1 #ifndef _PARAMETRIZATOR
2 #define _PARAMETRIZATOR
3 
4 #include <defines.h>
5 
6 
7 #include <param_collapse.h>
8 #include <param_flip.h>
9 
10 
11 #include <param_mesh.h>
12 #include <iso_parametrization.h>
13 
14 ///auxiliary structures
15 
16 #include <vcg/complex/algorithms/clean.h>
17 #include <vcg/complex/complex.h>
18 #include <vcg/complex/algorithms/update/topology.h>
19 #include <vcg/complex/algorithms/update/bounding.h>
20 
21 // update topology
22 #include <vcg/complex/algorithms/update/normal.h>
23 //#include <vcg/complex/algorithms/update/edges.h>
24 
25 
26 // local optimization
27 #include <vcg/complex/algorithms/local_optimization.h>
28 
29 
30 #include <local_parametrization.h>
31 #include <mesh_operators.h>
32 #include <vcg/space/color4.h>
33 #include <dual_coord_optimization.h>
34 #include <float.h>
35 #include <lm.h>
36 #ifndef _MESHLAB
37 #include <wrap/io_trimesh/export_ply.h>
38 #endif
39 //#include <EquilaterizeMesh.h>
40 
41 #include <opt_patch.h>
42 #include <local_optimization.h>
43 #include <statistics.h>
44 #include <stat_remeshing.h>
45 
46 //extern int step_global;
47 //
48 //int time_opt;
49 
50 ///Flip function
51 class MyTriEdgeFlip : public vcg::tri::ParamEdgeFlip<BaseMesh>{};
52 class MyTriEdgeCollapse: public vcg::tri::ParamEdgeCollapse<BaseMesh>{};
53 
54 ///THIS CLASS MAINTAINS STRUCTURES WHICH ARE USED FOR PARAMETRIZATION
55 ///TOGETHER WITH METHOD FOR COLORIZATION FOR VISUALIZATION PURPOSES
56 
57 class IsoParametrizator{
58 
59 public:
60      enum ReturnCode{MultiComponent,
61                                                     NonSizeCons,
62                                                     NonManifoldE,
63                                                     NonManifoldV,
64                                                     NonWatertigh,
65                                                     FailParam,Done};
66 
67 
68     BaseMesh final_mesh;
69     BaseMesh base_mesh;
70     typedef BaseMesh::ScalarType ScalarType;
71     typedef BaseMesh::CoordType CoordType;
72     vcg::CallBackPos *cb;
73     EnergyType EType;
74 private:
75 
InitVoronoiArea()76     void InitVoronoiArea()
77     {
78         ///area deviation respect to original
79         for (unsigned int i=0;i<base_mesh.face.size();i++)
80             base_mesh.face[i].areadelta=0;
81 
82         for (unsigned int i=0;i<final_mesh.vert.size();i++)
83             final_mesh.vert[i].area=0;
84 
85         for (unsigned int i=0;i<final_mesh.face.size();i++)
86         {
87             BaseFace *f=&final_mesh.face[i];
88             ScalarType areaf= (ScalarType)DoubleArea(*f)/2.0;//(((f->V(1)->P()-f->V(0)->P())^(f->V(2)->P()-f->V(0)->P())).Norm())/2.0;
89             f->V(0)->area+=areaf/(ScalarType)3.0;
90             f->V(1)->area+=areaf/(ScalarType)3.0;
91             f->V(2)->area+=areaf/(ScalarType)3.0;
92         }
93     }
94 
95     template <class MeshType>
InitializeStructures(MeshType * mesh)96     void InitializeStructures(MeshType *mesh)
97     {
98         ///cleaning of initial mesh
99         /*int dup = */vcg::tri::Clean<MeshType>::RemoveDuplicateVertex(*mesh);
100         /*int unref =  */vcg::tri::Clean<MeshType>::RemoveUnreferencedVertex(*mesh);
101 
102         vcg::tri::Allocator<MeshType>::CompactFaceVector(*mesh);
103         vcg::tri::Allocator<MeshType>::CompactVertexVector(*mesh);
104 
105         ///copy
106         base_mesh.Clear();
107         final_mesh.Clear();
108         vcg::tri::Append<BaseMesh,MeshType>::Mesh(base_mesh,*mesh);
109         vcg::tri::Append<BaseMesh,MeshType>::Mesh(final_mesh,*mesh);
110 
111         ///update auxiliary structures
112         UpdateStructures(&base_mesh);
113         UpdateStructures(&final_mesh);
114         vcg::tri::UpdateTopology<BaseMesh>::TestFaceFace(base_mesh);
115         vcg::tri::UpdateTopology<BaseMesh>::TestFaceFace(final_mesh);
116 
117         ///initialization of statistics
118         //stat.Init(&base_mesh,&final_mesh);
119 
120         ///copy original color
121         for (unsigned int i=0;i<final_mesh.vert.size();i++)
122             final_mesh.vert[i].OriginalCol=final_mesh.vert[i].C();
123 
124         ///set brother vertices and default father
125         /*unsigned int i=0;*/
126         for (unsigned int i=0;i<base_mesh.vert.size();i++)
127         {
128             base_mesh.vert[i].brother=&final_mesh.vert[i];
129             base_mesh.vert[i].RPos=base_mesh.vert[i].P();
130         }
131 
132         /*///area deviation respect to original
133         for (unsigned int i=0;i<base_mesh.face.size();i++)
134             base_mesh.face[i].areadelta=0;
135 
136         for (unsigned int i=0;i<final_mesh.vert.size();i++)
137             final_mesh.vert[i].area=0;*/
138 
139         for (unsigned int i=0;i<base_mesh.vert.size();i++){
140             base_mesh.vert[i].brother=&final_mesh.vert[i];
141             //final_mesh.vert[i].father=base_mesh.vert[i].VFp();
142             //assert(!base_mesh.vert[i].VFp()->IsD());
143             CoordType bary=CoordType(0,0,0);
144             bary.V(base_mesh.vert[i].VFi())=1;
145             //final_mesh.vert[i].Bary=bary;
146             AssingFather(final_mesh.vert[i],base_mesh.vert[i].VFp(),bary,base_mesh);
147         }
148 
149         ///initialize area per vertex
150 
151         for (unsigned int i=0;i<final_mesh.vert.size();i++){
152             BaseFace* father=final_mesh.vert[i].father;
153             CoordType bary=final_mesh.vert[i].Bary;
154             father->vertices_bary.push_back(std::pair<BaseVertex*,vcg::Point3f>(&final_mesh.vert[i],bary));
155         }
156 
157         ///testing everything is ok
158         for (unsigned int i=0;i<final_mesh.vert.size();i++)
159         {
160             final_mesh.vert[i].RPos=final_mesh.vert[i].P();
161             CoordType test=ProjectPos(final_mesh.vert[i]);
162             assert((test-final_mesh.vert[i].P()).Norm()<0.000001);
163         }
164 
165         ////initialization for decimation
166         //base_mesh.en=0;
167         InitIMark();
168     vcg::tri::UpdateFlags<BaseMesh>::VertexClear(base_mesh);
169     vcg::tri::UpdateFlags<BaseMesh>::FaceClear(base_mesh);
170     InitVoronoiArea();
171     }
172 
InitIMark()173     void InitIMark()
174     {
175     vcg::tri::IMark(base_mesh)=0;
176     vcg::tri::InitFaceIMark(base_mesh);
177     vcg::tri::InitVertexIMark(base_mesh);
178     }
179 
180 
181   void ParaDecimate(vcg::tri::ParamEdgeCollapseParameter &pecp,
182                     const int &targetFaces,
183                     const int &interval,
184                     bool execute_flip=false)
185     {
186     vcg::LocalOptimization<BaseMesh> DeciSession(base_mesh,&pecp);
187         DeciSession.Init<MyTriEdgeCollapse >();
188 
189         PatchesOptimizer<BaseMesh>::HresMesh()=&final_mesh;
190         PatchesOptimizer<BaseMesh>::BaseMesh()=&base_mesh;
191 
192         MyTriEdgeFlip::Accuracy()=accuracy;
193 
194         int flip_todo=4;
195         int next_flip_num=targetFaces;
196         std::vector<int> stop_points;
197 
198         if (execute_flip)
199         {
200             stop_points.resize(flip_todo+2);///number of flips + save stack point + final stop
201 
202             for (int i=0;i<flip_todo;i++)
203             {
204                 next_flip_num=(int)((ScalarType)next_flip_num*flip_factor);
205                 stop_points[i]=next_flip_num;
206             }
207             stop_points[flip_todo]=targetFaces+interval;
208             stop_points[flip_todo+1]=targetFaces;
209             std::sort(stop_points.begin(),stop_points.end());
210         }
211         else
212         {
213             stop_points.resize(2);
214             stop_points[0]=targetFaces;
215             stop_points[1]=targetFaces+interval;
216         }
217 
218         ///find the point where save stack is defined
219         int pos_stack=-1;
220         for (unsigned int i=0;i<stop_points.size();i++)
221         {
222             if (stop_points[i]==(targetFaces+interval))
223                 pos_stack=i;
224         }
225 
226 
227         assert(pos_stack!=-1);
228 
229         bool do_flip=false;
230         bool save_status=false;
231         int curr_limit=stop_points.size()-1;
232         bool not_heap_empty=true;
233         //bool check_status=false;
234         while ((base_mesh.fn>targetFaces)&&(not_heap_empty))
235         {
236             do_flip=false;
237 
238             int curr_num=base_mesh.fn;
239 
240             int next_num;
241             if (!save_status)
242                 next_num=curr_num-1000;
243             else
244                 next_num=curr_num-2;
245 
246             if ((curr_limit>=0)&&(next_num<stop_points[curr_limit]))
247             {
248                 next_num=stop_points[curr_limit];
249 
250                 if (curr_limit==pos_stack)
251                     save_status=true;
252                 else
253                 if ((curr_limit!=0)&&(execute_flip))
254                     do_flip=true;
255 
256                 curr_limit--;
257             }
258 
259 
260 
261             DeciSession.SetTargetSimplices(next_num);
262             not_heap_empty=DeciSession.DoOptimization();
263 
264 
265 
266             if (do_flip)
267             {
268         FlipStep(pecp);
269                 vcg::tri::UpdateTopology<BaseMesh>::FaceFace(base_mesh);
270                 vcg::tri::UpdateTopology<BaseMesh>::VertexFace(base_mesh);
271                 InitIMark();
272                 DeciSession.h.clear();
273                 DeciSession.Init<MyTriEdgeCollapse >();
274                 if (flip_todo>0)
275                 {
276                     next_flip_num=(int)(((ScalarType)next_flip_num)/flip_factor);
277                     flip_todo--;
278                 }
279             }
280             /*#ifndef _MESHLAB
281 
282             #endif*/
283             PrintAttributes();
284             if (save_status)
285             {
286                 #ifndef _MESHLAB
287                 printf("SAVING CURRENT STATUS....face_num: %d\n",curr_num);
288                 #endif
289                 SaveCurrentStatus();
290                 InitIMark();
291                 DeciSession.h.clear();
292                 DeciSession.Init<MyTriEdgeCollapse >();
293             }
294 
295             testParametrization<BaseMesh>(base_mesh,final_mesh);
296 
297         }
298 
299 
300     }
301 
302     ///ASSOCIATE SURVIVED VERTEX FROM DECIMATION
AssociateRemaining()303     void AssociateRemaining()
304     {
305         printf("\n ASSOCIATE REMAINING \n");
306         for (unsigned int i=0;i<base_mesh.vert.size();i++)
307             if (base_mesh.vert[i].brother!=NULL)
308             {
309                 BaseVertex* v=&base_mesh.vert[i];
310                 BaseVertex* vb=v->brother;
311                 vcg::face::VFIterator<BaseFace> vfi2(v);
312                 ///take the face that has lower number of vertices
313                 BaseFace *fmin=vfi2.F();
314                 int index=vfi2.I();
315         size_t sizeMin=fmin->vertices_bary.size();
316                 while (!vfi2.End())
317                 {
318                     BaseFace *f=vfi2.F();
319                     if (f->vertices_bary.size()<sizeMin)
320                     {
321                         sizeMin=f->vertices_bary.size();
322                         fmin=f;
323                         index=vfi2.I();
324                     }
325           ++vfi2;
326                 }
327                 CoordType bary=CoordType(0,0,0);
328                 bary[index]=1.f;
329                 fmin->vertices_bary.push_back(std::pair<BaseVertex*,vcg::Point3f>(vb,bary));
330                 AssingFather(*vb,fmin,bary,base_mesh);
331                 /*vb->father=f;
332                 assert(!f->IsD());
333                 vb->Bary=bary;*/
334                 v->brother=NULL;
335             }
336     }
337 
338     struct vert_para
339         {
340             ScalarType dist;
341             BaseVertex *v;
342       bool operator <(const vert_para &other) const
343             {return (dist>other.dist);}
344         };
345 
FinalOptimization(vcg::tri::ParamEdgeCollapseParameter * pecp)346   void FinalOptimization(vcg::tri::ParamEdgeCollapseParameter *pecp)
347     {
348         char ret[200];
349         sprintf(ret," PERFORM GLOBAL OPTIMIZATION initializing... ");
350         (*cb)(0,ret);
351 
352         std::vector<vert_para> ord_vertex;
353         ord_vertex.resize(base_mesh.vn);
354         for (unsigned int i=0;i<base_mesh.vert.size();i++)
355             if (!base_mesh.vert[i].IsD())
356             {
357                 BaseVertex *v=&base_mesh.vert[i];
358                 ScalarType val=StarDistorsion<BaseMesh>(&base_mesh.vert[i]);
359                 //printf("i: %d\n",i);
360                 ord_vertex[i].dist=val;
361                 ord_vertex[i].v=v;
362             }
363 
364         std::sort(ord_vertex.begin(),ord_vertex.end());
365         for (unsigned int i=0;i<ord_vertex.size();i++)
366         {
367                 printf("%3.3f\n",ord_vertex[i].dist);
368         SmartOptimizeStar<BaseMesh>(ord_vertex[i].v,base_mesh,pecp->Accuracy(),EType);
369         }
370     }
371 
372 
373     template <class MeshType>
374     ReturnCode InitBaseMesh(MeshType *mesh,
375         const int &targetFaces,
376         const int &interval,
377         bool execute_flip=true,
378         bool test_interpolation=true)
379     {
380     vcg::tri::UpdateFlags<MeshType>::VertexClearV(*mesh);
381     vcg::tri::UpdateFlags<MeshType>::FaceClearV(*mesh);
382 
383     ///TEST PRECONDITIONS
384     ReturnCode ret=Preconditions(*mesh);
385 
386     if (ret!=Done) return ret;
387 
388         ///INITIALIZATION
389         InitializeStructures<MeshType>(mesh);
390 
391     vcg::tri::ParamEdgeCollapseParameter pecp;
392     pecp.Accuracy()=accuracy;
393     pecp.HresMesh()=&final_mesh;
394 
395     ///DECIMATION & PARAMETRIZATION
396     ParaDecimate(pecp, targetFaces,interval,execute_flip);
397 
398         ///SET BEST FIND STOP POINT
399         bool isOK=SetBestStatus(test_interpolation);
400         if ((!isOK)&&(test_interpolation))
401             return FailParam;
402 
403         ///THEN CLEAR STACK
404         ClearStack();
405 
406         ///LAST FLIP STEP
407         if (execute_flip)
408       FlipStep(pecp);
409 
410         vcg::tri::UpdateTopology<BaseMesh>::FaceFace(base_mesh);
411         vcg::tri::UpdateTopology<BaseMesh>::VertexFace(base_mesh);
412         vcg::tri::UpdateTopology<BaseMesh>::TestVertexFace(base_mesh); ///TEST
413 
414         UpdateStructures(&base_mesh);
415         #ifndef _MESHLAB
416         if (execute_flip)
417         {
418             printf("\n POST LAST FLIP: \n");
419             PrintAttributes();
420         }
421         #endif
422 
423         ///ASSOCIATE REMAINING VERTICES TO ONE FACE
424         AssociateRemaining();
425 
426         ///LAST OPTIMIZATION STEP ON STARS
427         if (execute_flip)
428       FinalOptimization(&pecp);
429 
430         #ifndef _MESHLAB
431         if (execute_flip)
432         {
433             printf("\n POST STAR OPT: \n");
434             PrintAttributes();
435         }
436         #endif
437         return Done;
438     }
439 
CompactBaseDomain()440     void CompactBaseDomain()
441     {
442         /*testParametrization<BaseMesh>(base_mesh,final_mesh);
443         system("pause");*/
444         vcg::tri::Allocator<BaseMesh>::CompactVertexVector(base_mesh);
445         vcg::tri::Allocator<BaseMesh>::CompactFaceVector(base_mesh);
446         UpdateStructures(&base_mesh);
447         ///reassing
448         //for (int i=0;i<(int)base_mesh.face.size();i++)
449         for (int i=0;i<(int)base_mesh.face.size();i++)
450         {
451             int size=base_mesh.face[i].vertices_bary.size();
452             /*assert(size>0);*/
453             for (int j=0;j<size;j++)
454             {
455                 BaseVertex* son=base_mesh.face[i].vertices_bary[j].first;
456                 CoordType bary=base_mesh.face[i].vertices_bary[j].second;
457                 /*son->father=&base_mesh.face[i];
458                 assert(!base_mesh.face[i].IsD());
459                 son->Bary=bary;*/
460                 AssingFather(*son,&base_mesh.face[i],bary,base_mesh);
461             }
462         }
463         /*testParametrization<BaseMesh>(base_mesh,final_mesh);
464         system("pause");*/
465     }
466 
467     ///save the current status of the parameterization
SaveCurrentStatus()468     void SaveCurrentStatus()
469     {
470         ///copy
471         ParaStack.push_back(ParaInfo());
472         ParaStack.back().AbsMesh=new BaseMesh();
473         BaseMesh *mesh=ParaStack.back().AbsMesh;
474         CompactBaseDomain();
475 
476         vcg::tri::Append<BaseMesh,BaseMesh>::Mesh(*mesh,base_mesh);
477 
478 
479         for (unsigned int i=0;i<base_mesh.vert.size();i++)
480                 mesh->vert[i].RPos=base_mesh.vert[i].RPos;
481 
482         ///copy linking for parameterization information
483         int k=0;
484         for (unsigned int i=0;i<base_mesh.face.size();i++)
485         {
486             if (!base_mesh.face[i].IsD())
487             {
488                 int size=base_mesh.face[i].vertices_bary.size();
489                 mesh->face[k].vertices_bary.resize(size);
490                 for (int j=0;j<size;j++)
491                 {
492                     mesh->face[k].vertices_bary[j].first=base_mesh.face[i].vertices_bary[j].first;
493                     mesh->face[k].vertices_bary[j].second=base_mesh.face[i].vertices_bary[j].second;
494                 }
495                 k++;
496             }
497         }
498         //ParaStack.push_back(ParaInfo());
499         /*ParaStack.back().AbsMesh=mesh;*/
500         ScalarType valL2=ApproxL2Error(final_mesh);
501         ParaStack.back().L2=valL2;
502         ScalarType val0=ApproxAreaDistortion<BaseMesh>(final_mesh,mesh->fn);
503         ParaStack.back().AreaDist=val0;
504         ScalarType val1=ApproxAngleDistortion<BaseMesh>(final_mesh);
505         ParaStack.back().AngleDist=val1;
506         ParaStack.back().AggrDist=geomAverage<ScalarType>(val0+(ScalarType)1.0,val1+(ScalarType)1.0,3,1)-(ScalarType)1;
507         ParaStack.back().Regular=NumRegular<BaseMesh>(*mesh);
508         //ParaStack.back().distorsion=geomAverage<double>(val0,val1,3,1);
509         ScalarType val2=ParaStack.back().AggrDist;
510         ParaStack.back().num_faces=mesh->fn;
511         ParaStack.back().ratio=val2*sqrt((ScalarType)mesh->fn);
512     }
513 
RestoreStatus(const int & index_status)514     void RestoreStatus(const int &index_status)
515     {
516         ///delete current base mesh
517         base_mesh.Clear();
518         BaseMesh *to_restore=ParaStack[index_status].AbsMesh;
519 
520         ///restore saved abstract mesh and link
521         vcg::tri::Append<BaseMesh,BaseMesh>::Mesh(base_mesh,*to_restore);
522         for (unsigned int i=0;i<to_restore->face.size();i++)
523         {
524             int size=to_restore->face[i].vertices_bary.size();
525             base_mesh.face[i].vertices_bary.resize(size);
526             for (int j=0;j<size;j++)
527             {
528                 BaseVertex * vert=to_restore->face[i].vertices_bary[j].first;
529                 CoordType bary=to_restore->face[i].vertices_bary[j].second;
530 #ifdef _DEBUG
531                 bool done=NormalizeBaryCoords(bary);
532                 assert(done);
533 #else
534                 NormalizeBaryCoords(bary);
535 #endif
536                 base_mesh.face[i].vertices_bary[j].first=vert;
537                 base_mesh.face[i].vertices_bary[j].second=bary;
538 
539                 AssingFather(*vert,&base_mesh.face[i],bary,base_mesh);
540 
541                 //vert->father=&base_mesh.face[i];
542                 //assert(!base_mesh.face[i].IsD());
543                 //vert->Bary=bary;
544             }
545         }
546         UpdateTopologies<BaseMesh>(&base_mesh);
547 
548         ///copy rest pos
549         for (unsigned int i=0;i<to_restore->vert.size();i++)
550         {
551             base_mesh.vert[i].RPos=to_restore->vert[i].RPos;
552             base_mesh.vert[i].P()=to_restore->vert[i].P();
553         }
554         /*///clear stack of meshes
555         ClearStack();*/
556     }
557 
558     ///clear the durrent stack
ClearStack()559     void ClearStack()
560     {
561         for (unsigned int i=0;i<ParaStack.size();i++)
562             delete(ParaStack[i].AbsMesh);
563         ParaStack.clear();
564     }
565 
GetStatusVal(const int & index)566     ScalarType GetStatusVal(const int &index)
567     {
568         switch (SMode)
569         {
570         case (SM_Area): return ParaStack[index].AreaDist;
571             break;
572         case (SM_Angle):return ParaStack[index].AngleDist;
573             break;
574         case (SM_Corr):return ParaStack[index].AggrDist;
575             break;
576         case (SM_Reg):return (ScalarType)ParaStack[index].Regular;
577             break;
578         case (SM_Smallest):return (ScalarType)ParaStack[index].num_faces;
579             break;
580         case (SM_L2):return ParaStack[index].L2;
581             break;
582         default:return ParaStack[index].ratio;
583             break;
584         }
585     }
586 
587     ///return true if possible to construct an Isoparametrization
TestInterpolation()588     bool TestInterpolation()
589     {
590             ParamMesh para_mesh1;
591             AbstractMesh abs_mesh1;
592             ExportMeshes(para_mesh1,abs_mesh1);
593 
594             ///constrauct an ISOPARAM
595             IsoParametrization IsoParam1;
596             return(IsoParam1.Init(&abs_mesh1,&para_mesh1));
597     }
598 
599     ///set the best value considering the ratio value
SetBestStatus(bool test_interpolation)600     bool SetBestStatus(bool test_interpolation)
601     {
602         std::sort(ParaStack.begin(),ParaStack.end());
603         int indexmin=0;
604         bool isOK_interp;
605 
606         if (test_interpolation)
607             isOK_interp=false;
608         else
609             isOK_interp=true;
610 
611         RestoreStatus(indexmin);
612         if (test_interpolation)
613         {
614             while ((!isOK_interp)&&(indexmin<(int)ParaStack.size()))
615             {
616                 isOK_interp=TestInterpolation();
617                 if (!isOK_interp)
618                 {
619                     indexmin++;
620                     if (indexmin<(int)ParaStack.size())
621                         RestoreStatus(indexmin);
622                 }
623             }
624         }
625 
626         ///clear stack of meshes
627 
628 
629 
630 #ifndef _MESHLAB
631         for (unsigned int i=0;i<ParaStack.size();i++)
632         {
633 
634             printf("faces %d, Area %.4f, Angle %.4f, Corr %.4f, non Reg %d,L2 %.4f,Heuristic %.4f\n",
635                 ParaStack[i].num_faces,
636                 ParaStack[i].AreaDist,
637                 ParaStack[i].AngleDist,
638                 ParaStack[i].AggrDist,
639                 ParaStack[i].Regular,
640                 ParaStack[i].L2,
641                 ParaStack[i].ratio);
642         }
643         if ((isOK_interp)||(!test_interpolation))
644             printf("Chosen to stop at %d faces \n",ParaStack[indexmin].num_faces);
645         else
646             printf("Not a right Interpolation Domain is found");
647 #endif
648 
649         ClearStack();
650         isOK_interp=TestInterpolation();
651         return (isOK_interp);
652     }
653 
654 public:
655 
656     enum StopMode{
657         SM_Euristic,
658         SM_Area,
659         SM_Angle,
660         SM_Corr,
661         SM_Reg,
662         SM_Smallest,
663         SM_L2
664     };
665 
666     ///parameters
667     StopMode SMode;
668     int lower_limit;
669     int interval;
670     int accuracy;
671     //edn parameters
672 
673     MyTriEdgeCollapse *next_oper;
674     MyTriEdgeFlip *next_flip;
675     BaryOptimizatorDual<BaseMesh> *BaryOptDemo;
676     vcg::LocalOptimization<BaseMesh> *FlipSession;
677 
678     int TimeStepDeci,TimeStepFlip;
679 
680     struct ParaInfo
681     {
682         ScalarType AggrDist;
683         ScalarType AreaDist;
684         ScalarType AngleDist;
685         int Regular;
686         int num_faces;
687         ScalarType ratio;
688         ScalarType L2;
689         BaseMesh * AbsMesh;
690 
SMParaInfo691         static StopMode& SM()
692         {
693             static StopMode S;
694             return S;
695         }
696 
697     inline bool operator < (const ParaInfo &P_info) const{
698             switch (SM())
699             {
700             case (SM_Area): return AreaDist<P_info.AreaDist;
701                 break;
702             case (SM_Angle):return AngleDist<P_info.AngleDist;
703                 break;
704             case (SM_Corr):return AggrDist<P_info.AggrDist;
705                 break;
706             case (SM_Reg):return Regular<P_info.Regular;
707                 break;
708             case (SM_Smallest):return num_faces<P_info.num_faces;
709                 break;
710             case (SM_L2):return L2<P_info.L2;
711                 break;
712             default:return ratio<P_info.ratio;
713                 break;
714             }
715         }
716 
717     };
718 
719     std::vector<ParaInfo> ParaStack;
720 
721     ///PRECONDITIONS
722     template <class MeshType>
Preconditions(MeshType & mesh)723     ReturnCode Preconditions(MeshType &mesh)
724     {
725         bool b;
726         vcg::tri::UpdateTopology<MeshType>::FaceFace(mesh);
727     if(vcg::tri::Clean<MeshType>::CountNonManifoldEdgeFF(mesh)>0 ) return NonManifoldE;
728     if(vcg::tri::Clean<MeshType>::CountNonManifoldVertexFF(mesh)>0 ) return NonManifoldV;
729 
730         b=vcg::tri::Clean<MeshType>::IsSizeConsistent(mesh);
731         if (!b)	return NonSizeCons;
732 
733     int cc=vcg::tri::Clean<MeshType>::CountConnectedComponents(mesh);
734     if(cc>1) return MultiComponent;
735 
736     int boundaryEdgeNum, internalEdgeNum,nonManif;
737     vcg::tri::Clean<MeshType>::CountEdgeNum(mesh,internalEdgeNum,boundaryEdgeNum,nonManif);
738     if(boundaryEdgeNum>0) return NonWatertigh;
739 
740         return Done;
741     }
742 
743     ///perform a global optimization step
GlobalOptimizeStep()744     void GlobalOptimizeStep()
745     {
746 #ifndef _MESHLAB
747       printf("\n GLOBAL OPTIMIZATION \n");
748 #endif
749       BaryOptimizatorDual<BaseMesh> BaryOpt;
750       BaryOpt.Init(base_mesh,final_mesh,cb,accuracy,EType);
751       BaryOpt.Optimize(4.0f/(float)accuracy,accuracy*4);
752 #ifndef _MESHLAB
753       printf("\n POST DUAL OPT:	\n");
754       PrintAttributes();
755 #endif
756     }
757 
758     template <class MeshType>
ScaleMesh(MeshType & m,const ScalarType & factor)759     void ScaleMesh(MeshType &m,
760                                  const ScalarType &factor)
761     {
762     for (size_t i=0;i<m.vert.size();i++)
763             if (!m.vert[i].IsD())
764                 m.vert[i].P()*=factor;
765     }
766 
767     template <class MeshType>
TranslateMesh(MeshType & m,const typename MeshType::CoordType & vect)768     void TranslateMesh(MeshType &m,const typename MeshType::CoordType &vect)
769     {
770     for (size_t i=0;i<m.vert.size();i++)
771             if (!m.vert[i].IsD())
772                 m.vert[i].P()+=vect;
773     }
774 
775     ///PARAMETRIZATION FUNCTIONS
776     ///initialize the mesh
777     template <class MeshType>
778   ReturnCode Parametrize(MeshType *mesh,vcg::tri::ParamEdgeCollapseParameter &pecp,bool Two_steps=true,EnergyType _EType=EN_EXTMips)
779     {
780         EType=_EType;
781 //		MyTriEdgeCollapse::EType()=EType;
782 //		MyTriEdgeFlip::EType()=EType;
783     pecp.EType()=_EType;
784         ///clean unreferenced vertices
785         vcg::tri::Clean<MeshType>::RemoveUnreferencedVertex(*mesh);
786         /*bool done;*/
787         const int limit0=15000;//00;
788         const int limit1=30000;
789 
790         vcg::tri::UpdateBounding<MeshType>::Box(*mesh);
791         ScalarType factor=100.0/mesh->bbox.Diag();
792         typename MeshType::CoordType transl=-mesh->bbox.Center();
793         TranslateMesh(*mesh,transl);
794         ScaleMesh(*mesh,factor);
795         if ((!Two_steps)||(lower_limit>limit0)||(mesh->fn<limit1))
796         {
797             ReturnCode res=InitBaseMesh<MeshType>(mesh,lower_limit,interval,true,true);
798             ScaleMesh(*mesh,1.0/factor);
799             TranslateMesh(*mesh,-transl);
800             if (res!=Done)
801                 return res;
802         }
803         else
804         {
805             ///do a first parametrization step
806             printf("\n STEP 1 \n");
807             InitVoronoiArea();
808             ReturnCode res=InitBaseMesh<MeshType>(mesh,limit0,1,false,false);
809             ScaleMesh(*mesh,1.0/factor);
810             TranslateMesh(*mesh,-transl);
811             if (res!=Done)
812                 return res;
813 
814             ParamMesh para_mesh0;
815             AbstractMesh abs_mesh0;
816             //AbstractMesh abs_mesh_test;
817             ExportMeshes(para_mesh0,abs_mesh0);
818 
819             printf("\n STEP 2 \n");
820             res=InitBaseMesh<AbstractMesh>(&abs_mesh0,lower_limit,interval,true,true);
821             if (res!=Done)
822                 return res;
823 
824 
825             ParamMesh para_mesh1;
826             AbstractMesh abs_mesh1;
827             ExportMeshes(para_mesh1,abs_mesh1);
828 
829 
830             ///constrauct an ISOPARAM
831             printf("\n STEP 2.5 \n");
832             IsoParametrization IsoParam1;
833             bool done=IsoParam1.Init(&abs_mesh1,&para_mesh1,true);
834 
835             if (!done)
836                 return FailParam;
837 
838             printf("\n merging 0 \n");
839             ///copy initial mesh
840             final_mesh.Clear();
841             base_mesh.Clear();
842             vcg::tri::Append<BaseMesh,ParamMesh>::Mesh(final_mesh,para_mesh0);
843             vcg::tri::Append<BaseMesh,AbstractMesh>::Mesh(base_mesh,abs_mesh1);
844             ///scale by a factor
845 
846             UpdateTopologies<BaseMesh>(&final_mesh);
847             UpdateTopologies<BaseMesh>(&base_mesh);
848 
849             for (int i=0;i<(int)base_mesh.vert.size();i++)
850                 base_mesh.vert[i].RPos=abs_mesh1.vert[i].P();
851             for (int i=0;i<(int)final_mesh.vert.size();i++)
852                 final_mesh.vert[i].RPos=para_mesh0.vert[i].P();
853 
854             ///finally merge in between
855             for (int i=0;i<(int)para_mesh0.vert.size();i++)
856             {
857                 ///get the index of the first parametrization process
858                 int Index0=para_mesh0.vert[i].T().N();
859                 ///find the parametrization coordinates
860                 vcg::Point2<ScalarType> p2bary=para_mesh0.vert[i].T().P();
861                 CoordType bary0=CoordType (p2bary.X(),p2bary.Y(),1-p2bary.X()-p2bary.Y());
862                 bool isOK=NormalizeBaryCoords(bary0);
863                 assert(isOK);
864         assert(size_t(Index0)<para_mesh1.face.size());
865 
866                 ///get the correspondent face
867                 ParamFace *f1=&para_mesh1.face[Index0];
868                 int I_final=-1;
869                 vcg::Point2<ScalarType> UV_final;
870                 IsoParam1.Phi(f1,bary0,I_final,UV_final);
871         assert(size_t(I_final)<abs_mesh1.face.size());
872 
873                 CoordType bary2=CoordType(UV_final.X(),UV_final.Y(),1-UV_final.X()-UV_final.Y());
874                 isOK=NormalizeBaryCoords(bary2);
875                 assert(isOK);
876                 //final_mesh.vert[i].father=&base_mesh.face[I_final];
877                 //assert(!base_mesh.face[I_final].IsD());
878                 //final_mesh.vert[i].Bary=bary2;
879                 AssingFather(final_mesh.vert[i],&base_mesh.face[I_final],bary2,base_mesh);
880             }
881 
882             ///set father to son link
883             for (int i=0;i<(int)final_mesh.vert.size();i++)
884             {
885                 BaseFace* base_f=final_mesh.vert[i].father;
886                 CoordType bary=final_mesh.vert[i].Bary;
887                 assert((bary.X()>=0)&&(bary.Y()>=0));
888                 assert((bary.X()<=1)&&(bary.Y()<=1));
889                 assert(bary.X()+bary.Y()<=1.0001);
890                 base_f->vertices_bary.push_back(std::pair<BaseVertex *,CoordType>(&final_mesh.vert[i],bary));
891             }
892          InitVoronoiArea();
893      FinalOptimization(&pecp);
894          printf("STEP 3 \n");
895         }
896         ///finally perform the final optimization step
897         InitVoronoiArea();
898         //FinalOptimization();
899         GlobalOptimizeStep();
900 
901         CoordType ntransl = CoordType::Construct(-transl);
902 
903         ScaleMesh(final_mesh,1.0/factor);
904         TranslateMesh(final_mesh,ntransl);
905         ScaleMesh(base_mesh,1.0/factor);
906         TranslateMesh(base_mesh,ntransl);
907         return Done;
908     }
909 
910     ///perform one or more flip steps
FlipStep(vcg::tri::ParamEdgeCollapseParameter & pecp)911   void FlipStep(vcg::tri::ParamEdgeCollapseParameter &pecp)
912     {
913 #ifndef _MESHLAB
914         printf("\n STARTING FLIP SESSION \n");
915 #endif
916         InitIMark();
917     FlipSession=new vcg::LocalOptimization<BaseMesh>(base_mesh,&pecp);
918         FlipSession->Init<MyTriEdgeFlip>();
919         /*bool b=*/FlipSession->DoOptimization();
920 #ifndef _MESHLAB
921         printf("\n END FLIP SESSION %d edges \n",FlipSession->nPerfmormedOps);
922 #endif
923         UpdateTopologies(&base_mesh);
924     }
925 
926     ///equilateralize patch length and areas
EquiPatches()927     void EquiPatches()
928     {
929         PatchesOptimizer<BaseMesh> DomOpt(base_mesh,final_mesh);
930         DomOpt.OptimizePatches();
931         PrintAttributes();
932     }
933 
934     /// I/O FUNCTIONS
SaveMCP(char * filename)935     void SaveMCP(char* filename)
936     {
937         /*Warp(0);*/
938         FILE *f;
939         f=fopen(filename,"w+");
940         std::map<BaseFace*,int> facemap;
941         std::map<BaseVertex*,int> vertexmap;
942         typedef std::map<BaseVertex*,int>::iterator iteMapVert;
943         typedef std::map<BaseFace*,int>::iterator iteMapFace;
944 
945         ///add vertices
946         fprintf(f,"%d,%d \n",base_mesh.fn,base_mesh.vn);
947         int index=0;
948         for (unsigned int i=0;i<base_mesh.vert.size();i++)
949         {
950             BaseVertex* vert=&base_mesh.vert[i];
951             if (!vert->IsD())
952             {
953                 vertexmap.insert(std::pair<BaseVertex*,int>(vert,index));
954                 CoordType pos=vert->P();
955                 CoordType RPos=vert->RPos;
956                 fprintf(f,"%f,%f,%f;%f,%f,%f \n",pos.X(),pos.Y(),pos.Z(),RPos.X(),RPos.Y(),RPos.Z());
957                 index++;
958             }
959         }
960 
961         ///add faces
962         index=0;
963         for (unsigned int i=0;i<base_mesh.face.size();i++)
964         {
965             BaseFace* face=&base_mesh.face[i];
966             if (!face->IsD())
967             {
968                 BaseVertex* v0=face->V(0);
969                 BaseVertex* v1=face->V(1);
970                 BaseVertex* v2=face->V(2);
971                 iteMapVert vertIte;
972                 vertIte=vertexmap.find(v0);
973                 assert(vertIte!=vertexmap.end());
974                 int index0=(*vertIte).second;
975                 vertIte=vertexmap.find(v1);
976                 assert(vertIte!=vertexmap.end());
977                 int index1=(*vertIte).second;
978                 vertIte=vertexmap.find(v2);
979                 assert(vertIte!=vertexmap.end());
980                 int index2=(*vertIte).second;
981                 assert((index0!=index1)&&(index1!=index2));
982                 fprintf(f,"%d,%d,%d \n",index0,index1,index2);
983                 facemap.insert(std::pair<BaseFace*,int>(face,index));
984                 index++;
985             }
986         }
987 
988         ///high resolution mesh
989         fprintf(f,"%d,%d \n",final_mesh.fn,final_mesh.vn);
990 
991         ///add vertices
992         vertexmap.clear();
993         index=0;
994         for (unsigned int i=0;i<final_mesh.vert.size();i++)
995         {
996             BaseVertex* vert=&final_mesh.vert[i];
997             if (!vert->IsD())
998             {
999                 vertexmap.insert(std::pair<BaseVertex*,int>(vert,index));
1000                 CoordType pos=vert->P();
1001                 CoordType bary=vert->Bary;
1002                 BaseFace* father=vert->father;
1003                 iteMapFace IteF=facemap.find(father);
1004                 assert (IteF!=facemap.end());
1005                 int indexface=(*IteF).second;
1006                 fprintf(f,"%f,%f,%f;%f,%f,%f;%d,%d,%d;%d \n",
1007                 pos.X(),pos.Y(),pos.Z(),bary.X(),bary.Y(),bary.Z(),
1008                 vert->OriginalCol.X(),vert->OriginalCol.Y(),vert->OriginalCol.Z(),
1009                 indexface);
1010                 index++;
1011             }
1012         }
1013 
1014         ///add faces
1015         for (unsigned int i=0;i<final_mesh.face.size();i++)
1016         {
1017             BaseFace* face=&final_mesh.face[i];
1018             if (!face->IsD())
1019             {
1020                 BaseVertex* v0=face->V(0);
1021                 BaseVertex* v1=face->V(1);
1022                 BaseVertex* v2=face->V(2);
1023                 iteMapVert vertIte;
1024                 vertIte=vertexmap.find(v0);
1025                 assert(vertIte!=vertexmap.end());
1026                 int index0=(*vertIte).second;
1027                 vertIte=vertexmap.find(v1);
1028                 assert(vertIte!=vertexmap.end());
1029                 int index1=(*vertIte).second;
1030                 vertIte=vertexmap.find(v2);
1031                 assert(vertIte!=vertexmap.end());
1032                 int index2=(*vertIte).second;
1033                 assert((index0!=index1)&&(index1!=index2));
1034                 fprintf(f,"%d,%d,%d \n",index0,index1,index2);
1035             }
1036         }
1037         fclose(f);
1038     }
1039 
LoadMCP(char * filename)1040     int LoadMCP(char* filename)
1041     {
1042         FILE *f=NULL;
1043         f=fopen(filename,"r");
1044         if (f==NULL)
1045             return -1;
1046         /*std::map<BaseFace*,int> facemap;
1047         std::map<BaseVertex*,int> vertexmap;
1048         typedef std::map<BaseVertex*,int>::iterator iteMapVert;
1049         typedef std::map<BaseFace*,int>::iterator iteMapFace;*/
1050 
1051 
1052 
1053         ///add vertices
1054         base_mesh.Clear();
1055         fscanf(f,"%d,%d \n",&base_mesh.fn,&base_mesh.vn);
1056         base_mesh.vert.resize(base_mesh.vn);
1057         base_mesh.face.resize(base_mesh.fn);
1058 
1059         for (unsigned int i=0;i<base_mesh.vert.size();i++)
1060         {
1061             BaseVertex* vert=&base_mesh.vert[i];
1062             CoordType pos;
1063             CoordType RPos;
1064             fscanf(f,"%f,%f,%f;%f,%f,%f \n",&pos.X(),&pos.Y(),&pos.Z(),&RPos.X(),&RPos.Y(),&RPos.Z());
1065             vert->P()=pos;
1066             vert->RPos=RPos;
1067         }
1068 
1069 
1070 
1071         ///add faces
1072         for (unsigned int i=0;i<base_mesh.face.size();i++)
1073         {
1074             BaseFace* face=&base_mesh.face[i];
1075             if (!face->IsD())
1076             {
1077                 int index0,index1,index2;
1078                 fscanf(f,"%d,%d,%d \n",&index0,&index1,&index2);
1079                 base_mesh.face[i].V(0)=&base_mesh.vert[index0];
1080                 base_mesh.face[i].V(1)=&base_mesh.vert[index1];
1081                 base_mesh.face[i].V(2)=&base_mesh.vert[index2];
1082                 base_mesh.face[i].group=vcg::Color4b(rand()%200,rand()%200,rand()%200,255);
1083             }
1084         }
1085 
1086         ///high resolution mesh
1087         fscanf(f,"%d,%d \n",&final_mesh.fn,&final_mesh.vn);
1088         final_mesh.vert.resize(final_mesh.vn);
1089         final_mesh.face.resize(final_mesh.fn);
1090 
1091         ///add vertices
1092         for (unsigned int i=0;i<final_mesh.vert.size();i++)
1093         {
1094             BaseVertex* vert=&final_mesh.vert[i];
1095             CoordType pos;
1096             CoordType bary;
1097             vcg::Color4b col;
1098             int index_face;
1099             int col0,col1,col2;
1100             fscanf(f,"%f,%f,%f;%f,%f,%f;%d,%d,%d;%d \n",
1101                   &pos.X(),&pos.Y(),&pos.Z(),
1102                   &bary.X(),&bary.Y(),&bary.Z(),
1103                   &col0,&col1,&col2,
1104                   &index_face);
1105             vert->P()=pos;
1106             vert->RPos=pos;
1107             vert->Bary=bary;
1108             vert->father=&base_mesh.face[index_face];
1109             assert(!base_mesh.face[index_face].IsD());
1110             col=vcg::Color4b(col0,col1,col2,255);
1111             vert->OriginalCol=col;
1112             /*if (i==final_mesh.vert.size()-1)
1113             {
1114                 printf("sukka %d \n",index_face);
1115                 char test;
1116                 scanf ("%c",&test);
1117             }*/
1118 
1119         }
1120 
1121         ///add faces
1122         for (unsigned int i=0;i<final_mesh.face.size();i++)
1123         {
1124             //BaseFace* face=&final_mesh.face[i];
1125 
1126             int index0,index1,index2;
1127             fscanf(f,"%d,%d,%d \n",&index0,&index1,&index2);
1128             final_mesh.face[i].V(0)=&final_mesh.vert[index0];
1129             final_mesh.face[i].V(1)=&final_mesh.vert[index1];
1130             final_mesh.face[i].V(2)=&final_mesh.vert[index2];
1131 
1132         }
1133         fclose(f);
1134 
1135         ///update structures
1136         UpdateStructures(&base_mesh);
1137         UpdateStructures(&final_mesh);
1138         //Colo
1139         ///clear father and bary
1140         for (unsigned int i=0;i<base_mesh.face.size();i++)
1141             base_mesh.face[i].vertices_bary.resize(0);
1142 
1143         ///set face-vertex link
1144         for (unsigned int i=0;i<final_mesh.vert.size();i++)
1145         {
1146             BaseVertex *v=&final_mesh.vert[i];
1147             BaseFace *f=v->father;
1148             CoordType bary=v->Bary;
1149             f->vertices_bary.push_back(std::pair<BaseVertex *,CoordType>(v,bary));
1150         }
1151 
1152         //ColorByParametrization();
1153         PrintAttributes();
1154         //printf("faces:%5d AREA  distorsion:%lf\n",base_mesh.fn,ApproxAreaDistortion<BaseMesh>(final_mesh,base_mesh.fn));
1155         //printf("faces:%5d ANGLE distorsion:%lf\n",base_mesh.fn,ApproxAngleDistortion<BaseMesh>(final_mesh));
1156 
1157         vcg::tri::UpdateBounding<BaseMesh>::Box(final_mesh);
1158 
1159         ///area perr vertex
1160         for (unsigned int i=0;i<final_mesh.vert.size();i++)
1161             //AuxHPara[i].area=0;
1162             final_mesh.vert[i].area=0;
1163 
1164 
1165         for (unsigned int i=0;i<final_mesh.face.size();i++)
1166         {
1167             BaseFace *f=&final_mesh.face[i];
1168             ScalarType areaf=(((f->V(1)->P()-f->V(0)->P())^(f->V(2)->P()-f->V(0)->P())).Norm())/(ScalarType)2.0;
1169             /*AuxHPara[f->V(0)].area+=areaf/3.0;
1170             AuxHPara[f->V(1)].area+=areaf/3.0;
1171             AuxHPara[f->V(2)].area+=areaf/3.0;*/
1172             f->V(0)->area+=areaf/(ScalarType)3.0;
1173             f->V(1)->area+=areaf/(ScalarType)3.0;
1174             f->V(2)->area+=areaf/(ScalarType)3.0;
1175         }
1176 
1177         return 0;
1178     }
1179 
ExportMeshes(ParamMesh & para_mesh,AbstractMesh & abs_mesh)1180     void ExportMeshes(ParamMesh &para_mesh,AbstractMesh &abs_mesh)
1181     {
1182         para_mesh.Clear();
1183         abs_mesh.Clear();
1184 
1185         ///copy meshes
1186         vcg::tri::Append<AbstractMesh,BaseMesh>::Mesh(abs_mesh,base_mesh);
1187         vcg::tri::Append<ParamMesh,BaseMesh>::Mesh(para_mesh,final_mesh);
1188 
1189         ///copy additional values
1190         for (unsigned int i=0;i<base_mesh.vert.size();i++)
1191         {
1192             assert (!base_mesh.vert[i].IsD());
1193             abs_mesh.vert[i].RPos=base_mesh.vert[i].RPos;
1194         }
1195 
1196         for (unsigned int i=0;i<final_mesh.vert.size();i++)
1197             para_mesh.vert[i].RPos=final_mesh.vert[i].RPos;
1198 
1199         ///save in a table face-faces correspondences
1200         std::map<BaseFace*,int> faceMap;
1201         for (unsigned int i=0;i<base_mesh.face.size();i++)
1202             faceMap.insert(std::pair<BaseFace*,int>(&base_mesh.face[i],i));
1203 
1204         ///then reassing with new mesh
1205         for (unsigned int i=0;i<final_mesh.vert.size();i++)
1206         {
1207             std::map<BaseFace*,int>::iterator cur  = faceMap.find(final_mesh.vert[i].father);
1208             assert(cur!= faceMap.end());
1209             CoordType bary=final_mesh.vert[i].Bary;
1210             int index=(*cur).second;
1211             para_mesh.vert[i].T().N()=index;
1212 #ifdef _DEBUG
1213             bool done=NormalizeBaryCoords(bary);
1214             assert(done);
1215 #else
1216             NormalizeBaryCoords(bary);
1217 #endif
1218             para_mesh.vert[i].T().U()=bary.X();
1219             para_mesh.vert[i].T().V()=bary.Y();
1220 
1221         }
1222     }
1223 
1224     //int draw_mode;
1225 
PrintAttributes()1226     void PrintAttributes()
1227     {
1228         int done=(final_mesh.fn-base_mesh.fn);
1229         int total=(final_mesh.fn-lower_limit);
1230         ScalarType ratio=(ScalarType)done/total;
1231         ratio=pow(ratio,3);
1232         int percent=(int)(ratio*(ScalarType)100);
1233         ScalarType areaD=ApproxAreaDistortion<BaseMesh>(final_mesh,base_mesh.fn);
1234         ScalarType angleD=ApproxAngleDistortion<BaseMesh>(final_mesh);
1235         char ret[200];
1236         sprintf(ret," GATHERING ABSTRACT DOMAIN faces:%5d AREA  distorsion:%4f ; ANGLE distorsion:%4f ",base_mesh.fn,areaD,angleD);
1237         (*cb)(percent,ret);
1238     }
1239 
1240     void SetParameters(vcg::CallBackPos *_cb,
1241                        const int &_lower_limit=100,
1242                        const int &_interval=50,
1243                        StopMode _SMode=SM_Euristic,
1244                        const int &_accuracy=1)
1245     {
1246         lower_limit=_lower_limit;
1247         interval=_interval;
1248         accuracy=_accuracy;
1249         SMode=_SMode;
1250         ParaInfo::SM()=_SMode;
1251         cb=_cb;
1252     }
1253 
getValues(ScalarType & aggregate,ScalarType & L2,int & n_faces)1254     void getValues(ScalarType &aggregate,
1255                         ScalarType &L2,
1256                         int &n_faces)
1257     {
1258     L2=ApproxL2Error(final_mesh);
1259     ScalarType val0=ApproxAreaDistortion<BaseMesh>(final_mesh,base_mesh.fn);
1260     ScalarType val1=ApproxAngleDistortion<BaseMesh>(final_mesh);
1261     aggregate=geomAverage<ScalarType>(val0+1.0,val1+1.0,3,1)-1;
1262     n_faces=base_mesh.fn;
1263     }
1264 
IsoParametrizator()1265     IsoParametrizator()
1266     {
1267         ///parameters
1268         SMode=SM_Euristic;
1269         lower_limit=40;
1270         interval=50;
1271         accuracy=1;
1272     }
1273 
1274 };
1275 
1276 #endif
1277