1 #ifndef CRATERS_UTILS_H
2 #define CRATERS_UTILS_H
3 
4 #include <vcg/space/index/grid_static_ptr.h>
5 #include "fractal_utils.h"
6 
7 /* some utilities needed by the crater generation filter */
8 template<class MeshType>
9 class CratersUtils
10 {
11 public:
12     typedef typename MeshType::FacePointer          FacePointer;
13     typedef typename MeshType::FaceIterator         FaceIterator;
14     typedef typename MeshType::FaceType             FaceType;
15     typedef typename MeshType::VertexPointer        VertexPointer;
16     typedef typename MeshType::VertexIterator       VertexIterator;
17     typedef std::pair<VertexPointer, FacePointer>   SampleFace;
18     typedef std::vector<SampleFace>                 SampleFaceVector;
19     typedef typename MeshType::ScalarType           ScalarType;
20     typedef GridStaticPtr<FaceType, ScalarType>     MetroMeshGrid;
21     typedef tri::FaceTmark<MeshType>                MarkerFace;
22     typedef typename MeshType::template PerVertexAttributeHandle<ScalarType> PertHandle;
23 
24     /* wrapper for FP_CRATERS filter arguments */
25     class CratersArgs
26     {
27     public:
28         RadialFunctor<ScalarType>* radialFunctor;   // The radial functor that is defined according to
29                                                     // the chosen radial algorithm.
30         RadialFunctor<ScalarType>* blendingFunctor; // Blending functor defined accordingly to
31                                                     // the chosen blending algorithm.
32         NoiseFunctor<ScalarType>* noiseFunctor;     // Noise functor needed for postprocessing
33                                                     // noise application.
34         CraterFunctor<ScalarType>* craterFunctor;   // Functor constructed from the combination
35                                                     // of the above three functors.
36         MeshModel* target_model;
37         MeshModel* samples_model;
38         MeshType* target_mesh;
39         MeshType* samples_mesh;
40         int smoothingSteps;         // number of vertex normal smoothing steps (pre-processing)
41         ScalarType max_radius, max_depth, min_radius, min_depth, radius_range, depth_range;
42         bool save_as_quality, postprocessing_noise, successiveImpacts;
43 
CratersArgs(MeshModel * target,MeshModel * samples,int radial_alg,int seed,ScalarType min_r,ScalarType max_r,ScalarType min_d,ScalarType max_d,int smoothingSteps,bool save_as_quality,bool invert,bool ppNoise,bool successiveImpacts,ScalarType elevation,int blending_alg,ScalarType blendingThreshold)44         CratersArgs(MeshModel* target, MeshModel* samples, int radial_alg, int seed,
45                     ScalarType min_r, ScalarType max_r, ScalarType min_d, ScalarType max_d,
46                     int smoothingSteps, bool save_as_quality, bool invert, bool ppNoise, bool successiveImpacts,
47                     ScalarType elevation, int blending_alg, ScalarType blendingThreshold)
48         {
49             // Builds the random number generator used to generate radiuses and depths
50             // for craters.
51             generator = new vcg::math::SubtractiveRingRNG(seed);
52 
53             // builds the radial functor
54             switch(radial_alg)
55             {
56             case 0:
57                 radialFunctor = new GaussianBlending<ScalarType>();
58                 break;
59             case 1:
60                 radialFunctor = new MultiquadricBlending<ScalarType>();
61                 break;
62             case 2:
63                 radialFunctor = new F3Blending<ScalarType>();
64                 break;
65             }
66 
67             // builds the blending functor
68             switch(blending_alg)
69             {
70             case 0:
71                 blendingFunctor = new ExponentialBlending<ScalarType>();
72                 break;
73             case 1:
74                 blendingFunctor = new LinearBlending<ScalarType>();
75                 break;
76             case 2:
77                 blendingFunctor = new GaussianBlending<ScalarType>();
78                 break;
79             case 3:
80                 blendingFunctor = new F3Blending<ScalarType>();
81                 break;
82             }
83 
84             // if necessary, builds the noise functor
85             postprocessing_noise = ppNoise;
86             if (ppNoise)
87             {
88                 noiseFunctor = new FBMNoiseFunctor<ScalarType>(8, 0.7, 2);
89             }
90             craterFunctor = new CraterFunctor<ScalarType>(radialFunctor, blendingFunctor,
91                 noiseFunctor, blendingThreshold, elevation, ppNoise, invert);
92 
93             // fields assignments
94             target_model = target;
95             samples_model = samples;
96             target_mesh = &(target->cm);
97             samples_mesh = &(samples->cm);
98             this->save_as_quality = save_as_quality;
99             this->successiveImpacts = successiveImpacts;
100             this->smoothingSteps = smoothingSteps;
101             float target_bb_diag = target_mesh->bbox.Diag();
102             max_radius = target_bb_diag * 0.25 * max_r;     // calculates the maximum crater radius
103             min_radius = target_bb_diag * 0.25 * min_r;     // calculates the minimum crater radius
104             radius_range = max_radius - min_radius;         // calculates the radius range
105             max_depth = target_bb_diag * 0.25 * max_d;      // calculates the maximum crater depth
106             min_depth = target_bb_diag * 0.25 * min_d;      // calculates the minimum crater depth
107             depth_range = max_depth - min_depth;            // calculates the depth range
108 
109             // some cleanup operations on target mesh
110             vcg::tri::Clean<MeshType>::RemoveUnreferencedVertex(*target_mesh);
111             vcg::tri::Allocator<MeshType>::CompactVertexVector(*target_mesh);
112             vcg::tri::Allocator<MeshType>::CompactFaceVector(*target_mesh);
113         }
114 
115         // destructor
~CratersArgs()116         ~CratersArgs(){
117             delete radialFunctor;
118             delete blendingFunctor;
119             if(postprocessing_noise)
120                 delete noiseFunctor;
121 
122             delete craterFunctor;
123             delete generator;
124         }
125 
126         /* generates a crater radius within the specified range */
generateRadius()127         ScalarType generateRadius()
128         {
129             ScalarType rnd = generator->generate01closed();
130             return min_radius + radius_range * rnd;
131         }
132 
133         /* generates a crater depth within the specified range */
generateDepth()134         ScalarType generateDepth()
135         {
136             ScalarType rnd = generator->generate01closed();
137             return min_depth + depth_range * rnd;
138         }
139 
140     private:
141         vcg::math::RandomGenerator* generator;  // private random number generator
142     };
143 
144 
145     /* Finds the nearest faces of samples and stores the pairs (sample, nearest_face)
146        in the "sfv" vector (third parameter). */
FindSamplesFaces(MeshType * target,MeshType * samples,SampleFaceVector & sfv)147     static void FindSamplesFaces(MeshType *target, MeshType *samples, SampleFaceVector &sfv)
148     {
149         tri::UpdateNormal<MeshType>::PerFaceNormalized(*target);
150 //        tri::UpdateFlags<MeshType>::FaceProjection(*target);
151 
152         MetroMeshGrid mmg;
153         mmg.Set(target->face.begin(), target->face.end());
154         MarkerFace markerFunctor;
155         markerFunctor.SetMesh(target);
156         vcg::face::PointDistanceBaseFunctor<ScalarType> PDistFunct;
157         FacePointer nearestFace;
158         ScalarType dist_upper_bound = target->bbox.Diag()/10, dist;
159         Point3<ScalarType> closest;
160         sfv.clear();
161         SampleFace* tmpPair;
162         int i=0;
163 
164         for(VertexIterator vi=samples->vert.begin(); vi!=samples->vert.end(); ++vi, ++i)
165         {
166             nearestFace = mmg.GetClosest(PDistFunct, markerFunctor, (*vi).P(), dist_upper_bound, dist, closest);
167             tmpPair = new SampleFace(&(*vi), nearestFace);
168             sfv.push_back(*tmpPair);
169         }
170     }
171 
172     /* Detectes the faces of a crater starting from a given face, using FF adjacency. */
GetCraterFaces(MeshType * m,FacePointer startingFace,VertexPointer centre,ScalarType radius,std::vector<FacePointer> & toFill)173     static void GetCraterFaces(MeshType *m,              // target mesh
174                                FacePointer startingFace, // face under the crater centre
175                                VertexPointer centre,     // crater centre
176                                ScalarType radius,        // crater radius
177                                std::vector<FacePointer> &toFill) // the vector that has to be
178                                                          // filled with crater faces
179     {
180         assert(vcg::tri::HasFFAdjacency(*m));
181         vcg::tri::UpdateFlags<MeshType>::FaceClearV(*m);
182         vcg::tri::UpdateFlags<MeshType>::VertexClearV(*m);
183 
184         vcg::Sphere3<ScalarType> craterSphere(centre->P(), radius); // crater sphere
185         std::vector<FacePointer> fl;
186         fl.push_back(startingFace);
187 
188         toFill.clear();
189         FacePointer f;
190         Point3<ScalarType> dummyPoint;
191         std::pair<ScalarType, ScalarType> dummyPair;
192 
193         while(!fl.empty())
194         {
195             f = fl.back();
196             fl.pop_back();
197 
198             if((f != NULL) && (!f->IsV()))
199             {
200                 f->SetV();
201                 if(vcg::IntersectionSphereTriangle<ScalarType, FaceType>
202                    (craterSphere, *f, dummyPoint, &dummyPair))
203                 {   // intersection test succedeed
204                     toFill.push_back(f);
205                     for(int i=0; i<3; i++)
206                     {
207                         if(!f->FFp(i)->IsV())
208                         {
209                             fl.push_back(f->FFp(i));
210                         }
211                     }
212                 }
213             }
214         }
215     }
216 
217     /* Computes the radial perturbation given:
218        - args: a CratersArgs object that stores the needed perturbation parameters;
219        - centre: a pointer to the centre of the to-be-generated crater;
220        - craterFaces: a vector that contains the faces contained in the crater radius;
221        - radius: the radius of the to-be-generated crater;
222        - depth: the depth of the to-be-generated crater;
223        - pertHandle: an handle to a user-defined vertex attribute of type MeshType::ScalarType
224          (i.e. s floating point value). This attribute is filled with the computed perturbation.
225       */
ComputeRadialPerturbation(CratersArgs & args,VertexPointer centre,std::vector<FacePointer> & craterFaces,ScalarType radius,ScalarType depth,PertHandle & pertHandle)226     static void ComputeRadialPerturbation
227             (CratersArgs &args, VertexPointer centre,
228              std::vector<FacePointer> &craterFaces, ScalarType radius,
229              ScalarType depth, PertHandle& pertHandle)
230     {
231         vcg::tri::UpdateFlags<MeshType>::VertexClearV(*(args.target_mesh));
232 
233         typename std::vector<FacePointer>::iterator fi;
234         VertexPointer vp;
235         ScalarType perturbation = .0;
236         Point3<ScalarType> p;
237 
238         /* for each crater vertex, calculates the associated perturbation
239            and then stores it in the passed per-vertex-attribute handle */
240         for(fi = craterFaces.begin(); fi!=craterFaces.end(); ++fi)
241         {
242             for(int i=0; i<3; i++)
243             {
244                 vp = (*fi)->V(i);
245                 if(!vp->IsV())
246                 {
247                     vp->SetV();
248                     p = (vp->P() - centre->P())/radius;
249                     perturbation = (*(args.craterFunctor))(p) * depth;
250 
251                     // stores the perturbation in the passed handle, according to
252                     // the successiveImpacts flag
253                     if(args.successiveImpacts)
254                     {
255                         if(perturbation < 0)  // we are in the crater "depression"
256                         {
257                             pertHandle[vp] = std::min(perturbation, pertHandle[vp]);
258                         } else  // crater "elevation" and/or blending portion
259                         {
260                             if(pertHandle[vp] == .0)
261                             {
262                                 pertHandle[vp] += perturbation;
263                             }
264                         }
265                     } else {
266                         // by adding the perturbation to the one that is already present
267                         // we obtain a "crater intersection", so we cannot recognize
268                         // which crater is created before each other
269                         pertHandle[vp] += perturbation;
270                     }
271                 }
272             }
273         }
274     }
275 
276     /* craters generation algorithm */
GenerateCraters(CratersArgs & args,vcg::CallBackPos * cb)277     static bool GenerateCraters(CratersArgs &args, vcg::CallBackPos *cb)
278     {
279         // enables per-vertex-quality if needed
280         if(args.save_as_quality)
281             args.target_model->updateDataMask(MeshModel::MM_VERTQUALITY);
282 
283 //        tri::UpdateFlags<MeshType>::FaceProjection(args.target_model->cm);
284         // smoothes vertex normals
285         cb(0, "Smoothing vertex normals..");
286         tri::Smooth<MeshType>::VertexNormalLaplacian(*(args.target_mesh), args.smoothingSteps, false);
287 
288         // finds samples faces
289         args.target_model->updateDataMask(MeshModel::MM_FACEFACETOPO);
290         args.target_model->updateDataMask(MeshModel::MM_FACEMARK);
291         SampleFaceVector sfv;
292         CratersUtils<MeshType>::FindSamplesFaces(args.target_mesh, args.samples_mesh, sfv);
293 
294         // detectes crater faces and applies the radial perturbation
295         int cratersNo = int(args.samples_mesh->vert.size()), currentCrater = 0;
296         char buffer[50];
297         typename SampleFaceVector::iterator sfvi;
298         SampleFace p;
299         ScalarType radius = .0, depth = .0;
300         std::vector<FacePointer> craterFaces;
301 
302         // per-vertex float attribute
303         PertHandle h = tri::Allocator<MeshType>::template AddPerVertexAttribute<ScalarType>
304                             (*(args.target_mesh), std::string("perturbation"));
305         for(VertexIterator vi=args.target_mesh->vert.begin(); vi!=args.target_mesh->vert.end(); ++vi)
306         {
307             h[vi] = .0;
308         }
309 
310         // calculates the perturbation and stores it in the per-vertex-attribute
311         for(sfvi=sfv.begin(); sfvi!=sfv.end(); ++sfvi)
312         {
313             sprintf(buffer, "Generating crater %i...", currentCrater);
314             cb(100*(currentCrater++)/cratersNo, buffer);
315 
316             p = (*sfvi);
317             radius = args.generateRadius();
318             depth = args.generateDepth();
319             CratersUtils<MeshType>::GetCraterFaces(args.target_mesh, p.second, p.first, radius, craterFaces);
320             CratersUtils<MeshType>::ComputeRadialPerturbation(args, p.first, craterFaces, radius, depth, h);
321         }
322 
323         for(VertexIterator vi=args.target_mesh->vert.begin(); vi!=args.target_mesh->vert.end(); ++vi)
324         {
325             if(h[vi] == .0) continue;
326 
327             if(args.save_as_quality)
328             {
329                 (*vi).Q() = h[vi];
330             } else
331             {
332                 (*vi).P() += ((*vi).N() * h[vi]);
333             }
334         }
335 
336         // updates bounding box and normals
337         tri::Allocator<MeshType>::DeletePerVertexAttribute(*(args.target_mesh), std::string("perturbation"));
338         vcg::tri::UpdateBounding<MeshType>::Box(*(args.target_mesh));
339         vcg::tri::UpdateNormal<MeshType>::PerVertexNormalizedPerFaceNormalized(*(args.target_mesh));
340         return true;
341     }
342 };
343 
344 #endif // CRATERS_UTILS_H
345