voronoi_volume_sampling.h
Go to the documentation of this file.
00001 /****************************************************************************
00002 * MeshLab                                                           o o     *
00003 * A versatile mesh processing toolbox                             o     o   *
00004 *                                                                _   O  _   *
00005 * Copyright(C) 2005                                                \/)\/    *
00006 * Visual Computing Lab                                            /\/|      *
00007 * ISTI - Italian National Research Council                           |      *
00008 *                                                                    \      *
00009 * All rights reserved.                                                      *
00010 *                                                                           *
00011 * This program is free software; you can redistribute it and/or modify      *
00012 * it under the terms of the GNU General Public License as published by      *
00013 * the Free Software Foundation; either version 2 of the License, or         *
00014 * (at your option) any later version.                                       *
00015 *                                                                           *
00016 * This program is distributed in the hope that it will be useful,           *
00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of            *
00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
00019 * GNU General Public License (http://www.gnu.org/licenses/gpl.txt)          *
00020 * for more details.                                                         *
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; // the type of element
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; // used for fast inside query 
00079   KdTree<ScalarType>  *seedTree; // used to accumulate barycenter in relaxation
00080   KdTree<ScalarType>  *seedDomainTree; // used to accumulate barycenter in relaxation
00081   
00082   typename KdTree<ScalarType>::PriorityQueue pq;
00083   GridType surfGrid; // used for fast inside query
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; // we use this mesh as volume evaluator
00093   MeshType seedDomainMesh;       // where we choose the seeds (by default is the montecarlo volume mesh)
00094   vcg::CallBackPos *cb;
00095   math::MarsenneTwisterRNG rng;
00096   bool restrictedRelaxationFlag;
00097 
00098   
00099   // Build up the needed structure for efficient point in mesh search. 
00100   // It uses a poisson disk sampling of the surface plus a
00101   // kdtree to speed up query point closest on surface for points far from surface. 
00102   // It initializes the surfGrid, surfTree and poissonSurfaceMesh members   
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; // we want the same bounding box
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   // Compute the signed distance from the surface exploting both a kdtree and a ugrid 
00133   // for a query point p first we use the kdtree with a good poisson sampling of the surface;
00134   // to get the nearest point on the surface, then if the point is far from the surface we can use the point point distance, while if it is near (e.g. less than 3*poisson radius) we rely on point face distance with a grid.
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 //    CoordType dir = surfTree->getNeighbor(0) - p;
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  * Function: scaffolding
00185  * ----------------------------
00186  * calculates the distance between the point P and the line R
00187  * (intersection of the plane P01 P02)
00188  *
00189  *   p_point: point to calculate
00190  *   p_tree: KdTree of the mesh of point
00191  *   p_m: Mesh of points ( surface and inside )
00192  *
00193  *   returns: distance between the point P and the line R
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     // Calculating the line R that intersect the planes pl01 and pl02
00209     vcg::IntersectionPlanePlane(pl01,pl02,voroLine);
00210     // Calculating the distance k between the point p_point and the line R.
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     // Calculating the line R that intersect the planes pl01 and pl02
00235     vcg::IntersectionPlanePlane(pl01,pl02,voroLine);
00236     // Calculating the distance k between the point p_point and the line R.
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     // Calculating the line R that intersect the planes pl01 and pl02
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     // Calculating the line R that intersect the planes pl01 and pl02
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     // First accumulate for each seed the coord of all the samples that are closest to him.
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     // Kdtree for the seeds must be rebuilt at the end of each step;
00318     VertexConstDataWrapper<MeshType> vdw(seedMesh);
00319     delete seedTree;
00320     seedTree = new KdTree<ScalarType>(vdw);
00321     if(!changed)
00322       break;
00323   }
00324 //  qDebug("performed %i relax step on %i",i,relaxStep);
00325 }
00326 
00327 // Given a volumetric sampling of the mesh, and a set of seeds
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     // Each voronoi region has a quadric representing the sum of the squared distances of all the points of its region.
00340     // First Loop:
00341     // For each point of the volume add its distance to the quadric of its region.
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     // Second Loop:  for each region we search in the seed domain the point that has minimal squared distance from all other points in that region.
00352     // We do that evaluating the quadric in each point
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     // Kdtree for the seeds must be rebuilt at the end of each step;
00378     VertexConstDataWrapper<MeshType> vdw(seedMesh);
00379     delete seedTree;
00380     seedTree = new KdTree<ScalarType>(vdw);
00381     if(!changed)
00382       break;
00383   }
00384 //  qDebug("performed %i relax step on %i",i,relaxStep);
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  * Function: BuildScaffoldingMesh
00414  * ----------------------------
00415  * Build a mesh that is the scaffolding of the original mesh.
00416  * uses an implicit function and a voronoi3d diagram consisting of the set of inside and
00417  * surface points of the original mesh m
00418  *
00419  *   m: original mesh
00420  *   surVertex: mesh of surface points
00421  *   PruningPoisson: mesh of inside and surface points, it's the voronoi3d diagram
00422  *   n_voxel: number of voxels for the greater side
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            //ScalarType dist = math::Sqrt(sqDistVec[i]);
00484            if(vp->Q() < minDist) {
00485              vp->Q()=minDist;
00486              medialSrc[indVec[i]]=&*vi;
00487            }             
00488          }
00489        }       
00490      }
00491    }
00492    // Now collect the vertexes of the volume mesh that are on the medial surface 
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  * Function: BuildVolumeSampling
00555  * ----------------------------
00556  * Build a Poisson-Disk Point cloud that cover all the space of the original mesh m
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     // Kdtree must be rebuilt at the end of each step;
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 }; // end class
00587 
00588 
00589 } // end namespace vcg
00590 } // end namespace vcg
00591 #endif // VORONOI_VOLUME_SAMPLING_H


shape_reconstruction
Author(s): Roberto Martín-Martín
autogenerated on Sat Jun 8 2019 18:38:47