bool FilterScreenedPoissonPlugin::applyFilter( const QString& filterName,MeshDocument& md,EnvWrap& env, vcg::CallBackPos* cb) { if (filterName == "Screened Poisson Surface Reconstruction") { MeshModel *mm =md.mm(); MeshModel *pm =md.addNewMesh("","Poisson mesh",false); md.setVisible(pm->id(),false); pm->updateDataMask(MeshModel::MM_VERTQUALITY); PoissonParam<Scalarm> pp; MeshModelPointStream<Scalarm> meshStream(mm->cm); MeshDocumentPointStream<Scalarm> documentStream(md); pp.MaxDepthVal = env.evalInt("depth"); pp.FullDepthVal = env.evalInt("fullDepth"); pp.CGDepthVal= env.evalInt("cgDepth"); pp.ScaleVal = env.evalFloat("scale"); pp.SamplesPerNodeVal = env.evalFloat("samplesPerNode"); pp.PointWeightVal = env.evalFloat("pointWeight"); pp.ItersVal = env.evalInt("iters"); pp.ConfidenceFlag = env.evalBool("confidence"); pp.NormalWeightsFlag = env.evalBool("nWeights"); pp.DensityFlag = true; if(env.evalBool("visibleLayer")) { MeshModel *m=0; while(m=md.nextVisibleMesh(m)) PoissonClean(m->cm, (pp.ConfidenceFlag || pp.NormalWeightsFlag)); Execute<Scalarm>(&documentStream,pm->cm,pp,cb); } else { PoissonClean(mm->cm, (pp.ConfidenceFlag || pp.NormalWeightsFlag)); Execute<Scalarm>(&meshStream,pm->cm,pp,cb); } pm->UpdateBoxAndNormals(); md.setVisible(pm->id(),true); return true; } return false; }
bool SampleXMLFilterPlugin::applyFilter( const QString& filterName,MeshDocument& md,EnvWrap& env, vcg::CallBackPos* cb) { if (filterName == "Random vertex displacement") { MeshModel &m=*md.mm(); srand(time(NULL)); const float max_displacement =env.evalFloat("Displacement"); for(unsigned int i = 0; i< m.cm.vert.size(); i++) { // Typical usage of the callback for showing a nice progress bar in the bottom. // // First parameter is a 0..100 number indicating percentage of completion, the second is an info string. cb(100*i/m.cm.vert.size(), "Randomly Displacing..."); float rndax = (float(2.0f*rand())/RAND_MAX - 1.0f ) *max_displacement; float rnday = (float(2.0f*rand())/RAND_MAX - 1.0f ) *max_displacement; float rndaz = (float(2.0f*rand())/RAND_MAX - 1.0f ) *max_displacement; m.cm.vert[i].P() += vcg::Point3f(rndax,rnday,rndaz); //if ( i % 1000 == 0) QList<int> meshlist; meshlist << m.id(); md.updateRenderStateMeshes(meshlist,int(MeshModel::MM_VERTCOORD)); if (intteruptreq) return true; } //// Log function dump textual info in the lower part of the MeshLab screen. Log("Successfully displaced %i vertices",m.cm.vn); //// to access to the parameters of the filter dialog simply use the getXXXX function of the FilterParameter Class if(env.evalBool("UpdateNormals")) vcg::tri::UpdateNormals<CMeshO>::PerVertexNormalizedPerFace(m.cm); vcg::tri::UpdateBounding<CMeshO>::Box(m.cm); return true; } return false; }
// Core Function doing the actual mesh processing. bool FilterMeasurePlugin::applyFilter( const QString& filterName,MeshDocument& md,EnvWrap& env, vcg::CallBackPos * /*cb*/ ) { if (filterName == "Compute Topological Measures") { CMeshO &m=md.mm()->cm; tri::Allocator<CMeshO>::CompactFaceVector(m); tri::Allocator<CMeshO>::CompactVertexVector(m); md.mm()->updateDataMask(MeshModel::MM_FACEFACETOPO); md.mm()->updateDataMask(MeshModel::MM_VERTFACETOPO); int edgeManifNum = tri::Clean<CMeshO>::CountNonManifoldEdgeFF(m,true); int faceEdgeManif = tri::UpdateSelection<CMeshO>::FaceCount(m); tri::UpdateSelection<CMeshO>::VertexClear(m); tri::UpdateSelection<CMeshO>::FaceClear(m); int vertManifNum = tri::Clean<CMeshO>::CountNonManifoldVertexFF(m,true); tri::UpdateSelection<CMeshO>::FaceFromVertexLoose(m); int faceVertManif = tri::UpdateSelection<CMeshO>::FaceCount(m); int edgeNum=0,borderNum=0; tri::Clean<CMeshO>::CountEdges(m, edgeNum, borderNum); int holeNum; Log("V: %6i E: %6i F:%6i",m.vn,edgeNum,m.fn); int unrefVertNum = tri::Clean<CMeshO>::CountUnreferencedVertex(m); Log("Unreferenced Vertices %i",unrefVertNum); Log("Boundary Edges %i",borderNum); int connectedComponentsNum = tri::Clean<CMeshO>::CountConnectedComponents(m); Log("Mesh is composed by %i connected component(s)\n",connectedComponentsNum); if(edgeManifNum==0 && vertManifNum==0) { Log("Mesh is two-manifold "); } if(edgeManifNum!=0) Log("Mesh has %i non two manifold edges and %i faces are incident on these edges\n",edgeManifNum,faceEdgeManif); if(vertManifNum!=0) Log("Mesh has %i non two manifold vertexes and %i faces are incident on these vertices\n",vertManifNum,faceVertManif); // For Manifold meshes compute some other stuff if(vertManifNum==0 && edgeManifNum==0) { holeNum = tri::Clean<CMeshO>::CountHoles(m); Log("Mesh has %i holes",holeNum); int genus = tri::Clean<CMeshO>::MeshGenus(m.vn-unrefVertNum, edgeNum, m.fn, holeNum, connectedComponentsNum); Log("Genus is %i",genus); } else { Log("Mesh has a undefined number of holes (non 2-manifold mesh)"); Log("Genus is undefined (non 2-manifold mesh)"); } return true; } /************************************************************/ if (filterName == "Compute Topological Measures for Quad Meshes") { CMeshO &m=md.mm()->cm; md.mm()->updateDataMask(MeshModel::MM_FACEFACETOPO); md.mm()->updateDataMask(MeshModel::MM_FACEQUALITY); if (! tri::Clean<CMeshO>::IsFFAdjacencyConsistent(m)) { this->errorMessage = "Error: mesh has a not consistent FF adjacency"; return false; } if (! tri::Clean<CMeshO>::HasConsistentPerFaceFauxFlag(m)) { this->errorMessage = "QuadMesh problem: mesh has a not consistent FauxEdge tagging"; return false; } int nQuads = tri::Clean<CMeshO>::CountBitQuads(m); int nTris = tri::Clean<CMeshO>::CountBitTris(m); int nPolys = tri::Clean<CMeshO>::CountBitPolygons(m); int nLargePolys = tri::Clean<CMeshO>::CountBitLargePolygons(m); if(nLargePolys>0) nQuads=0; Log("Mesh has %8i triangles \n",nTris); Log(" %8i quads \n",nQuads); Log(" %8i polygons \n",nPolys); Log(" %8i large polygons (with internal faux vertexes)",nLargePolys); if (! tri::Clean<CMeshO>::IsBitTriQuadOnly(m)) { this->errorMessage = "QuadMesh problem: the mesh is not TriQuadOnly"; return false; } // // i // // // i+1 i+2 tri::UpdateFlags<CMeshO>::FaceClearV(m); Distribution<float> AngleD; // angle distribution Distribution<float> RatioD; // ratio distribution tri::UpdateFlags<CMeshO>::FaceClearV(m); for(CMeshO::FaceIterator fi=m.face.begin(); fi!=m.face.end(); ++fi) if(!fi->IsV()) { fi->SetV(); // Collect the vertices Point3f qv[4]; bool quadFound=false; for(int i=0; i<3; ++i) { if((*fi).IsF(i) && !(*fi).IsF((i+1)%3) && !(*fi).IsF((i+2)%3) ) { qv[0] = fi->V0(i)->P(), qv[1] = fi->FFp(i)->V2( fi->FFi(i) )->P(), qv[2] = fi->V1(i)->P(), qv[3] = fi->V2(i)->P(); quadFound=true; } } assert(quadFound); for(int i=0; i<4; ++i) AngleD.Add(fabs(90-math::ToDeg(Angle(qv[(i+0)%4] - qv[(i+1)%4], qv[(i+2)%4] - qv[(i+1)%4])))); float edgeLen[4]; for(int i=0; i<4; ++i) edgeLen[i]=Distance(qv[(i+0)%4],qv[(i+1)%4]); std::sort(edgeLen,edgeLen+4); RatioD.Add(edgeLen[0]/edgeLen[3]); } Log("Right Angle Discrepancy Avg %4.3f Min %4.3f Max %4.3f StdDev %4.3f Percentile 0.05 %4.3f percentile 95 %4.3f", AngleD.Avg(), AngleD.Min(), AngleD.Max(),AngleD.StandardDeviation(),AngleD.Percentile(0.05),AngleD.Percentile(0.95)); Log("Quad Ratio Avg %4.3f Min %4.3f Max %4.3f", RatioD.Avg(), RatioD.Min(), RatioD.Max()); return true; } /************************************************************/ if(filterName == "Compute Geometric Measures") { CMeshO &m=md.mm()->cm; tri::Inertia<CMeshO> I(m); float Area = tri::Stat<CMeshO>::ComputeMeshArea(m); float Volume = I.Mass(); Log("Mesh Bounding Box Size %f %f %f", m.bbox.DimX(), m.bbox.DimY(), m.bbox.DimZ()); Log("Mesh Bounding Box Diag %f ", m.bbox.Diag()); Log("Mesh Volume is %f", Volume); Log("Mesh Surface is %f", Area); Point3f bc=tri::Stat<CMeshO>::ComputeShellBarycenter(m); Log("Thin shell barycenter %9.6f %9.6f %9.6f",bc[0],bc[1],bc[2]); if(Volume<=0) Log("Mesh is not 'solid', no information on barycenter and inertia tensor."); else { Log("Center of Mass is %f %f %f", I.CenterOfMass()[0], I.CenterOfMass()[1], I.CenterOfMass()[2]); Matrix33f IT; I.InertiaTensor(IT); Log("Inertia Tensor is :"); Log(" | %9.6f %9.6f %9.6f |",IT[0][0],IT[0][1],IT[0][2]); Log(" | %9.6f %9.6f %9.6f |",IT[1][0],IT[1][1],IT[1][2]); Log(" | %9.6f %9.6f %9.6f |",IT[2][0],IT[2][1],IT[2][2]); Matrix33f PCA; Point3f pcav; I.InertiaTensorEigen(PCA,pcav); Log("Principal axes are :"); Log(" | %9.6f %9.6f %9.6f |",PCA[0][0],PCA[0][1],PCA[0][2]); Log(" | %9.6f %9.6f %9.6f |",PCA[1][0],PCA[1][1],PCA[1][2]); Log(" | %9.6f %9.6f %9.6f |",PCA[2][0],PCA[2][1],PCA[2][2]); Log("axis momenta are :"); Log(" | %9.6f %9.6f %9.6f |",pcav[0],pcav[1],pcav[2]); } return true; } /************************************************************/ if((filterName == "Per Vertex Quality Stat") || (filterName == "Per Face Quality Stat") ) { CMeshO &m=md.mm()->cm; Distribution<float> DD; if(filterName == "Per Vertex Quality Stat") tri::Stat<CMeshO>::ComputePerVertexQualityDistribution(m, DD, false); else tri::Stat<CMeshO>::ComputePerFaceQualityDistribution(m, DD, false); Log(" Min %f Max %f",DD.Min(),DD.Max()); Log(" Avg %f Med %f",DD.Avg(),DD.Percentile(0.5f)); Log(" StdDev %f",DD.StandardDeviation()); Log(" Variance %f",DD.Variance()); return true; } if((filterName == "Per Vertex Quality Histogram") || (filterName == "Per Face Quality Histogram") ) { CMeshO &m=md.mm()->cm; float RangeMin = env.evalFloat("HistMin"); float RangeMax = env.evalFloat("HistMax"); int binNum = env.evalInt("binNum"); Histogramf H; H.SetRange(RangeMin,RangeMax,binNum); if(filterName == "Per Vertex Quality Histogram") { for(CMeshO::VertexIterator vi = m.vert.begin(); vi != m.vert.end(); ++vi) if(!(*vi).IsD()) { assert(!math::IsNAN((*vi).Q()) && "You should never try to compute Histogram with Invalid Floating points numbers (NaN)"); H.Add((*vi).Q()); } } else { for(CMeshO::FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) if(!(*fi).IsD()) { assert(!math::IsNAN((*fi).Q()) && "You should never try to compute Histogram with Invalid Floating points numbers (NaN)"); H.Add((*fi).Q()); } } Log("( -inf..%15.7f) : %4.0f",RangeMin,H.BinCountInd(0)); for(int i=1; i<=binNum; ++i) Log("[%15.7f..%15.7f) : %4.0f",H.BinLowerBound(i),H.BinUpperBound(i),H.BinCountInd(i)); Log("[%15.7f.. +inf) : %4.0f",RangeMax,H.BinCountInd(binNum+1)); return true; } return false; }