00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #ifndef VORONOI_PROCESSING_H
00025 #define VORONOI_PROCESSING_H
00026
00027 #include<vcg/complex/algorithms/geodesic.h>
00028 #include<vcg/complex/algorithms/update/color.h>
00029 #include<vcg/complex/algorithms/refine.h>
00030 #include<vcg/complex/algorithms/smooth.h>
00031 #include<vcg/space/fitting3.h>
00032 #include<wrap/callback.h>
00033
00034 namespace vcg
00035 {
00036 namespace tri
00037 {
00038
00039 struct VoronoiProcessingParameter
00040 {
00041 enum {
00042 None=0,
00043 DistanceFromSeed=1,
00044 DistanceFromBorder=2,
00045 RegionArea=3
00046 };
00047
00048 VoronoiProcessingParameter()
00049 {
00050 colorStrategy = DistanceFromSeed;
00051 areaThresholdPerc=0;
00052 deleteUnreachedRegionFlag=false;
00053 constrainSelectedSeed=false;
00054 preserveFixedSeed=false;
00055 collapseShortEdge=false;
00056 collapseShortEdgePerc = 0.01f;
00057 triangulateRegion=false;
00058 unbiasedSeedFlag = true;
00059 geodesicRelaxFlag = true;
00060 relaxOnlyConstrainedFlag=false;
00061 refinementRatio = 5.0f;
00062 seedPerturbationProbability=0;
00063 seedPerturbationAmount = 0.001f;
00064
00065 }
00066 int colorStrategy;
00067
00068 float areaThresholdPerc;
00069 bool deleteUnreachedRegionFlag;
00070
00071 bool unbiasedSeedFlag;
00072 bool constrainSelectedSeed;
00073
00074
00075
00076
00077
00078
00079 bool relaxOnlyConstrainedFlag;
00080
00081 bool preserveFixedSeed;
00082
00083
00084 float refinementRatio;
00085
00086
00087
00088 float seedPerturbationProbability;
00089 float seedPerturbationAmount;
00090
00091
00092
00093 bool triangulateRegion;
00094
00095
00096
00097 bool collapseShortEdge;
00098 float collapseShortEdgePerc;
00099
00100 bool geodesicRelaxFlag;
00101 };
00102
00103 template <class MeshType, class DistanceFunctor = EuclideanDistance<MeshType> >
00104 class VoronoiProcessing
00105 {
00106 typedef typename MeshType::CoordType CoordType;
00107 typedef typename MeshType::ScalarType ScalarType;
00108 typedef typename MeshType::VertexType VertexType;
00109 typedef typename MeshType::VertexPointer VertexPointer;
00110 typedef typename MeshType::VertexIterator VertexIterator;
00111 typedef typename MeshType::FacePointer FacePointer;
00112 typedef typename MeshType::FaceIterator FaceIterator;
00113 typedef typename MeshType::FaceType FaceType;
00114 typedef typename MeshType::FaceContainer FaceContainer;
00115 typedef typename tri::Geodesic<MeshType>::VertDist VertDist;
00116
00117 static math::MarsenneTwisterRNG &RandomGenerator()
00118 {
00119 static math::MarsenneTwisterRNG rnd;
00120 return rnd;
00121 }
00122
00123 public:
00124
00125 typedef typename MeshType::template PerVertexAttributeHandle<VertexPointer> PerVertexPointerHandle;
00126 typedef typename MeshType::template PerVertexAttributeHandle<bool> PerVertexBoolHandle;
00127 typedef typename MeshType::template PerVertexAttributeHandle<float> PerVertexFloatHandle;
00128 typedef typename MeshType::template PerFaceAttributeHandle<VertexPointer> PerFacePointerHandle;
00129
00130
00131
00132
00133 static void SeedToVertexConversion(MeshType &m,std::vector<CoordType> &seedPVec,std::vector<VertexType *> &seedVVec, bool compactFlag = true)
00134 {
00135 typedef typename vcg::SpatialHashTable<VertexType, ScalarType> HashVertexGrid;
00136 seedVVec.clear();
00137
00138 HashVertexGrid HG;
00139 HG.Set(m.vert.begin(),m.vert.end());
00140
00141 const float dist_upper_bound=m.bbox.Diag()/10.0;
00142
00143 typename std::vector<CoordType>::iterator pi;
00144 for(pi=seedPVec.begin();pi!=seedPVec.end();++pi)
00145 {
00146 ScalarType dist;
00147 VertexPointer vp;
00148 vp=tri::GetClosestVertex<MeshType,HashVertexGrid>(m, HG, *pi, dist_upper_bound, dist);
00149 if(vp)
00150 {
00151 seedVVec.push_back(vp);
00152 }
00153 }
00154 if(compactFlag)
00155 {
00156 std::sort(seedVVec.begin(),seedVVec.end());
00157 typename std::vector<VertexType *>::iterator vi = std::unique(seedVVec.begin(),seedVVec.end());
00158 seedVVec.resize( std::distance(seedVVec.begin(),vi) );
00159 }
00160 }
00161
00162
00163 static void ComputePerVertexSources(MeshType &m, std::vector<VertexType *> &seedVec, DistanceFunctor &df)
00164 {
00165 tri::Allocator<MeshType>::DeletePerVertexAttribute(m,"sources");
00166 PerVertexPointerHandle vertexSources = tri::Allocator<MeshType>:: template AddPerVertexAttribute<VertexPointer> (m,"sources");
00167
00168 tri::Allocator<MeshType>::DeletePerFaceAttribute(m,"sources");
00169 tri::Allocator<MeshType>::template AddPerFaceAttribute<VertexPointer> (m,"sources");
00170
00171 assert(tri::Allocator<MeshType>::IsValidHandle(m,vertexSources));
00172
00173 tri::Geodesic<MeshType>::Compute(m,seedVec,df,std::numeric_limits<ScalarType>::max(),0,&vertexSources);
00174 }
00175
00176 static void VoronoiColoring(MeshType &m, bool frontierFlag=true)
00177 {
00178 PerVertexPointerHandle sources = tri::Allocator<MeshType>:: template GetPerVertexAttribute<VertexPointer> (m,"sources");
00179 assert(tri::Allocator<MeshType>::IsValidHandle(m,sources));
00180
00181 if(frontierFlag)
00182 {
00183
00184
00185 std::pair<float,VertexPointer> zz(0.0f,static_cast<VertexPointer>(NULL));
00186 std::vector< std::pair<float,VertexPointer> > regionArea(m.vert.size(),zz);
00187 std::vector<VertexPointer> frontierVec;
00188 GetAreaAndFrontier(m, sources, regionArea, frontierVec);
00189 tri::Geodesic<MeshType>::Compute(m,frontierVec);
00190 }
00191 float minQ = std::numeric_limits<float>::max();
00192 float maxQ = -std::numeric_limits<float>::max();
00193
00194 for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi)
00195 if(sources[*vi])
00196 {
00197 if( (*vi).Q() < minQ) minQ=(*vi).Q();
00198 if( (*vi).Q() > maxQ) maxQ=(*vi).Q();
00199 }
00200 for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi)
00201 if(sources[*vi])
00202 (*vi).C().SetColorRamp(minQ,maxQ,(*vi).Q());
00203 else
00204 (*vi).C()=Color4b::DarkGray;
00205
00206
00207 }
00208
00209 static void VoronoiAreaColoring(MeshType &m,std::vector<VertexType *> &seedVec,
00210 std::vector< std::pair<float,VertexPointer> > ®ionArea)
00211 {
00212 PerVertexPointerHandle vertexSources = tri::Allocator<MeshType>:: template GetPerVertexAttribute<VertexPointer> (m,"sources");
00213 float meshArea = tri::Stat<MeshType>::ComputeMeshArea(m);
00214 float expectedArea = meshArea/float(seedVec.size());
00215 for(size_t i=0;i<m.vert.size();++i)
00216 m.vert[i].C()=Color4b::ColorRamp(expectedArea *0.75f ,expectedArea*1.25f, regionArea[tri::Index(m,vertexSources[i])].first);
00217 }
00218
00219
00220
00221
00222
00223 static void FaceAssociateRegion(MeshType &m)
00224 {
00225 PerFacePointerHandle faceSources = tri::Allocator<MeshType>:: template GetPerFaceAttribute<VertexPointer> (m,"sources");
00226 PerVertexPointerHandle vertexSources = tri::Allocator<MeshType>:: template GetPerVertexAttribute<VertexPointer> (m,"sources");
00227 for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi)
00228 {
00229 faceSources[fi]=0;
00230 std::vector<VertexPointer> vp(3);
00231 for(int i=0;i<3;++i) vp[i]=vertexSources[fi->V(i)];
00232
00233 for(int i=0;i<3;++i)
00234 {
00235 if(vp[0]==vp[1] && vp[0]==vp[2]) faceSources[fi] = vp[0];
00236 else
00237 {
00238 if(vp[0]==vp[1] && vp[0]->Q()< vp[2]->Q()) faceSources[fi] = vp[0];
00239 if(vp[0]==vp[2] && vp[0]->Q()< vp[1]->Q()) faceSources[fi] = vp[0];
00240 if(vp[1]==vp[2] && vp[1]->Q()< vp[0]->Q()) faceSources[fi] = vp[1];
00241 }
00242 }
00243 }
00244 tri::UpdateTopology<MeshType>::FaceFace(m);
00245 int unassCnt=0;
00246 do
00247 {
00248 unassCnt=0;
00249 for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi)
00250 {
00251 if(faceSources[fi]==0)
00252 {
00253 std::vector<VertexPointer> vp(3);
00254 for(int i=0;i<3;++i)
00255 vp[i]=faceSources[fi->FFp(i)];
00256
00257 if(vp[0]!=0 && (vp[0]==vp[1] || vp[0]==vp[2]))
00258 faceSources[fi] = vp[0];
00259 else if(vp[1]!=0 && (vp[1]==vp[2]))
00260 faceSources[fi] = vp[1];
00261 else
00262 faceSources[fi] = std::max(vp[0],std::max(vp[1],vp[2]));
00263 if(faceSources[fi]==0) unassCnt++;
00264 }
00265 }
00266 }
00267 while(unassCnt>0);
00268 }
00269
00270
00271
00272
00273 static int FaceSelectAssociateRegion(MeshType &m, VertexPointer vp)
00274 {
00275 PerFacePointerHandle sources = tri::Allocator<MeshType>:: template FindPerFaceAttribute<VertexPointer> (m,"sources");
00276 assert(tri::Allocator<MeshType>::IsValidHandle(m,sources));
00277 tri::UpdateSelection<MeshType>::Clear(m);
00278 int selCnt=0;
00279 for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi)
00280 {
00281 if(sources[fi]==vp)
00282 {
00283 fi->SetS();
00284 ++selCnt;
00285 }
00286 }
00287 return selCnt;
00288 }
00289
00290
00291
00292
00293
00294
00295 static int FaceSelectRegion(MeshType &m, VertexPointer vp)
00296 {
00297 PerVertexPointerHandle sources = tri::Allocator<MeshType>:: template GetPerVertexAttribute<VertexPointer> (m,"sources");
00298 assert(tri::Allocator<MeshType>::IsValidHandle(m,sources));
00299 tri::UpdateSelection<MeshType>::Clear(m);
00300 int selCnt=0;
00301 for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi)
00302 {
00303 int minInd = 0; float minVal=std::numeric_limits<float>::max();
00304 for(int i=0;i<3;++i)
00305 {
00306 if((*fi).V(i)->Q()<minVal)
00307 {
00308 minInd=i;
00309 minVal=(*fi).V(i)->Q();
00310 }
00311 }
00312
00313 if( sources[(*fi).V(minInd)] == vp)
00314 {
00315 fi->SetS();
00316 selCnt++;
00317 }
00318 }
00319 return selCnt;
00320 }
00321
00329
00330 static void GetAreaAndFrontier(MeshType &m, PerVertexPointerHandle &sources,
00331 std::vector< std::pair<float, VertexPointer> > ®ionArea,
00332 std::vector<VertexPointer> &frontierVec)
00333 {
00334 tri::UpdateFlags<MeshType>::VertexClearV(m);
00335 frontierVec.clear();
00336 for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi)
00337 {
00338 VertexPointer s0 = sources[(*fi).V(0)];
00339 VertexPointer s1 = sources[(*fi).V(1)];
00340 VertexPointer s2 = sources[(*fi).V(2)];
00341 assert(s0 && s1 && s2);
00342 if((s0 != s1) || (s0 != s2) )
00343 {
00344 for(int i=0;i<3;++i)
00345 if(!fi->V(i)->IsV())
00346 {
00347 frontierVec.push_back(fi->V(i));
00348 fi->V(i)->SetV();
00349 }
00350 }
00351 else
00352 {
00353 if(s0 != 0)
00354 {
00355 int seedIndex = tri::Index(m,s0);
00356 regionArea[seedIndex].first+=DoubleArea(*fi)*0.5f;
00357 regionArea[seedIndex].second=s0;
00358 }
00359 }
00360 }
00361 }
00362
00363
00368
00369 static void GetFaceCornerVec(MeshType &m, PerVertexPointerHandle &sources,
00370 std::vector<FacePointer> &cornerVec,
00371 std::vector<FacePointer> &borderCornerVec)
00372 {
00373 tri::UpdateFlags<MeshType>::VertexClearV(m);
00374 cornerVec.clear();
00375 for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi)
00376 {
00377 VertexPointer s0 = sources[(*fi).V(0)];
00378 VertexPointer s1 = sources[(*fi).V(1)];
00379 VertexPointer s2 = sources[(*fi).V(2)];
00380 assert(s0 && s1 && s2);
00381 if(s1!=s2 && s0!=s1 && s0!=s2) {
00382 cornerVec.push_back(&*fi);
00383 }
00384 else
00385 {
00386 if(isBorderCorner(&*fi,sources))
00387 borderCornerVec.push_back(&*fi);
00388 }
00389 }
00390 }
00391
00392 static bool isBorderCorner(FaceType *f, typename MeshType::template PerVertexAttributeHandle<VertexPointer> &sources)
00393 {
00394 for(int i=0;i<3;++i)
00395 {
00396 if(sources[(*f).V0(i)] != sources[(*f).V1(i)] && f->IsB(i))
00397 return true;
00398 }
00399 return false;
00400 }
00401
00402
00403 static VertexPointer CommonSourceBetweenBorderCorner(FacePointer f0, FacePointer f1, typename MeshType::template PerVertexAttributeHandle<VertexPointer> &sources)
00404 {
00405 assert(isBorderCorner(f0,sources));
00406 assert(isBorderCorner(f1,sources));
00407 int b0 =-1,b1=-1;
00408 for(int i=0;i<3;++i)
00409 {
00410 if(face::IsBorder(*f0,i)) b0=i;
00411 if(face::IsBorder(*f1,i)) b1=i;
00412 }
00413 assert(b0!=-1 && b1!=-1);
00414
00415 if( (sources[f0->V0(b0)] == sources[f1->V0(b1)]) || (sources[f0->V0(b0)] == sources[f1->V1(b1)]) )
00416 return sources[f0->V0(b0)];
00417
00418 if( (sources[f0->V1(b0)] == sources[f1->V0(b1)]) || (sources[f0->V1(b0)] == sources[f1->V1(b1)]) )
00419 return sources[f0->V1(b0)];
00420
00421 assert(0);
00422 return 0;
00423 }
00424
00425
00426 static void ConvertVoronoiDiagramToMesh(MeshType &m,
00427 MeshType &outMesh, MeshType &outPoly,
00428 std::vector<VertexType *> &seedVec,
00429 VoronoiProcessingParameter &vpp )
00430 {
00431 tri::RequirePerVertexAttribute(m,"sources");
00432 PerVertexPointerHandle sources = tri::Allocator<MeshType>:: template GetPerVertexAttribute<VertexPointer> (m,"sources");
00433 outMesh.Clear();
00434 outPoly.Clear();
00435 tri::UpdateTopology<MeshType>::FaceFace(m);
00436 tri::UpdateFlags<MeshType>::FaceBorderFromFF(m);
00437
00438 std::vector<FacePointer> innerCornerVec,
00439 borderCornerVec;
00440 GetFaceCornerVec(m, sources, innerCornerVec, borderCornerVec);
00441
00442
00443 for(size_t i=0;i<seedVec.size();++i)
00444 tri::Allocator<MeshType>::AddVertex(outMesh,seedVec[i]->P(),Color4b::DarkGray);
00445
00446 for(size_t i=0;i<seedVec.size();++i)
00447 {
00448 VertexPointer curSeed=seedVec[i];
00449 vector<CoordType> pt;
00450 for(size_t j=0;j<innerCornerVec.size();++j)
00451 for(int qq=0;qq<3;qq++)
00452 if(sources[innerCornerVec[j]->V(qq)] == curSeed)
00453 {
00454 pt.push_back(Barycenter(*innerCornerVec[j]));
00455 break;
00456 }
00457 for(size_t j=0;j<borderCornerVec.size();++j)
00458 for(int qq=0;qq<3;qq++)
00459 if(sources[borderCornerVec[j]->V(qq)] == curSeed)
00460 {
00461 CoordType edgeCenter;
00462 for(int jj=0;jj<3;++jj) if(face::IsBorder(*(borderCornerVec[j]),jj))
00463 edgeCenter=(borderCornerVec[j]->P0(jj)+borderCornerVec[j]->P1(jj))/2.0f;
00464 pt.push_back(edgeCenter);
00465 break;
00466 }
00467 Plane3<ScalarType> pl;
00468 pt.push_back(curSeed->P());
00469 FitPlaneToPointSet(pt,pl);
00470 pt.pop_back();
00471 CoordType nZ = pl.Direction();
00472 CoordType nX = (pt[0]-curSeed->P()).Normalize();
00473 CoordType nY = (nX^nZ).Normalize();
00474 vector<std::pair<float,int> > angleVec(pt.size());
00475 for(size_t j=0;j<pt.size();++j)
00476 {
00477 CoordType p = (pt[j]-curSeed->P()).Normalize();
00478 float angle = 180.0f+math::ToDeg(atan2(p*nY,p*nX));
00479 angleVec[j] = make_pair(angle,j);
00480 }
00481 std::sort(angleVec.begin(),angleVec.end());
00482
00483 int curRegionStart=outMesh.vert.size();
00484
00485
00486 for(size_t j=0;j<pt.size();++j)
00487 tri::Allocator<MeshType>::AddVertex(outMesh,pt[angleVec[j].second],Color4b::LightGray);
00488
00489 for(size_t j=0;j<pt.size();++j){
00490 float curAngle = angleVec[(j+1)%pt.size()].first - angleVec[j].first;
00491
00492 if(curAngle < 0) curAngle += 360.0;
00493 if(curAngle < 170.0)
00494 tri::Allocator<MeshType>::AddFace(outMesh,
00495 &outMesh.vert[i ],
00496 &outMesh.vert[curRegionStart + j ],
00497 &outMesh.vert[curRegionStart + ((j+1)%pt.size())]);
00498 outMesh.face.back().SetF(0);
00499 outMesh.face.back().SetF(2);
00500 }
00501 }
00502 tri::Clean<MeshType>::RemoveDuplicateVertex(outMesh);
00503 tri::UpdateTopology<MeshType>::FaceFace(outMesh);
00504 bool oriented,orientable;
00505 tri::Clean<MeshType>::OrientCoherentlyMesh(outMesh,oriented,orientable);
00506 tri::UpdateTopology<MeshType>::FaceFace(outMesh);
00507
00508
00509 for(FaceIterator fi=outMesh.face.begin();fi!=outMesh.face.end();++fi)
00510 for(int i=0;i<3;++i)
00511 if(face::IsBorder(*fi,i) && fi->IsF(i)) fi->ClearF(i);
00512
00513 std::vector< typename tri::UpdateTopology<MeshType>::PEdge> EdgeVec;
00514
00515
00516
00517
00518 if(vpp.triangulateRegion)
00519 {
00520 tri::UpdateFlags<MeshType>::FaceBorderFromFF(outMesh);
00521 tri::UpdateFlags<MeshType>::VertexBorderFromFaceBorder(outMesh);
00522 for(FaceIterator fi=outMesh.face.begin();fi!=outMesh.face.end();++fi) if(!fi->IsD())
00523 {
00524 for(int i=0;i<3;++i)
00525 {
00526 bool b0 = fi->V0(i)->IsB();
00527 bool b1 = fi->V1(i)->IsB();
00528 if( ((b0 && b1) || (fi->IsF(i) && !b0) ) &&
00529 tri::Index(outMesh,fi->V0(i))<seedVec.size())
00530 {
00531 if(!seedVec[tri::Index(outMesh,fi->V0(i))]->IsS())
00532 if(face::FFLinkCondition(*fi, i))
00533 {
00534 face::FFEdgeCollapse(outMesh, *fi,i);
00535 break;
00536 }
00537 }
00538 }
00539 }
00540 }
00541
00542
00543 tri::UpdateTopology<MeshType>::FillUniqueEdgeVector(outMesh,EdgeVec,false);
00544 tri::UpdateTopology<MeshType>::AllocateEdge(outMesh);
00545 for(size_t i=0;i<outMesh.vert.size();++i)
00546 tri::Allocator<MeshType>::AddVertex(outPoly,outMesh.vert[i].P());
00547 for(size_t i=0;i<EdgeVec.size();++i)
00548 {
00549 size_t e0 = tri::Index(outMesh,EdgeVec[i].v[0]);
00550 size_t e1 = tri::Index(outMesh,EdgeVec[i].v[1]);
00551 assert(e0<outPoly.vert.size());
00552 tri::Allocator<MeshType>::AddEdge(outPoly,&(outPoly.vert[e0]),&(outPoly.vert[e1]));
00553 }
00554
00555 }
00556
00566
00567 static void ConvertVoronoiDiagramToMeshOld(MeshType &m,
00568 MeshType &outMesh, MeshType &outPoly,
00569 std::vector<VertexType *> &seedVec,
00570 VoronoiProcessingParameter &vpp )
00571 {
00572 tri::RequirePerVertexAttribute(m,"sources");
00573 PerVertexPointerHandle sources = tri::Allocator<MeshType>:: template GetPerVertexAttribute<VertexPointer> (m,"sources");
00574
00575 outMesh.Clear();
00576 outPoly.Clear();
00577 tri::UpdateTopology<MeshType>::FaceFace(m);
00578 tri::UpdateFlags<MeshType>::FaceBorderFromFF(m);
00579
00580 std::map<VertexPointer, int> seedMap;
00581 for(size_t i=0;i<m.vert.size();++i)
00582 seedMap[&(m.vert[i])]=-1;
00583 for(size_t i=0;i<seedVec.size();++i)
00584 seedMap[seedVec[i]]=i;
00585
00586
00587 for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi)
00588 {
00589 assert(sources[vi] != 0);
00590 int ind=tri::Index(m,sources[vi]);
00591 assert((ind>=0) && (ind<m.vn));
00592 assert(seedMap[sources[vi]]!=-1);
00593 }
00594
00595 std::vector<FacePointer> innerCornerVec,
00596 borderCornerVec;
00597 GetFaceCornerVec(m, sources, innerCornerVec, borderCornerVec);
00598
00599 std::map<FacePointer,int> vertexIndCornerMap;
00600 for(size_t i=0;i<m.face.size();++i)
00601 vertexIndCornerMap[&(m.face[i])]=-1;
00602
00603
00604 for(size_t i=0;i<seedVec.size();++i)
00605 tri::Allocator<MeshType>::AddVertex(outMesh, seedVec[i]->P(),Color4b::White);
00606
00607 for(size_t i=0;i<innerCornerVec.size();++i){
00608 tri::Allocator<MeshType>::AddVertex(outMesh, vcg::Barycenter(*(innerCornerVec[i])),Color4b::Gray);
00609 vertexIndCornerMap[innerCornerVec[i]] = outMesh.vn-1;
00610 }
00611 for(size_t i=0;i<borderCornerVec.size();++i){
00612 Point3f edgeCenter;
00613 for(int j=0;j<3;++j) if(face::IsBorder(*(borderCornerVec[i]),j))
00614 edgeCenter=(borderCornerVec[i]->P0(j)+borderCornerVec[i]->P1(j))/2.0f;
00615 tri::Allocator<MeshType>::AddVertex(outMesh, edgeCenter,Color4b::Gray);
00616 vertexIndCornerMap[borderCornerVec[i]] = outMesh.vn-1;
00617 }
00618 tri::Append<MeshType,MeshType>::MeshCopy(outPoly,outMesh);
00619
00620
00621
00622
00623
00624 std::map<std::pair<VertexPointer,VertexPointer>, FacePointer > VoronoiEdge;
00625
00626
00627
00628
00629
00630 for(size_t i=0;i<innerCornerVec.size();++i)
00631 {
00632 for(int j=0;j<3;++j)
00633 {
00634 VertexPointer v0 = sources[innerCornerVec[i]->V0(j)];
00635 VertexPointer v1 = sources[innerCornerVec[i]->V1(j)];
00636 assert(seedMap[v0]>=0);assert(seedMap[v1]>=0);
00637
00638 if(v1<v0) std::swap(v0,v1); assert(v1!=v0);
00639
00640 if(VoronoiEdge[std::make_pair(v0,v1)] == 0)
00641 VoronoiEdge[std::make_pair(v0,v1)] = innerCornerVec[i];
00642 else
00643 {
00644 FacePointer otherCorner = VoronoiEdge[std::make_pair(v0,v1)];
00645 VertexPointer corner0 = &(outMesh.vert[vertexIndCornerMap[innerCornerVec[i]]]);
00646 VertexPointer corner1 = &(outMesh.vert[vertexIndCornerMap[otherCorner]]);
00647 tri::Allocator<MeshType>::AddFace(outMesh,&(outMesh.vert[seedMap[v0]]), corner0, corner1);
00648 tri::Allocator<MeshType>::AddFace(outMesh,&(outMesh.vert[seedMap[v1]]), corner1, corner0);
00649 }
00650 }
00651 }
00652
00653
00654
00655
00656 for(size_t i=0;i<borderCornerVec.size();++i)
00657 {
00658 VertexPointer s0 = sources[borderCornerVec[i]->V(0)];
00659 VertexPointer s1 = sources[borderCornerVec[i]->V(1)];
00660 if(s1==s0) s1 = sources[borderCornerVec[i]->V(2)];
00661 if(s1<s0) std::swap(s0,s1); assert(s1!=s0);
00662
00663 FacePointer innerCorner = VoronoiEdge[std::make_pair(s0,s1)] ;
00664 if(innerCorner)
00665 {
00666 VertexPointer corner0 = &(outMesh.vert[vertexIndCornerMap[innerCorner]]);
00667 VertexPointer corner1 = &(outMesh.vert[vertexIndCornerMap[borderCornerVec[i]]]);
00668 tri::Allocator<MeshType>::AddFace(outMesh,&(outMesh.vert[seedMap[s0]]), corner0, corner1);
00669 tri::Allocator<MeshType>::AddFace(outMesh,&(outMesh.vert[seedMap[s1]]), corner0, corner1);
00670 }
00671 }
00672
00673
00674 tri::UpdateFlags<MeshType>::FaceClearV(m);
00675 bool AllFaceVisited = false;
00676 while(!AllFaceVisited)
00677 {
00678
00679 face::Pos<FaceType> pos,startPos;
00680 AllFaceVisited=true;
00681 for(size_t i=0; (AllFaceVisited) && (i<borderCornerVec.size()); ++i)
00682 if(!borderCornerVec[i]->IsV())
00683 {
00684 for(int j=0;j<3;++j)
00685 if(face::IsBorder(*(borderCornerVec[i]),j))
00686 {
00687 pos.Set(borderCornerVec[i],j,borderCornerVec[i]->V(j));
00688 AllFaceVisited =false;
00689 }
00690 }
00691 if(AllFaceVisited) break;
00692 assert(pos.IsBorder());
00693 startPos=pos;
00694 bool foundBorderSeed=false;
00695 FacePointer curBorderCorner = pos.F();
00696 do
00697 {
00698 pos.F()->SetV();
00699 pos.NextB();
00700 if(sources[pos.V()]==pos.V())
00701 foundBorderSeed=true;
00702 assert(isBorderCorner(curBorderCorner,sources));
00703 if(isBorderCorner(pos.F(),sources))
00704 if(pos.F() != curBorderCorner)
00705 {
00706 VertexPointer curReg = CommonSourceBetweenBorderCorner(curBorderCorner, pos.F(),sources);
00707 VertexPointer curSeed = &(outMesh.vert[seedMap[curReg]]);
00708 int otherCorner0 = vertexIndCornerMap[pos.F() ];
00709 int otherCorner1 = vertexIndCornerMap[curBorderCorner];
00710 VertexPointer corner0 = &(outMesh.vert[otherCorner0]);
00711 VertexPointer corner1 = &(outMesh.vert[otherCorner1]);
00712 if(!foundBorderSeed)
00713 tri::Allocator<MeshType>::AddFace(outMesh,curSeed,corner0,corner1);
00714 foundBorderSeed=false;
00715 curBorderCorner=pos.F();
00716 }
00717 }
00718 while(pos!=startPos);
00719 }
00720
00721
00722
00723 bool oriented,orientable;
00724 tri::UpdateTopology<MeshType>::FaceFace(outMesh);
00725 tri::Clean<MeshType>::OrientCoherentlyMesh(outMesh,oriented,orientable);
00726
00727
00728 tri::UpdateNormal<MeshType>::PerVertexNormalizedPerFaceNormalized(outMesh);
00729 tri::UpdateNormal<MeshType>::PerVertexNormalizedPerFaceNormalized(m);
00730 if(seedVec[0]->N() * outMesh.vert[0].N() < 0 )
00731 tri::Clean<MeshType>::FlipMesh(outMesh);
00732
00733 tri::UpdateTopology<MeshType>::FaceFace(outMesh);
00734 tri::UpdateFlags<MeshType>::FaceBorderFromFF(outMesh);
00735
00736
00737 tri::UpdateNormal<MeshType>::PerFaceNormalized(outMesh);
00738 tri::UpdateFlags<MeshType>::FaceClearV(outMesh);
00739 for(FaceIterator fi=outMesh.face.begin();fi!=outMesh.face.end();++fi)
00740 {
00741 int badDiedralCnt=0;
00742 for(int i=0;i<3;++i)
00743 if(fi->N() * fi->FFp(i)->N() <0 ) badDiedralCnt++;
00744
00745 if(badDiedralCnt == 2) fi->SetV();
00746 }
00747 for(FaceIterator fi=outMesh.face.begin();fi!=outMesh.face.end();++fi)
00748 if(fi->IsV()) Allocator<MeshType>::DeleteFace(outMesh,*fi);
00749 tri::Allocator<MeshType>::CompactEveryVector(outMesh);
00750 tri::UpdateTopology<MeshType>::FaceFace(outMesh);
00751 tri::UpdateFlags<MeshType>::FaceBorderFromFF(outMesh);
00752 tri::UpdateFlags<MeshType>::VertexBorderFromFaceBorder(outMesh);
00753
00754
00755 for(FaceIterator fi=outMesh.face.begin();fi!=outMesh.face.end();++fi)
00756 for(int i=0;i<3;++i)
00757 {
00758 size_t v0 = tri::Index(outMesh,fi->V0(i) );
00759 size_t v1 = tri::Index(outMesh,fi->V1(i) );
00760 if (v0 < seedVec.size() && !(seedVec[v0]->IsB() && fi->IsB(i))) fi->SetF(i);
00761 if (v1 < seedVec.size() && !(seedVec[v1]->IsB() && fi->IsB(i))) fi->SetF(i);
00762 }
00763
00764 if(vpp.collapseShortEdge)
00765 {
00766 float distThr = m.bbox.Diag() * vpp.collapseShortEdgePerc;
00767 for(FaceIterator fi=outMesh.face.begin();fi!=outMesh.face.end();++fi) if(!fi->IsD())
00768 {
00769 for(int i=0;i<3;++i)
00770 if((Distance(fi->P0(i),fi->P1(i))<distThr) && !fi->IsF(i))
00771 {
00772
00773 if ((!fi->V(i)->IsB())&&(face::FFLinkCondition(*fi, i)))
00774 face::FFEdgeCollapse(outMesh, *fi,i);
00775 break;
00776 }
00777 }
00778 }
00779
00780
00781
00782
00783
00784
00785
00786 if(vpp.triangulateRegion)
00787 {
00788 for(FaceIterator fi=outMesh.face.begin();fi!=outMesh.face.end();++fi) if(!fi->IsD())
00789 {
00790 for(int i=0;i<3;++i)
00791 {
00792 bool b0 = fi->V0(i)->IsB();
00793 bool b1 = fi->V1(i)->IsB();
00794 if( ((b0 && b1) || (fi->IsF(i) && !b0 && !b1) ) &&
00795 tri::Index(outMesh,fi->V(i))<seedVec.size())
00796 {
00797 if(!seedVec[tri::Index(outMesh,fi->V(i))]->IsS())
00798 if(face::FFLinkCondition(*fi, i))
00799 {
00800 face::FFEdgeCollapse(outMesh, *fi,i);
00801 break;
00802 }
00803 }
00804 }
00805 }
00806 }
00807
00808
00809 std::vector< typename tri::UpdateTopology<MeshType>::PEdge> EdgeVec;
00810 tri::UpdateTopology<MeshType>::FillUniqueEdgeVector(outMesh,EdgeVec,false);
00811 tri::UpdateTopology<MeshType>::AllocateEdge(outMesh);
00812
00813 for(size_t i=0;i<EdgeVec.size();++i)
00814 {
00815 size_t e0 = tri::Index(outMesh,EdgeVec[i].v[0]);
00816 size_t e1 = tri::Index(outMesh,EdgeVec[i].v[1]);
00817 assert(e0<outPoly.vert.size());
00818 tri::Allocator<MeshType>::AddEdge(outPoly,&(outPoly.vert[e0]),&(outPoly.vert[e1]));
00819 }
00820 }
00821
00822 class VoronoiEdge
00823 {
00824 public:
00825 VertexPointer r0,r1;
00826 FacePointer f0,f1;
00827 bool operator == (const VoronoiEdge &ve) const {return ve.r0==r0 && ve.r1==r1; }
00828 bool operator < (const VoronoiEdge &ve) const { return (ve.r0==r0)?ve.r1<r1:ve.r0<r0; }
00829 float Len() const { return Distance(vcg::Barycenter(*f0), vcg::Barycenter(*f1)); }
00830 };
00831
00832 static void BuildVoronoiEdgeVec(MeshType &m, std::vector<VoronoiEdge> &edgeVec)
00833 {
00834 PerVertexPointerHandle sources = tri::Allocator<MeshType>:: template GetPerVertexAttribute<VertexPointer> (m,"sources");
00835
00836 edgeVec.clear();
00837 std::vector<FacePointer> cornerVec;
00838 std::vector<FacePointer> borderCornerVec;
00839 GetFaceCornerVec(m,sources,cornerVec,borderCornerVec);
00840
00841 typedef std::map< std::pair<VertexPointer,VertexPointer>, std::pair<FacePointer,FacePointer> > EdgeMapType;
00842 EdgeMapType EdgeMap;
00843 printf("cornerVec.size() %i\n",(int)cornerVec.size());
00844
00845 for(size_t i=0;i<cornerVec.size();++i)
00846 {
00847 for(int j=0;j<3;++j)
00848 {
00849 VertexPointer v0 = sources[cornerVec[i]->V0(j)];
00850 VertexPointer v1 = sources[cornerVec[i]->V1(j)];
00851 assert(v0!=v1);
00852 if(v0>v1) std::swap(v1,v0);
00853 std::pair<VertexPointer,VertexPointer> adjRegion = std::make_pair(v0,v1);
00854 if(EdgeMap[adjRegion].first==0)
00855 EdgeMap[adjRegion].first = cornerVec[i];
00856 else
00857 EdgeMap[adjRegion].second = cornerVec[i];
00858 }
00859 }
00860 for(size_t i=0;i<borderCornerVec.size();++i)
00861 {
00862 VertexPointer v0 = sources[borderCornerVec[i]->V(0)];
00863 VertexPointer v1 = sources[borderCornerVec[i]->V(1)];
00864 if(v0==v1) v1 = sources[borderCornerVec[i]->V(2)];
00865 assert(v0!=v1);
00866 if(v0>v1) std::swap(v1,v0);
00867 std::pair<VertexPointer,VertexPointer> adjRegion = std::make_pair(v0,v1);
00868 if(EdgeMap[adjRegion].first==0)
00869 EdgeMap[adjRegion].first = borderCornerVec[i];
00870 else
00871 EdgeMap[adjRegion].second = borderCornerVec[i];
00872
00873 }
00874 typename EdgeMapType::iterator mi;
00875 for(mi=EdgeMap.begin();mi!=EdgeMap.end();++mi)
00876 {
00877 if((*mi).second.first && (*mi).second.second)
00878 {
00879 assert((*mi).first.first && (*mi).first.second);
00880 edgeVec.push_back(VoronoiEdge());
00881 edgeVec.back().r0 = (*mi).first.first;
00882 edgeVec.back().r1 = (*mi).first.second;
00883 edgeVec.back().f0 = (*mi).second.first;
00884 edgeVec.back().f1 = (*mi).second.second;
00885 }
00886 }
00887 }
00888
00889 static void BuildBiasedSeedVec(MeshType &m,
00890 DistanceFunctor &df,
00891 std::vector<VertexPointer> &seedVec,
00892 std::vector<VertexPointer> &frontierVec,
00893 std::vector<VertDist> &biasedFrontierVec,
00894 VoronoiProcessingParameter &vpp)
00895 {
00896 (void)df;
00897 biasedFrontierVec.clear();
00898 if(vpp.unbiasedSeedFlag)
00899 {
00900 for(size_t i=0;i<frontierVec.size();++i)
00901 biasedFrontierVec.push_back(VertDist(frontierVec[i],0));
00902 assert(biasedFrontierVec.size() == frontierVec.size());
00903 return;
00904 }
00905
00906 std::vector<VoronoiEdge> edgeVec;
00907 BuildVoronoiEdgeVec(m,edgeVec);
00908 printf("Found %i edges on a diagram of %i seeds\n",int(edgeVec.size()),int(seedVec.size()));
00909
00910 std::map<VertexPointer,std::vector<VoronoiEdge *> > SeedToEdgeVecMap;
00911 std::map< std::pair<VertexPointer,VertexPointer>, VoronoiEdge *> SeedPairToEdgeMap;
00912 float totalLen=0;
00913 for(size_t i=0;i<edgeVec.size();++i)
00914 {
00915 SeedToEdgeVecMap[edgeVec[i].r0].push_back(&(edgeVec[i]));
00916 SeedToEdgeVecMap[edgeVec[i].r1].push_back(&(edgeVec[i]));
00917 SeedPairToEdgeMap[std::make_pair(edgeVec[i].r0, edgeVec[i].r1)]=&(edgeVec[i]);
00918 assert (edgeVec[i].r0 < edgeVec[i].r1);
00919 totalLen +=edgeVec[i].Len();
00920 }
00921
00922
00923 std::map <VertexPointer, float> regionPerymeter;
00924 for(size_t i=0;i<seedVec.size();++i)
00925 {
00926 for(size_t j=0;j<SeedToEdgeVecMap[seedVec[i]].size();++j)
00927 {
00928 VoronoiEdge *vep = SeedToEdgeVecMap[seedVec[i]][j];
00929 regionPerymeter[seedVec[i]]+=vep->Len();
00930 }
00931 printf("perimeter of region %i is %f\n",(int)i,regionPerymeter[seedVec[i]]);
00932 }
00933
00934
00935 PerVertexPointerHandle sources = tri::Allocator<MeshType>:: template GetPerVertexAttribute<VertexPointer> (m,"sources");
00936
00937
00938 std::map<VertexPointer,float> weight;
00939 std::map<VertexPointer,int> cnt;
00940 float biasSum = totalLen/5.0f;
00941 for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi)
00942 {
00943 for(int i=0;i<3;++i)
00944 {
00945 VertexPointer s0 = sources[(*fi).V0(i)];
00946 VertexPointer s1 = sources[(*fi).V1(i)];
00947 if(s0!=s1)
00948 {
00949 if(s0>s1) std::swap(s0,s1);
00950 VoronoiEdge *ve = SeedPairToEdgeMap[std::make_pair(s0,s1)];
00951 if(!ve) printf("v %i %i \n",(int)tri::Index(m,s0),(int)tri::Index(m,s1));
00952 assert(ve);
00953 float el = ve->Len();
00954 weight[(*fi).V0(i)] += (regionPerymeter[s0]+biasSum)/(el+biasSum) ;
00955 weight[(*fi).V1(i)] += (regionPerymeter[s1]+biasSum)/(el+biasSum) ;
00956 cnt[(*fi).V0(i)]++;
00957 cnt[(*fi).V1(i)]++;
00958 }
00959 }
00960 }
00961 for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi)
00962 {
00963 if(cnt[&*vi]>0)
00964 {
00965
00966 float bias = weight[&*vi]/float(cnt[&*vi]) + totalLen;
00967 biasedFrontierVec.push_back(VertDist(&*vi, bias));
00968 }
00969 }
00970 printf("Collected %i frontier vertexes\n",(int)biasedFrontierVec.size());
00971 }
00972
00973
00974 static void DeleteUnreachedRegions(MeshType &m, PerVertexPointerHandle &sources)
00975 {
00976 tri::UpdateFlags<MeshType>::VertexClearV(m);
00977 for(size_t i=0;i<m.vert.size();++i)
00978 if(sources[i]==0) m.vert[i].SetV();
00979
00980 for(FaceIterator fi=m.face.begin(); fi!=m.face.end();++fi)
00981 if(fi->V(0)->IsV() || fi->V(1)->IsV() || fi->V(2)->IsV() )
00982 {
00983 face::VFDetach(*fi);
00984 tri::Allocator<MeshType>::DeleteFace(m,*fi);
00985 }
00986
00987 tri::Clean<MeshType>::RemoveUnreferencedVertex(m);
00988 tri::Allocator<MeshType>::CompactEveryVector(m);
00989 }
00990
00995
00996 struct QuadricSumDistance
00997 {
00998 ScalarType a;
00999 ScalarType c;
01000 CoordType b;
01001 QuadricSumDistance() {a=0; c=0; b[0]=0; b[1]=0; b[2]=0;}
01002 void AddPoint(CoordType p)
01003 {
01004 a+=1;
01005 assert(c>=0);
01006 c+=p*p;
01007 b[0]+= -2.0f*p[0];
01008 b[1]+= -2.0f*p[1];
01009 b[2]+= -2.0f*p[2];
01010 }
01011
01012 ScalarType Eval(CoordType p) const
01013 {
01014 ScalarType d = a*(p*p) + b*p + c;
01015 assert(d>=0);
01016 return d;
01017 }
01018
01019 CoordType Min() const
01020 {
01021 return b * -0.5f;
01022 }
01023 };
01024
01036 static bool QuadricRelax(MeshType &m, std::vector<VertexType *> &seedVec,
01037 std::vector<VertexPointer> &frontierVec,
01038 std::vector<VertexType *> &newSeeds,
01039 DistanceFunctor &df,
01040 VoronoiProcessingParameter &vpp)
01041 {
01042 (void)seedVec;
01043 (void)frontierVec;
01044 (void)df;
01045 newSeeds.clear();
01046 PerVertexPointerHandle sources = tri::Allocator<MeshType>:: template GetPerVertexAttribute<VertexPointer> (m,"sources");
01047 PerVertexBoolHandle fixed = tri::Allocator<MeshType>:: template GetPerVertexAttribute<bool> (m,"fixed");
01048
01049 QuadricSumDistance dz;
01050 std::vector<QuadricSumDistance> dVec(m.vert.size(),dz);
01051 for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi)
01052 {
01053 assert(sources[vi]!=0);
01054 int seedIndex = tri::Index(m,sources[vi]);
01055
01056 if(vpp.constrainSelectedSeed)
01057 {
01058 if( (sources[vi]->IsS() && vi->IsS()) || (!sources[vi]->IsS()))
01059 dVec[seedIndex].AddPoint(vi->P());
01060 }
01061 else
01062 dVec[seedIndex].AddPoint(vi->P());
01063 }
01064
01065
01066 std::pair<float,VertexPointer> zz(std::numeric_limits<ScalarType>::max(), static_cast<VertexPointer>(0));
01067 std::vector< std::pair<float,VertexPointer> > seedMaximaVec(m.vert.size(),zz);
01068 for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi)
01069 {
01070 assert(sources[vi]!=0);
01071 int seedIndex = tri::Index(m,sources[vi]);
01072 ScalarType val = dVec[seedIndex].Eval(vi->P());
01073 vi->Q()=val;
01074
01075 if(!vpp.constrainSelectedSeed || !sources[vi]->IsS() || vi->IsS())
01076 {
01077 if(seedMaximaVec[seedIndex].first > val)
01078 {
01079 seedMaximaVec[seedIndex].first = val;
01080 seedMaximaVec[seedIndex].second = &*vi;
01081 }
01082 }
01083 }
01084
01085 if(vpp.colorStrategy==VoronoiProcessingParameter::DistanceFromBorder)
01086 tri::UpdateColor<MeshType>::PerVertexQualityRamp(m);
01087
01088
01089 bool seedChanged=false;
01090
01091 for(size_t i=0;i<m.vert.size();++i)
01092 if(seedMaximaVec[i].second)
01093 {
01094 VertexPointer curSrc = sources[seedMaximaVec[i].second];
01095 if(vpp.preserveFixedSeed && fixed[curSrc])
01096 newSeeds.push_back(curSrc);
01097 else
01098 {
01099 newSeeds.push_back(seedMaximaVec[i].second);
01100 if(curSrc != seedMaximaVec[i].second)
01101 seedChanged=true;
01102 }
01103 }
01104
01105 return seedChanged;
01106 }
01107
01115
01116 static bool GeodesicRelax(MeshType &m, std::vector<VertexType *> &seedVec, std::vector<VertexPointer> &frontierVec,
01117 std::vector<VertexType *> &newSeeds,
01118 DistanceFunctor &df, VoronoiProcessingParameter &vpp)
01119 {
01120 newSeeds.clear();
01121 typename MeshType::template PerVertexAttributeHandle<VertexPointer> sources;
01122 sources = tri::Allocator<MeshType>:: template GetPerVertexAttribute<VertexPointer> (m,"sources");
01123 typename MeshType::template PerVertexAttributeHandle<bool> fixed;
01124 fixed = tri::Allocator<MeshType>:: template GetPerVertexAttribute<bool> (m,"fixed");
01125
01126 std::vector<typename tri::Geodesic<MeshType>::VertDist> biasedFrontierVec;
01127 BuildBiasedSeedVec(m,df,seedVec,frontierVec,biasedFrontierVec,vpp);
01128 tri::Geodesic<MeshType>::Visit(m,biasedFrontierVec,df);
01129 if(vpp.colorStrategy == VoronoiProcessingParameter::DistanceFromSeed)
01130 tri::UpdateColor<MeshType>::PerVertexQualityRamp(m);
01131
01132
01133 if(vpp.colorStrategy == VoronoiProcessingParameter::DistanceFromBorder)
01134 tri::UpdateColor<MeshType>::PerVertexQualityRamp(m);
01135
01136
01137 std::pair<float,VertexPointer> zz(0.0f,static_cast<VertexPointer>(NULL));
01138 std::vector< std::pair<float,VertexPointer> > seedMaximaVec(m.vert.size(),zz);
01139 for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi)
01140 {
01141 assert(sources[vi]!=0);
01142 int seedIndex = tri::Index(m,sources[vi]);
01143
01144 if(!vpp.constrainSelectedSeed || !sources[vi]->IsS() || vi->IsS())
01145 {
01146 if(seedMaximaVec[seedIndex].first < (*vi).Q())
01147 {
01148 seedMaximaVec[seedIndex].first=(*vi).Q();
01149 seedMaximaVec[seedIndex].second=&*vi;
01150 }
01151 }
01152 }
01153
01154 bool seedChanged=false;
01155
01156
01157 for(size_t i=0;i<seedMaximaVec.size();++i)
01158 if(seedMaximaVec[i].second)
01159 {
01160 VertexPointer curSrc = sources[seedMaximaVec[i].second];
01161 if(vpp.preserveFixedSeed && fixed[curSrc])
01162 newSeeds.push_back(curSrc);
01163 else
01164 {
01165 newSeeds.push_back(seedMaximaVec[i].second);
01166 if(curSrc != seedMaximaVec[i].second) seedChanged=true;
01167 }
01168 }
01169 return seedChanged;
01170 }
01171
01172 static void PruneSeedByRegionArea(std::vector<VertexType *> &seedVec,
01173 std::vector< std::pair<float,VertexPointer> > ®ionArea,
01174 VoronoiProcessingParameter &vpp)
01175 {
01176
01177 Distribution<float> H;
01178 for(size_t i=0;i<regionArea.size();++i)
01179 if(regionArea[i].second) H.Add(regionArea[i].first);
01180 float areaThreshold=0;
01181 if(vpp.areaThresholdPerc != 0) areaThreshold = H.Percentile(vpp.areaThresholdPerc);
01182 std::vector<VertexType *> newSeedVec;
01183
01184
01185 for(size_t i=0;i<seedVec.size();++i)
01186 {
01187 if(regionArea[i].first >= areaThreshold)
01188 newSeedVec.push_back(seedVec[i]);
01189 }
01190 swap(seedVec,newSeedVec);
01191 }
01192
01198 static void FixVertexVector(MeshType &m, std::vector<VertexType *> &vertToFixVec)
01199 {
01200 typename MeshType::template PerVertexAttributeHandle<bool> fixed;
01201 fixed = tri::Allocator<MeshType>:: template GetPerVertexAttribute<bool> (m,"fixed");
01202 for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi)
01203 fixed[vi]=false;
01204 for(size_t i=0;i<vertToFixVec.size();++i)
01205 fixed[vertToFixVec[i]]=true;
01206 }
01207
01208
01209 static int RestrictedVoronoiRelaxing(MeshType &m, std::vector<CoordType> &seedPosVec,
01210 std::vector<bool> &fixedVec,
01211 int relaxStep,
01212 VoronoiProcessingParameter &vpp,
01213 vcg::CallBackPos *cb=0)
01214 {
01215 PerVertexFloatHandle area = tri::Allocator<MeshType>:: template GetPerVertexAttribute<float> (m,"area");
01216
01217 for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi)
01218 area[vi]=0;
01219
01220 for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi)
01221 {
01222 ScalarType a3 = DoubleArea(*fi)/6.0;
01223 for(int i=0;i<3;++i)
01224 area[fi->V(i)]+=a3;
01225 }
01226
01227 assert(m.vn > seedPosVec.size()*20);
01228 int i;
01229 ScalarType perturb = m.bbox.Diag()*vpp.seedPerturbationAmount;
01230 for(i=0;i<relaxStep;++i)
01231 {
01232 if(cb) cb(i*100/relaxStep,"RestrictedVoronoiRelaxing ");
01233
01234 VectorConstDataWrapper<std::vector<CoordType> > vdw(seedPosVec);
01235 KdTree<ScalarType> seedTree(vdw);
01236
01237 std::vector<std::pair<ScalarType,CoordType> > sumVec(seedPosVec.size(),std::make_pair(0,CoordType(0,0,0)));
01238 for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi)
01239 {
01240 unsigned int seedInd;
01241 ScalarType sqdist;
01242 seedTree.doQueryClosest(vi->P(),seedInd,sqdist);
01243 vi->Q()=sqrt(sqdist);
01244 sumVec[seedInd].first+=area[vi];
01245 sumVec[seedInd].second+=vi->cP()*area[vi];
01246 }
01247
01248 vector<CoordType> newseedVec;
01249 vector<bool> newfixedVec;
01250
01251 for(size_t i=0;i<seedPosVec.size();++i)
01252 {
01253 if(fixedVec[i])
01254 {
01255 newseedVec.push_back(seedPosVec[i]);
01256 newfixedVec.push_back(true);
01257 }
01258 else
01259 {
01260 if(sumVec[i].first != 0)
01261 {
01262 newseedVec.push_back(sumVec[i].second /ScalarType(sumVec[i].first));
01263 if(vpp.seedPerturbationProbability > RandomGenerator().generate01())
01264 newseedVec.back()+=math::GeneratePointInUnitBallUniform<ScalarType,math::MarsenneTwisterRNG>( RandomGenerator())*perturb;
01265 newfixedVec.push_back(false);
01266 }
01267 }
01268 }
01269 std::swap(seedPosVec,newseedVec);
01270 std::swap(fixedVec,newfixedVec);
01271 tri::UpdateColor<MeshType>::PerVertexQualityRamp(m);
01272 }
01273 return relaxStep;
01274 }
01275
01281
01282 static int VoronoiRelaxing(MeshType &m, std::vector<VertexType *> &seedVec,
01283 int relaxIter, DistanceFunctor &df,
01284 VoronoiProcessingParameter &vpp,
01285 vcg::CallBackPos *cb=0)
01286 {
01287 tri::RequireVFAdjacency(m);
01288 tri::RequireCompactness(m);
01289 for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi)
01290 assert(vi->VFp() && "Require mesh without unreferenced vertexes\n");
01291 std::vector<VertexType *> selectedVec;
01292 if(vpp.relaxOnlyConstrainedFlag)
01293 {
01294 for(size_t i=0;i<seedVec.size();++i)
01295 if(seedVec[i]->IsS())
01296 selectedVec.push_back(seedVec[i]);
01297 std::swap(seedVec,selectedVec);
01298 }
01299
01300 tri::UpdateFlags<MeshType>::FaceBorderFromVF(m);
01301 tri::UpdateFlags<MeshType>::VertexBorderFromFaceBorder(m);
01302 PerVertexPointerHandle sources = tri::Allocator<MeshType>:: template GetPerVertexAttribute<VertexPointer> (m,"sources");
01303 PerVertexBoolHandle fixed = tri::Allocator<MeshType>:: template GetPerVertexAttribute<bool> (m,"fixed");
01304 int iter;
01305 for(iter=0;iter<relaxIter;++iter)
01306 {
01307 if(cb) cb(iter*100/relaxIter,"Voronoi Lloyd Relaxation: First Partitioning");
01308
01309
01310 tri::Geodesic<MeshType>::Compute(m, seedVec, df,std::numeric_limits<ScalarType>::max(),0,&sources);
01311
01312 if(vpp.colorStrategy == VoronoiProcessingParameter::DistanceFromSeed)
01313 tri::UpdateColor<MeshType>::PerVertexQualityRamp(m);
01314
01315
01316 if(vpp.deleteUnreachedRegionFlag) DeleteUnreachedRegions(m,sources);
01317 std::pair<float,VertexPointer> zz(0.0f,static_cast<VertexPointer>(NULL));
01318 std::vector< std::pair<float,VertexPointer> > regionArea(m.vert.size(),zz);
01319 std::vector<VertexPointer> frontierVec;
01320
01321 GetAreaAndFrontier(m, sources, regionArea, frontierVec);
01322 assert(frontierVec.size()>0);
01323
01324 if(vpp.colorStrategy == VoronoiProcessingParameter::RegionArea) VoronoiAreaColoring(m, seedVec, regionArea);
01325
01326
01327
01328 if(cb) cb(iter*100/relaxIter,"Voronoi Lloyd Relaxation: Searching New Seeds");
01329 std::vector<VertexPointer> newSeedVec;
01330
01331 bool changed;
01332 if(vpp.geodesicRelaxFlag)
01333 changed = GeodesicRelax(m,seedVec, frontierVec, newSeedVec, df,vpp);
01334 else
01335 changed = QuadricRelax(m,seedVec,frontierVec, newSeedVec, df,vpp);
01336
01337
01338 PruneSeedByRegionArea(newSeedVec,regionArea,vpp);
01339
01340 for(size_t i=0;i<frontierVec.size();++i)
01341 frontierVec[i]->C() = Color4b::Gray;
01342 for(size_t i=0;i<seedVec.size();++i)
01343 seedVec[i]->C() = Color4b::Black;
01344 for(size_t i=0;i<newSeedVec.size();++i)
01345 newSeedVec[i]->C() = Color4b::White;
01346
01347 swap(newSeedVec,seedVec);
01348 if(!changed) break;
01349 }
01350
01351
01352 if(iter==relaxIter)
01353 tri::Geodesic<MeshType>::Compute(m, seedVec, df,std::numeric_limits<ScalarType>::max(),0,&sources);
01354
01355 if(vpp.relaxOnlyConstrainedFlag)
01356 {
01357 std::swap(seedVec,selectedVec);
01358 size_t i,j;
01359 for(i=0,j=0;i<seedVec.size();++i){
01360 if(seedVec[i]->IsS())
01361 {
01362 seedVec[i]=selectedVec[j];
01363 fixed[seedVec[i]]=true;
01364 ++j;
01365 }
01366 }
01367 }
01368 return iter;
01369 }
01370
01371
01372
01373
01374
01375
01376
01377 static void TopologicalVertexColoring(MeshType &m, std::vector<VertexType *> &seedVec)
01378 {
01379 std::queue<VertexPointer> VQ;
01380
01381 tri::UpdateQuality<MeshType>::VertexConstant(m,0);
01382
01383 for(size_t i=0;i<seedVec.size();++i)
01384 {
01385 VQ.push(seedVec[i]);
01386 seedVec[i]->Q()=i+1;
01387 }
01388
01389 while(!VQ.empty())
01390 {
01391 VertexPointer vp = VQ.front();
01392 VQ.pop();
01393
01394 std::vector<VertexPointer> vertStar;
01395 vcg::face::VVStarVF<FaceType>(vp,vertStar);
01396 for(typename std::vector<VertexPointer>::iterator vv = vertStar.begin();vv!=vertStar.end();++vv)
01397 {
01398 if((*vv)->Q()==0)
01399 {
01400 (*vv)->Q()=vp->Q();
01401 VQ.push(*vv);
01402 }
01403 }
01404 }
01405
01406 }
01407
01408
01409 template <class genericType>
01410 static std::pair<genericType, genericType> ordered_pair(const genericType &a, const genericType &b)
01411 {
01412 if(a<b) return std::make_pair(a,b);
01413 return std::make_pair(b,a);
01414 }
01415
01423 static void GenerateMidPointMap(MeshType &m,
01424 map<std::pair<VertexPointer,VertexPointer>, VertexPointer > &midMap)
01425 {
01426 PerVertexPointerHandle sources = tri::Allocator<MeshType>:: template GetPerVertexAttribute<VertexPointer> (m,"sources");
01427
01428 for(FaceIterator fi = m.face.begin(); fi!=m.face.end(); ++fi)
01429 {
01430 VertexPointer vp[3],sp[3];
01431 vp[0] = (*fi).V(0); vp[1] = (*fi).V(1); vp[2] = (*fi).V(2);
01432 sp[0] = sources[vp[0]]; sp[1] = sources[vp[1]]; sp[2] = sources[vp[2]];
01433 if((sp[0] == sp[1]) && (sp[0] == sp[2])) continue;
01434
01435
01436 for(int i=0;i<3;++i)
01437 {
01438 int i0 = i;
01439 int i1 = (i+1)%3;
01440
01441
01442 VertexPointer closestVert = vp[i0];
01443 if( vp[i1]->Q() < closestVert->Q()) closestVert = vp[i1];
01444
01445 if(sp[i0]->IsS() && sp[i1]->IsS())
01446 {
01447 if ( (vp[i0]->IsS()) && !(vp[i1]->IsS()) ) closestVert = vp[i0];
01448 if (!(vp[i0]->IsS()) && (vp[i1]->IsS()) ) closestVert = vp[i1];
01449 if ( (vp[i0]->IsS()) && (vp[i1]->IsS()) ) closestVert = (vp[i0]->Q() < vp[i1]->Q()) ? vp[i0]:vp[i1];
01450 }
01451
01452 if(midMap[ordered_pair(sp[i0],sp[i1])] == 0 ) {
01453 midMap[ordered_pair(sp[i0],sp[i1])] = closestVert;
01454 }
01455 else {
01456 if(sp[i0]->IsS() && sp[i1]->IsS())
01457 {
01458 if(!(midMap[ordered_pair(sp[i0],sp[i1])]->IsS()) && closestVert->IsS())
01459 midMap[ordered_pair(sp[i0],sp[i1])] = closestVert;
01460 if( midMap[ordered_pair(sp[i0],sp[i1])]->IsS() && closestVert->IsS() &&
01461 closestVert->Q() < midMap[ordered_pair(sp[i0],sp[i1])]->Q())
01462 {
01463 midMap[ordered_pair(sp[i0],sp[i1])] = closestVert;
01464 }
01465 }
01466 else
01467 {
01468 if(closestVert->Q() < midMap[ordered_pair(sp[i0],sp[i1])]->Q())
01469 midMap[ordered_pair(sp[i0],sp[i1])] = closestVert;
01470 }
01471 }
01472 }
01473 }
01474 }
01475
01484
01485 static bool CheckVoronoiTopology(MeshType& m,std::vector<VertexType *> &seedVec)
01486 {
01487 tri::RequirePerVertexAttribute(m,"sources");
01488 tri::RequireCompactness(m);
01489
01490 typename MeshType::template PerVertexAttributeHandle<VertexPointer> sources;
01491 sources = tri::Allocator<MeshType>:: template GetPerVertexAttribute<VertexPointer> (m,"sources");
01492
01493 std::map<VertexPointer, int> seedMap;
01494 BuildSeedMap(m,seedVec,seedMap);
01495
01496
01497 for(int i=0;i<m.vn;++i)
01498 {
01499 VertexPointer vp = sources[i];
01500 int seedInd = seedMap[vp];
01501 if(seedInd <0)
01502 return false;
01503 }
01504
01505 std::vector<MeshType *> regionVec(seedVec.size(),0);
01506 for(size_t i=0; i< seedVec.size();i++) regionVec[i] = new MeshType;
01507
01508 for(int i=0;i<m.fn;++i)
01509 {
01510 int vi0 = seedMap[sources[m.face[i].V(0)]];
01511 int vi1 = seedMap[sources[m.face[i].V(1)]];
01512 int vi2 = seedMap[sources[m.face[i].V(2)]];
01513 assert(vi0>=0 && vi1>=0 && vi2>=0);
01514 tri::Allocator<MeshType>::AddFace(*regionVec[vi0], m.face[i].cP(0),m.face[i].cP(1),m.face[i].cP(2));
01515
01516 if(vi1 != vi0)
01517 tri::Allocator<MeshType>::AddFace(*regionVec[vi1], m.face[i].cP(0),m.face[i].cP(1),m.face[i].cP(2));
01518
01519 if((vi2 != vi0) && (vi2 != vi1) )
01520 tri::Allocator<MeshType>::AddFace(*regionVec[vi2], m.face[i].cP(0),m.face[i].cP(1),m.face[i].cP(2));
01521 }
01522
01523 bool AllDiskRegion=true;
01524 for(size_t i=0; i< seedVec.size();i++)
01525 {
01526 MeshType &rm = *(regionVec[i]);
01527 tri::Clean<MeshType>::RemoveDuplicateVertex(rm);
01528 tri::Allocator<MeshType>::CompactEveryVector(rm);
01529 tri::UpdateTopology<MeshType>::FaceFace(rm);
01530
01531
01532 int NNmanifoldE=tri::Clean<MeshType>::CountNonManifoldEdgeFF(rm);
01533 if (NNmanifoldE!=0)
01534 AllDiskRegion= false;
01535 int G=tri::Clean<MeshType>::MeshGenus(rm);
01536 int numholes=tri::Clean<MeshType>::CountHoles(rm);
01537 if (numholes!=1)
01538 AllDiskRegion= false;
01539 if(G!=0) AllDiskRegion= false;
01540 delete regionVec[i];
01541 }
01542
01543 if(!AllDiskRegion) return false;
01544
01545
01546 MeshType delaMesh;
01547 std::vector<FacePointer> innerCornerVec,
01548 borderCornerVec;
01549 GetFaceCornerVec(m, sources, innerCornerVec, borderCornerVec);
01550
01551
01552 for(size_t i=0;i<seedVec.size();++i)
01553 tri::Allocator<MeshType>::AddVertex(delaMesh, seedVec[i]->P());
01554
01555
01556 for(size_t i=0;i<innerCornerVec.size();++i)
01557 {
01558 VertexPointer v0 = & delaMesh.vert[seedMap[sources[innerCornerVec[i]->V(0)]]];
01559 VertexPointer v1 = & delaMesh.vert[seedMap[sources[innerCornerVec[i]->V(1)]]];
01560 VertexPointer v2 = & delaMesh.vert[seedMap[sources[innerCornerVec[i]->V(2)]]];
01561 tri::Allocator<MeshType>::AddFace(delaMesh,v0,v1,v2);
01562 }
01563 Clean<MeshType>::RemoveUnreferencedVertex(delaMesh);
01564 tri::Allocator<MeshType>::CompactVertexVector(delaMesh);
01565 tri::UpdateTopology<MeshType>::FaceFace(delaMesh);
01566
01567 int nonManif = tri::Clean<MeshType>::CountNonManifoldEdgeFF(delaMesh);
01568 if(nonManif>0) return false;
01569
01570 return true;
01571 }
01572
01573 static void BuildSeedMap(MeshType &m, std::vector<VertexType *> &seedVec, std::map<VertexPointer, int> &seedMap)
01574 {
01575 seedMap.clear();
01576 for(size_t i=0;i<m.vert.size();++i)
01577 seedMap[&(m.vert[i])]=-1;
01578 for(size_t i=0;i<seedVec.size();++i)
01579 seedMap[seedVec[i]]=i;
01580 for(size_t i=0;i<seedVec.size();++i)
01581 assert(tri::Index(m,seedVec[i])>=0 && tri::Index(m,seedVec[i])<size_t(m.vn));
01582 }
01583
01594 static void ConvertDelaunayTriangulationToMesh(MeshType &m,
01595 MeshType &outMesh,
01596 std::vector<VertexType *> &seedVec, bool refineFlag=true)
01597 {
01598 tri::RequirePerVertexAttribute(m,"sources");
01599 tri::RequireCompactness(m);
01600 tri::RequireVFAdjacency(m);
01601
01602 PerVertexPointerHandle sources = tri::Allocator<MeshType>:: template GetPerVertexAttribute<VertexPointer> (m,"sources");
01603
01604 outMesh.Clear();
01605 tri::UpdateTopology<MeshType>::FaceFace(m);
01606 tri::UpdateFlags<MeshType>::FaceBorderFromFF(m);
01607
01608 std::map<VertexPointer, int> seedMap;
01609 BuildSeedMap(m,seedVec,seedMap);
01610
01611 std::vector<FacePointer> innerCornerVec,
01612 borderCornerVec;
01613 GetFaceCornerVec(m, sources, innerCornerVec, borderCornerVec);
01614
01615
01616 for(size_t i=0;i<seedVec.size();++i)
01617 tri::Allocator<MeshType>::AddVertex(outMesh, seedVec[i]->P(),Color4b::White);
01618
01619 map<std::pair<VertexPointer,VertexPointer>, int > midMapInd;
01620
01621
01622 map<std::pair<VertexPointer,VertexPointer>, VertexPointer > midMapPt;
01623 if(refineFlag)
01624 {
01625 GenerateMidPointMap(m, midMapPt);
01626 typename std::map<std::pair<VertexPointer,VertexPointer>, VertexPointer >::iterator mi;
01627 for(mi=midMapPt.begin(); mi!=midMapPt.end(); ++mi)
01628 {
01629 midMapInd[ordered_pair(mi->first.first, mi->first.second)]=outMesh.vert.size();
01630 tri::Allocator<MeshType>::AddVertex(outMesh, mi->second->cP(), Color4b::LightBlue);
01631 }
01632 }
01633
01634
01635 for(size_t i=0;i<innerCornerVec.size();++i)
01636 {
01637 VertexPointer s0 = sources[innerCornerVec[i]->V(0)];
01638 VertexPointer s1 = sources[innerCornerVec[i]->V(1)];
01639 VertexPointer s2 = sources[innerCornerVec[i]->V(2)];
01640 assert ( (s0!=s1) && (s0!=s2) && (s1!=s2) );
01641 VertexPointer v0 = & outMesh.vert[seedMap[s0]];
01642 VertexPointer v1 = & outMesh.vert[seedMap[s1]];
01643 VertexPointer v2 = & outMesh.vert[seedMap[s2]];
01644 if(refineFlag)
01645 {
01646 VertexPointer mp01 = & outMesh.vert[ midMapInd[ordered_pair(s0,s1)]];
01647 VertexPointer mp02 = & outMesh.vert[ midMapInd[ordered_pair(s0,s2)]];
01648 VertexPointer mp12 = & outMesh.vert[ midMapInd[ordered_pair(s1,s2)]];
01649 assert ( (mp01!=mp02) && (mp01!=mp12) && (mp02!=mp12) );
01650 tri::Allocator<MeshType>::AddFace(outMesh,v0,mp01,mp02);
01651 tri::Allocator<MeshType>::AddFace(outMesh,v1,mp12,mp01);
01652 tri::Allocator<MeshType>::AddFace(outMesh,v2,mp02,mp12);
01653 tri::Allocator<MeshType>::AddFace(outMesh,mp01,mp12,mp02);
01654 }
01655 else
01656 tri::Allocator<MeshType>::AddFace(outMesh,v0,v1,v2);
01657 }
01658 Clean<MeshType>::RemoveUnreferencedVertex(outMesh);
01659 tri::Allocator<MeshType>::CompactVertexVector(outMesh);
01660 }
01661
01662 template <class MidPointType >
01663 static void PreprocessForVoronoi(MeshType &m, ScalarType radius,
01664 MidPointType mid,
01665 VoronoiProcessingParameter &vpp)
01666 {
01667 const int maxSubDiv = 10;
01668 tri::RequireFFAdjacency(m);
01669 tri::UpdateTopology<MeshType>::FaceFace(m);
01670 tri::Clean<MeshType>::RemoveUnreferencedVertex(m);
01671 ScalarType edgeLen = tri::Stat<MeshType>::ComputeFaceEdgeLengthAverage(m);
01672
01673 for(int i=0;i<maxSubDiv;++i)
01674 {
01675 bool ret = tri::Refine<MeshType, MidPointType >(m,mid,min(edgeLen*2.0f,radius/vpp.refinementRatio));
01676 if(!ret) break;
01677 }
01678 tri::Allocator<MeshType>::CompactEveryVector(m);
01679 tri::UpdateTopology<MeshType>::VertexFace(m);
01680 }
01681
01682 static void PreprocessForVoronoi(MeshType &m, float radius, VoronoiProcessingParameter &vpp)
01683 {
01684 tri::MidPoint<MeshType> mid(&m);
01685 PreprocessForVoronoi<tri::MidPoint<MeshType> >(m, radius,mid,vpp);
01686 }
01687
01688 static void RelaxRefineTriangulationSpring(MeshType &m, MeshType &delaMesh, int relaxStep=10, int refineStep=3 )
01689 {
01690 tri::RequireCompactness(m);
01691 tri::RequireCompactness(delaMesh);
01692 tri::RequireVFAdjacency(delaMesh);
01693 tri::RequireFFAdjacency(delaMesh);
01694 tri::RequirePerFaceMark(delaMesh);
01695
01696 const float convergenceThr = 0.001f;
01697 const float eulerStep = 0.1f;
01698
01699 tri::UpdateNormal<MeshType>::PerVertexNormalizedPerFaceNormalized(m);
01700
01701 typedef GridStaticPtr<FaceType, ScalarType> TriMeshGrid;
01702 TriMeshGrid ug;
01703 ug.Set(m.face.begin(),m.face.end());
01704
01705 typedef typename vcg::SpatialHashTable<VertexType, ScalarType> HashVertexGrid;
01706 HashVertexGrid HG;
01707 HG.Set(m.vert.begin(),m.vert.end());
01708
01709 PerVertexBoolHandle fixed = tri::Allocator<MeshType>:: template GetPerVertexAttribute<bool> (m,"fixed");
01710
01711 const ScalarType maxDist = m.bbox.Diag()/4.f;
01712 for(int kk=0;kk<refineStep+1;kk++)
01713 {
01714 tri::UpdateTopology<MeshType>::FaceFace(delaMesh);
01715
01716 if(kk!=0)
01717 {
01718 int nonManif = tri::Clean<MeshType>::CountNonManifoldEdgeFF(delaMesh);
01719 if(nonManif) return;
01720 tri::Refine<MeshType, tri::MidPoint<MeshType> >(delaMesh,tri::MidPoint<MeshType>(&delaMesh));
01721 }
01722 tri::UpdateTopology<MeshType>::VertexFace(delaMesh);
01723 const float dist_upper_bound=m.bbox.Diag()/10.0;
01724 float dist;
01725
01726 for(int k=0;k<relaxStep;k++)
01727 {
01728 std::vector<Point3f> avgForce(delaMesh.vn);
01729 std::vector<float> avgLenVec(delaMesh.vn,0);
01730 for(int i=0;i<delaMesh.vn;++i)
01731 {
01732 vector<VertexPointer> starVec;
01733 face::VVStarVF<FaceType>(&delaMesh.vert[i],starVec);
01734
01735 for(size_t j=0;j<starVec.size();++j)
01736 avgLenVec[i] +=Distance(delaMesh.vert[i].cP(),starVec[j]->cP());
01737 avgLenVec[i] /= float(starVec.size());
01738
01739 avgForce[i] =Point3f(0,0,0);
01740 for(size_t j=0;j<starVec.size();++j)
01741 {
01742 Point3f force = delaMesh.vert[i].cP()-starVec[j]->cP();
01743 float len = force.Norm();
01744 force.Normalize();
01745 avgForce[i] += force * (avgLenVec[i]-len);
01746 }
01747 }
01748 bool changed=false;
01749 for(int i=0;i<delaMesh.vn;++i)
01750 {
01751 VertexPointer vp = tri::GetClosestVertex<MeshType,HashVertexGrid>(m, HG, delaMesh.vert[i].P(), dist_upper_bound, dist);
01752 if(!fixed[vp] && !(vp->IsS()))
01753 {
01754 delaMesh.vert[i].P() += (avgForce[i]*eulerStep);
01755 CoordType closest;
01756 float dist;
01757 tri::GetClosestFaceBase(m,ug,delaMesh.vert[i].cP(), maxDist,dist,closest);
01758 assert(dist!=maxDist);
01759 if(Distance(closest,delaMesh.vert[i].P()) > avgLenVec[i]*convergenceThr) changed = true;
01760 delaMesh.vert[i].P()=closest;
01761 }
01762 }
01763
01764 if(!changed) k=relaxStep;
01765 }
01766 }
01767 }
01768
01769 static void RelaxRefineTriangulationLaplacian(MeshType &m, MeshType &delaMesh, int refineStep=3, int relaxStep=10 )
01770 {
01771 tri::RequireCompactness(m);
01772 tri::RequireCompactness(delaMesh);
01773 tri::RequireFFAdjacency(delaMesh);
01774 tri::RequirePerFaceMark(delaMesh);
01775 tri::UpdateTopology<MeshType>::FaceFace(delaMesh);
01776
01777 typedef GridStaticPtr<FaceType, ScalarType> TriMeshGrid;
01778 TriMeshGrid ug;
01779 ug.Set(m.face.begin(),m.face.end());
01780 const ScalarType maxDist = m.bbox.Diag()/4.f;
01781
01782 int origVertNum = delaMesh.vn;
01783
01784 for(int k=0;k<refineStep;++k)
01785 {
01786 tri::UpdateSelection<MeshType>::VertexClear(delaMesh);
01787
01788 tri::Refine<MeshType, tri::MidPoint<MeshType> >(delaMesh,tri::MidPoint<MeshType>(&delaMesh));
01789
01790 for(int j=0;j<relaxStep;++j)
01791 {
01792
01793 for(int i=origVertNum;i<delaMesh.vn;++i)
01794 {
01795 float dist;
01796 delaMesh.vert[i].SetS();
01797 CoordType closest;
01798 tri::GetClosestFaceBase(m,ug,delaMesh.vert[i].cP(), maxDist,dist,closest);
01799 assert(dist!=maxDist);
01800 delaMesh.vert[i].P()= (delaMesh.vert[i].P()+closest)/2.0f;
01801 }
01802 tri::Smooth<MeshType>::VertexCoordLaplacianBlend(delaMesh,1,0.2f,true);
01803 }
01804 }
01805 for(int i=origVertNum;i<delaMesh.vn;++i) delaMesh.vert[i].C()=Color4b::LightBlue;
01806 }
01807 };
01808
01809 }
01810 }
01811 #endif