00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #ifndef __VORONOI_VOLUME_SAMPLING_H
00024 #define __VORONOI_VOLUME_SAMPLING_H
00025 #include <vcg/complex/algorithms/voronoi_processing.h>
00026 #include <vcg/complex/algorithms/create/marching_cubes.h>
00027 #include <vcg/complex/algorithms/create/mc_trivial_walker.h>
00028 #include <vcg/complex/algorithms/point_sampling.h>
00029
00030
00031 namespace vcg
00032 {
00033 namespace tri
00034 {
00035
00036 template< class MeshType>
00037 class VoronoiVolumeSampling
00038 {
00039 public:
00040 typedef typename tri::VoronoiProcessing<MeshType>::QuadricSumDistance QuadricSumDistance;
00041 typedef typename MeshType::ScalarType ScalarType;
00042 typedef typename MeshType::BoxType BoxType;
00043 typedef typename MeshType::VertexIterator VertexIterator;
00044 typedef typename MeshType::VertexPointer VertexPointer;
00045 typedef typename MeshType::CoordType CoordType;
00046 typedef typename MeshType::FacePointer FacePointer;
00047 typedef typename vcg::GridStaticPtr<typename MeshType::FaceType, ScalarType> GridType;
00048
00049 typedef SimpleVolume<SimpleVoxel<ScalarType> > VVSVolume;
00050 typedef typename vcg::tri::TrivialWalker<MeshType,VVSVolume> VVSWalker;
00051 typedef typename vcg::tri::MarchingCubes<MeshType, VVSWalker> VVSMarchingCubes;
00052
00053 class Param
00054 {
00055 public:
00056 Param()
00057 {
00058 elemType=1;
00059 isoThr=0.1;
00060 surfFlag=false;
00061 voxelSide=0;
00062 }
00063
00064 int elemType;
00065 ScalarType isoThr;
00066 ScalarType voxelSide;
00067 bool surfFlag;
00068 };
00069
00070 VoronoiVolumeSampling(MeshType &_baseMesh)
00071 :surfTree(0),seedTree(0),baseMesh(_baseMesh),cb(0),restrictedRelaxationFlag(false)
00072 {
00073 tri::RequirePerFaceMark(baseMesh);
00074 tri::UpdateBounding<MeshType>::Box(baseMesh);
00075 tri::UpdateNormal<MeshType>::PerFaceNormalized(baseMesh);
00076 }
00077
00078 KdTree<ScalarType> *surfTree;
00079 KdTree<ScalarType> *seedTree;
00080 KdTree<ScalarType> *seedDomainTree;
00081
00082 typename KdTree<ScalarType>::PriorityQueue pq;
00083 GridType surfGrid;
00084 typedef FaceTmark<MeshType> MarkerFace;
00085 MarkerFace mf;
00086 vcg::face::PointDistanceBaseFunctor<ScalarType> PDistFunct;
00087
00088 MeshType &baseMesh;
00089 MeshType seedMesh;
00090 MeshType poissonSurfaceMesh;
00091 ScalarType poissonRadiusSurface;
00092 MeshType montecarloVolumeMesh;
00093 MeshType seedDomainMesh;
00094 vcg::CallBackPos *cb;
00095 math::MarsenneTwisterRNG rng;
00096 bool restrictedRelaxationFlag;
00097
00098
00099
00100
00101
00102
00103 void Init(ScalarType _poissonRadiusSurface=0)
00104 {
00105 MeshType montecarloSurfaceMesh;
00106
00107 if(_poissonRadiusSurface==0) poissonRadiusSurface = baseMesh.bbox.Diag()/50.0f;
00108 else poissonRadiusSurface = _poissonRadiusSurface;
00109 ScalarType meshArea = Stat<MeshType>::ComputeMeshArea(baseMesh);
00110 int MontecarloSurfSampleNum = 10 * meshArea / (poissonRadiusSurface*poissonRadiusSurface);
00111 tri::MeshSampler<MeshType> sampler(montecarloSurfaceMesh);
00112 tri::SurfaceSampling<MeshType,tri::MeshSampler<MeshType> >::SamplingRandomGenerator()=rng;
00113 tri::SurfaceSampling<MeshType,tri::MeshSampler<MeshType> >::Montecarlo(baseMesh, sampler, MontecarloSurfSampleNum);
00114 montecarloSurfaceMesh.bbox = baseMesh.bbox;
00115 poissonSurfaceMesh.Clear();
00116 tri::MeshSampler<MeshType> mps(poissonSurfaceMesh);
00117 typename tri::SurfaceSampling<MeshType,tri::MeshSampler<MeshType> >::PoissonDiskParam pp;
00118 pp.geodesicDistanceFlag=false;
00119
00120 tri::SurfaceSampling<MeshType,tri::MeshSampler<MeshType> >::PoissonDiskPruning(mps, montecarloSurfaceMesh, poissonRadiusSurface,pp);
00121 vcg::tri::UpdateBounding<MeshType>::Box(poissonSurfaceMesh);
00122
00123 printf("Surface Sampling radius %f - montecarlo %ivn - Poisson %ivn\n",poissonRadiusSurface,montecarloSurfaceMesh.vn,poissonSurfaceMesh.vn);
00124 VertexConstDataWrapper<MeshType> ww(poissonSurfaceMesh);
00125 if(surfTree) delete surfTree;
00126 surfTree = new KdTree<ScalarType>(ww);
00127
00128 surfGrid.SetWithRadius(baseMesh.face.begin(),baseMesh.face.end(),poissonRadiusSurface);
00129 mf.SetMesh(&baseMesh);
00130 }
00131
00132
00133
00134
00135 ScalarType DistanceFromSurface(const CoordType &q, CoordType &closestP)
00136 {
00137 ScalarType squaredDist;
00138 unsigned int ind;
00139 surfTree->doQueryClosest(q,ind,squaredDist);
00140 ScalarType dist = sqrt(squaredDist);
00141 if( dist > 3.0f*poissonRadiusSurface)
00142 {
00143
00144 CoordType dir = this->poissonSurfaceMesh.vert[ind].P() - q;
00145 const CoordType &surfN = this->poissonSurfaceMesh.vert[ind].N();
00146 if(dir* surfN > 0) dist= -dist;
00147 closestP=this->poissonSurfaceMesh.vert[ind].P();
00148 return dist;
00149 }
00150
00151 ScalarType _maxDist = this->poissonRadiusSurface*3.0f;
00152 dist=_maxDist;
00153 FacePointer f=surfGrid.GetClosest(PDistFunct,mf,q,_maxDist,dist,closestP);
00154 assert(f);
00155 assert (dist >=0);
00156 CoordType dir = closestP - q;
00157 if(dir*f->cN() > 0) dist = -dist;
00158
00159 return dist;
00160 }
00161
00162
00163 ScalarType DistanceFromVoronoiSeed(const CoordType &p_point)
00164 {
00165 ScalarType squaredDist;
00166 unsigned int ind;
00167 seedTree->doQueryClosest(p_point,ind,squaredDist);
00168 return math::Sqrt(squaredDist);
00169 }
00170
00171 ScalarType DistanceFromVoronoiFace(const CoordType &p_point)
00172 {
00173
00174 seedTree->doQueryK(p_point,2,pq);
00175
00176 std::vector<std::pair<ScalarType, CoordType> > closeSeedVec;
00177 CoordType p0= this->seedMesh.vert[pq.getIndex(0)].P();
00178 CoordType p1= this->seedMesh.vert[pq.getIndex(1)].P();
00179 Plane3<ScalarType> pl; pl.Init((p0+p1)/2.0f,p0-p1);
00180 return fabs(SignedDistancePlanePoint(pl,p_point));
00181 }
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196 ScalarType DistanceFromVoronoiInternalEdge(const CoordType &p_point)
00197 {
00198 seedTree->doQueryK(p_point,3,pq);
00199 std::vector<std::pair<ScalarType, CoordType> > closeSeedVec;
00200 CoordType p0= this->seedMesh.vert[pq.getIndex(0)].P();
00201 CoordType p1= this->seedMesh.vert[pq.getIndex(1)].P();
00202 CoordType p2= this->seedMesh.vert[pq.getIndex(2)].P();
00203
00204 Plane3<ScalarType> pl01; pl01.Init((p0+p1)/2.0f,p0-p1);
00205 Plane3<ScalarType> pl02; pl02.Init((p0+p2)/2.0f,p0-p2);
00206 Line3<ScalarType> voroLine;
00207
00208
00209 vcg::IntersectionPlanePlane(pl01,pl02,voroLine);
00210
00211 CoordType closestPt;
00212 ScalarType closestDist;
00213 vcg::LinePointDistance(voroLine,p_point,closestPt, closestDist);
00214
00215 return closestDist;
00216 }
00217
00218 ScalarType DistanceFromVoronoiSurfaceEdge(const CoordType &p_point, const CoordType &surfPt)
00219 {
00220 seedTree->doQueryK(p_point,3,pq);
00221 pq.sort();
00222 assert(pq.getWeight(0) <= pq.getWeight(1));
00223
00224 CoordType p0= this->seedMesh.vert[pq.getIndex(0)].P();
00225 CoordType p1= this->seedMesh.vert[pq.getIndex(1)].P();
00226 CoordType p2= this->seedMesh.vert[pq.getIndex(2)].P();
00227
00228 Plane3<ScalarType> pl01; pl01.Init((p0+p1)/2.0f,p0-p1);
00229 Plane3<ScalarType> pl02; pl02.Init((p0+p2)/2.0f,p0-p2);
00230 Plane3<ScalarType> pl12; pl12.Init((p1+p2)/2.0f,p1-p2);
00231 Line3<ScalarType> voroLine;
00232
00233
00234
00235 vcg::IntersectionPlanePlane(pl01,pl02,voroLine);
00236
00237 CoordType closestPt;
00238 ScalarType voroLineDist;
00239 vcg::LinePointDistance(voroLine,p_point,closestPt, voroLineDist);
00240
00241 Plane3<ScalarType> plSurf; plSurf.Init(surfPt, surfPt - p_point);
00242 Line3<ScalarType> surfLine;
00243
00244
00245 ScalarType surfLineDist;
00246 vcg::IntersectionPlanePlane(pl01,plSurf,surfLine);
00247 vcg::LinePointDistance(surfLine,p_point,closestPt, surfLineDist);
00248
00249 return min(voroLineDist,surfLineDist);
00250 }
00251
00252
00253 ScalarType DistanceFromVoronoiCorner(const CoordType &p_point)
00254 {
00255 seedTree->doQueryK(p_point,4,pq);
00256 std::vector<std::pair<ScalarType, CoordType> > closeSeedVec;
00257 CoordType p0= this->seedMesh.vert[pq.getIndex(0)].P();
00258 CoordType p1= this->seedMesh.vert[pq.getIndex(1)].P();
00259 CoordType p2= this->seedMesh.vert[pq.getIndex(2)].P();
00260 CoordType p3= this->seedMesh.vert[pq.getIndex(3)].P();
00261
00262 Plane3<ScalarType> pl01; pl01.Init((p0+p1)/2.0f,p0-p1);
00263 Plane3<ScalarType> pl02; pl02.Init((p0+p2)/2.0f,p0-p2);
00264 Plane3<ScalarType> pl03; pl03.Init((p0+p3)/2.0f,p0-p3);
00265 Line3<ScalarType> voroLine;
00266
00267
00268 vcg::IntersectionPlanePlane(pl01,pl02,voroLine);
00269 CoordType intersectionPt;
00270 vcg::IntersectionLinePlane(voroLine,pl03,intersectionPt);
00271
00272 return vcg::Distance(p_point,intersectionPt);
00273 }
00274
00275
00276 void BarycentricRelaxVoronoiSamples(int relaxStep)
00277 {
00278 bool changed=false;
00279 assert(montecarloVolumeMesh.vn > seedMesh.vn*20);
00280 int i;
00281 for(i=0;i<relaxStep;++i)
00282 {
00283
00284 std::vector<std::pair<int,CoordType> > sumVec(seedMesh.vn,std::make_pair(0,CoordType(0,0,0)));
00285
00286
00287 for(typename MeshType::VertexIterator vi=montecarloVolumeMesh.vert.begin();vi!=montecarloVolumeMesh.vert.end();++vi)
00288 {
00289 unsigned int seedInd;
00290 ScalarType sqdist;
00291 seedTree->doQueryClosest(vi->P(),seedInd,sqdist);
00292 sumVec[seedInd].first++;
00293 sumVec[seedInd].second+=vi->cP();
00294 }
00295
00296 changed=false;
00297 for(size_t i=0;i<seedMesh.vert.size();++i)
00298 {
00299 if(sumVec[i].first == 0) tri::Allocator<MeshType>::DeleteVertex(seedMesh,seedMesh.vert[i]);
00300 else
00301 {
00302 CoordType prevP = seedMesh.vert[i].P();
00303 seedMesh.vert[i].P() = sumVec[i].second /ScalarType(sumVec[i].first);
00304 seedMesh.vert[i].Q() = sumVec[i].first;
00305 if(restrictedRelaxationFlag)
00306 {
00307 unsigned int seedInd;
00308 ScalarType sqdist;
00309 seedDomainTree->doQueryClosest(seedMesh.vert[i].P(),seedInd,sqdist);
00310 seedMesh.vert[i].P() = seedDomainMesh.vert[seedInd].P();
00311 }
00312 if(prevP != seedMesh.vert[i].P()) changed = true;
00313 }
00314 }
00315 tri::Allocator<MeshType>::CompactVertexVector(seedMesh);
00316
00317
00318 VertexConstDataWrapper<MeshType> vdw(seedMesh);
00319 delete seedTree;
00320 seedTree = new KdTree<ScalarType>(vdw);
00321 if(!changed)
00322 break;
00323 }
00324
00325 }
00326
00327
00328 void QuadricRelaxVoronoiSamples(int relaxStep)
00329 {
00330 bool changed=false;
00331 assert(montecarloVolumeMesh.vn > seedMesh.vn*20);
00332 int i;
00333 for(i=0;i<relaxStep;++i)
00334 {
00335 QuadricSumDistance dz;
00336 std::vector<QuadricSumDistance> dVec(montecarloVolumeMesh.vert.size(),dz);
00337 tri::UpdateQuality<MeshType>::VertexConstant(seedMesh,0);
00338
00339
00340
00341
00342 for(typename MeshType::VertexIterator vi=montecarloVolumeMesh.vert.begin();vi!=montecarloVolumeMesh.vert.end();++vi)
00343 {
00344 unsigned int seedInd;
00345 ScalarType sqdist;
00346 seedTree->doQueryClosest(vi->P(),seedInd,sqdist);
00347 dVec[seedInd].AddPoint(vi->P());
00348 seedMesh.vert[seedInd].Q() +=1;
00349 }
00350
00351
00352
00353 std::vector< std::pair<ScalarType,int> > seedMinimaVec(seedMesh.vert.size(),std::make_pair(std::numeric_limits<ScalarType>::max(),-1 ));
00354 for(typename MeshType::VertexIterator vi=seedDomainMesh.vert.begin();vi!=seedDomainMesh.vert.end();++vi)
00355 {
00356 unsigned int seedInd;
00357 ScalarType sqdist;
00358 seedTree->doQueryClosest(vi->P(),seedInd,sqdist);
00359
00360 ScalarType val = dVec[seedInd].Eval(vi->P());
00361 if(val < seedMinimaVec[seedInd].first)
00362 {
00363 seedMinimaVec[seedInd].first = val;
00364 seedMinimaVec[seedInd].second = tri::Index(seedDomainMesh,*vi);
00365 }
00366 }
00367 changed=false;
00368 for(int i=0;i<seedMesh.vert.size();++i)
00369 {
00370 CoordType prevP = seedMesh.vert[i].P() ;
00371 if(seedMinimaVec[i].second == -1) tri::Allocator<MeshType>::DeleteVertex(seedMesh,seedMesh.vert[i]);
00372 seedMesh.vert[i].P() = seedDomainMesh.vert[seedMinimaVec[i].second].P();
00373 if(prevP != seedMesh.vert[i].P()) changed = true;
00374 }
00375 tri::Allocator<MeshType>::CompactVertexVector(seedMesh);
00376
00377
00378 VertexConstDataWrapper<MeshType> vdw(seedMesh);
00379 delete seedTree;
00380 seedTree = new KdTree<ScalarType>(vdw);
00381 if(!changed)
00382 break;
00383 }
00384
00385 }
00386
00387
00388 ScalarType ImplicitFunction(const CoordType &p, Param &pp)
00389 {
00390 CoordType closest;
00391 ScalarType surfDist = this->DistanceFromSurface(p,closest);
00392
00393 ScalarType elemDist;
00394 switch(pp.elemType)
00395 {
00396 case 0: elemDist = DistanceFromVoronoiSeed(p) - pp.isoThr; break;
00397 case 1: elemDist = DistanceFromVoronoiSurfaceEdge(p,closest) - pp.isoThr; break;
00398 case 2: elemDist = DistanceFromVoronoiFace(p) - pp.isoThr; break;
00399 case 3: elemDist = DistanceFromVoronoiCorner(p) - pp.isoThr; break;
00400 case 4: elemDist = DistanceFromVoronoiInternalEdge(p) - pp.isoThr; break;
00401 default: assert(0);
00402 }
00403 ScalarType val;
00404 if(pp.surfFlag)
00405 val = std::max(-elemDist,surfDist);
00406 else
00407 val = std::max(elemDist,surfDist);
00408
00409 return val;
00410 }
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424 void BuildScaffoldingMesh(MeshType &scaffoldingMesh, Param &pp)
00425 {
00426 VVSVolume volume;
00427 int sizeX = (baseMesh.bbox.DimX() / pp.voxelSide)+1;
00428 int sizeY = (baseMesh.bbox.DimY() / pp.voxelSide)+1;
00429 int sizeZ = (baseMesh.bbox.DimZ() / pp.voxelSide)+1;
00430
00431 int t0=clock();
00432 BoxType bb = BoxType::Construct(baseMesh.bbox);
00433 bb.Offset(pp.voxelSide+pp.isoThr*2.0f);
00434 volume.Init(Point3i(sizeX,sizeY,sizeZ),bb);
00435 int cnt=0;
00436 for(ScalarType i=0;i<sizeX;i++)
00437 for(ScalarType j=0;j<sizeY;j++)
00438 for(ScalarType k=0;k<sizeZ;k++)
00439 {
00440 CoordType p;
00441 volume.IPiToPf(Point3i(i,j,k),p);
00442 volume.Val(i,j,k) = ImplicitFunction(p,pp);
00443 cnt++;
00444 }
00445 int t1=clock();
00446 VVSWalker walker;
00447 VVSMarchingCubes mc(scaffoldingMesh, walker);
00448 walker.template BuildMesh <VVSMarchingCubes>(scaffoldingMesh, volume, mc,0);
00449 int t2=clock();
00450 printf("Fill Volume (%3i %3i %3i) %5.2f\n", sizeX,sizeY,sizeZ,float(t1-t0)/CLOCKS_PER_SEC);
00451 printf("Marching %i tris %5.2f\n", scaffoldingMesh.fn,float(t2-t1)/CLOCKS_PER_SEC);
00452 }
00461 void ThicknessEvaluator(float distThr, int smoothSize, int smoothIter, MeshType *skelM=0)
00462 {
00463 tri::UpdateQuality<MeshType>::VertexConstant(poissonSurfaceMesh,0);
00464 std::vector<VertexPointer> medialSrc(poissonSurfaceMesh.vert.size(),0);
00465 for(VertexIterator vi=montecarloVolumeMesh.vert.begin(); vi!=montecarloVolumeMesh.vert.end(); ++vi)
00466 {
00467 unsigned int ind;
00468 ScalarType sqdist;
00469 this->surfTree->doQueryClosest(vi->P(),ind,sqdist);
00470 VertexPointer vp = &poissonSurfaceMesh.vert[ind];
00471 ScalarType minDist = math::Sqrt(sqdist);
00472 if(vp->Q() < minDist)
00473 {
00474 std::vector<unsigned int> indVec;
00475 std::vector<ScalarType> sqDistVec;
00476
00477 this->surfTree->doQueryDist( vi->P(), minDist*distThr,indVec,sqDistVec);
00478 if(indVec.size()>1)
00479 {
00480 for(size_t i=0;i<indVec.size();++i)
00481 {
00482 VertexPointer vp = &poissonSurfaceMesh.vert[indVec[i]];
00483
00484 if(vp->Q() < minDist) {
00485 vp->Q()=minDist;
00486 medialSrc[indVec[i]]=&*vi;
00487 }
00488 }
00489 }
00490 }
00491 }
00492
00493 if(skelM)
00494 {
00495 tri::UpdateFlags<MeshType>::VertexClearV(montecarloVolumeMesh);
00496 for(size_t i=0;i<medialSrc.size();++i)
00497 medialSrc[i]->SetV();
00498 for(VertexIterator vi=montecarloVolumeMesh.vert.begin(); vi!=montecarloVolumeMesh.vert.end(); ++vi)
00499 if(vi->IsV()) tri::Allocator<MeshType>::AddVertex(*skelM,vi->P());
00500 printf("Generated a medial surf of %i vertexes\n",skelM->vn);
00501 }
00502
00503
00504 tri::Smooth<MeshType>::PointCloudQualityMedian(poissonSurfaceMesh);
00505 tri::Smooth<MeshType>::PointCloudQualityAverage(poissonSurfaceMesh,smoothSize,smoothIter);
00506 tri::UpdateColor<MeshType>::PerVertexQualityRamp(poissonSurfaceMesh);
00507 tri::RedetailSampler<MeshType> rs;
00508 rs.init(&poissonSurfaceMesh);
00509 rs.dist_upper_bound = poissonSurfaceMesh.bbox.Diag()*0.05 ;
00510 rs.qualityFlag = true;
00511 tri::SurfaceSampling<MeshType, RedetailSampler<MeshType> >::VertexUniform(baseMesh, rs, baseMesh.vn, false);
00512 }
00513
00514 void RefineSkeletonVolume(MeshType &skelMesh)
00515 {
00516 CoordType closestP;
00517 int trialNum=0;
00518 for(int i=0;i<skelMesh.vn;++i)
00519 {
00520 CoordType point = math::GeneratePointInBox3Uniform(rng,baseMesh.bbox);
00521 trialNum++;
00522 ScalarType d = this->DistanceFromSurface(point, closestP);
00523 if(d<0){
00524 vcg::tri::Allocator<MeshType>::AddVertex(montecarloVolumeMesh,point);
00525 montecarloVolumeMesh.vert.back().Q() = fabs(d);
00526 }
00527 }
00528 }
00529
00530
00531 void BuildMontecarloSampling(int montecarloSampleNum)
00532 {
00533 montecarloVolumeMesh.Clear();
00534
00535 int trialNum=0;
00536 CoordType closest;
00537 while(montecarloVolumeMesh.vn < montecarloSampleNum)
00538 {
00539 CoordType point = math::GeneratePointInBox3Uniform(rng,baseMesh.bbox);
00540 trialNum++;
00541 ScalarType d = this->DistanceFromSurface(point,closest);
00542 if(d<0){
00543 vcg::tri::Allocator<MeshType>::AddVertex(montecarloVolumeMesh,point);
00544 montecarloVolumeMesh.vert.back().Q() = fabs(d);
00545 }
00546 if(cb && (montecarloVolumeMesh.vn%1000)==0)
00547 cb((100*montecarloVolumeMesh.vn)/montecarloSampleNum,"Montecarlo Sampling...");
00548 }
00549 printf("Made %i Trials to get %i samples\n",trialNum,montecarloSampleNum);
00550 tri::UpdateBounding<MeshType>::Box(montecarloVolumeMesh);
00551 }
00552
00553
00554
00555
00556
00557
00558
00559 void BuildVolumeSampling(int montecarloSampleNum, int poissonSampleNum, ScalarType &poissonRadius, int randSeed)
00560 {
00561 if(montecarloSampleNum >0)
00562 this->BuildMontecarloSampling(montecarloSampleNum);
00563 if(seedDomainMesh.vn == 0)
00564 tri::Append<MeshType,MeshType>::MeshCopy(seedDomainMesh,montecarloVolumeMesh);
00565
00566 vector<VertexPointer> pruningVec;
00567 if(poissonRadius ==0 && poissonSampleNum!=0)
00568 tri::PoissonPruningExact(seedDomainMesh,pruningVec,poissonRadius,poissonSampleNum,0.04,10,randSeed);
00569 else
00570 tri::PoissonPruning(seedDomainMesh,pruningVec,poissonRadius,randSeed);
00571
00572 std::vector<CoordType> seedPts(pruningVec.size());
00573 for(size_t i=0;i<pruningVec.size();++i)
00574 seedPts[i]=pruningVec[i]->P();
00575 tri::BuildMeshFromCoordVector(this->seedMesh,seedPts);
00576
00577 VertexConstDataWrapper<MeshType> vdw(seedMesh);
00578 if(seedTree) delete seedTree;
00579 seedTree = new KdTree<ScalarType>(vdw);
00580
00581 VertexConstDataWrapper<MeshType> vdw2(seedDomainMesh);
00582 if(seedDomainTree) delete seedTree;
00583 seedDomainTree = new KdTree<ScalarType>(vdw);
00584 }
00585
00586 };
00587
00588
00589 }
00590 }
00591 #endif // VORONOI_VOLUME_SAMPLING_H