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,¶_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,¶_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=¶_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 ¶_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