// // Apply filter // bool FilterTopoPlugin::applyFilter(QAction *filter, MeshModel &m, RichParameterSet & par, vcg::CallBackPos *cb) { // To run the retopology algorithm an istance of RetopoMeshBuilder is needed RetopMeshBuilder rm; // Load topology mesh MeshModel *userMesh = par.getMesh("userMesh"); // Load (input) original mesh MeshModel *inMesh = par.getMesh("inMesh"); // Load iterations value int it = par.getInt("it"); // Load distance value float dist = par.getAbsPerc("dist"); // Destination meshmodel: retopology mesh will replace flat topology mesh MeshModel * outM = par.getMesh("userMesh"); // Prepare mesh inMesh->updateDataMask(MeshModel::MM_FACEMARK); tri::UpdateNormals<CMeshO>::PerFaceNormalized(inMesh->cm); tri::UpdateFlags<CMeshO>::FaceProjection(inMesh->cm); // Init the retopology builder with original input mesh and distance value rm.init(inMesh, dist); // Apply the algorithm return rm.applyTopoMesh(*userMesh, *inMesh, it, dist, *outM); }
// The Real Core Function doing the actual mesh processing. // Move Vertex of a random quantity bool ExtraSamplePlugin::applyFilter(QAction */*filter*/, MeshDocument &md, RichParameterSet & par, vcg::CallBackPos *cb) { CMeshO &m = md.mm()->cm; srand(time(NULL)); const float max_displacement =par.getAbsPerc("Displacement"); for(unsigned int i = 0; i< m.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.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.vert[i].P() += vcg::Point3f(rndax,rnday,rndaz); } // Log function dump textual info in the lower part of the MeshLab screen. Log("Successfully displaced %i vertices",m.vn); // to access to the parameters of the filter dialog simply use the getXXXX function of the FilterParameter Class if(par.getBool("UpdateNormals")) vcg::tri::UpdateNormal<CMeshO>::PerVertexNormalizedPerFace(m); vcg::tri::UpdateBounding<CMeshO>::Box(m); return true; }
bool FilterFractal::applyFilter(QAction* filter, MeshDocument &md, RichParameterSet &par, vcg::CallBackPos* cb) { if(this->getClass(filter) == MeshFilterInterface::MeshCreation) md.addNewMesh("",this->filterName(ID(filter))); switch(ID(filter)) { case CR_FRACTAL_TERRAIN: case FP_FRACTAL_MESH: { MeshModel* mm = md.mm(); float maxHeight = .0; int smoothingSteps = 0; if(ID(filter) == CR_FRACTAL_TERRAIN) { int steps = par.getInt("steps"); steps = ((steps<2)? 2: steps); float gridSide = .0; FractalUtils<CMeshO>::GenerateGrid(mm->cm, steps, gridSide); maxHeight = par.getDynamicFloat("maxHeight") * gridSide; } else { maxHeight = par.getAbsPerc("maxHeight"); smoothingSteps = par.getInt("smoothingSteps"); } FractalUtils<CMeshO>::FractalArgs args (mm, par.getEnum("algorithm"),par.getFloat("seed"), par.getFloat("octaves"), par.getFloat("lacunarity"), par.getFloat("fractalIncrement"), par.getFloat("offset"), par.getFloat("gain"), maxHeight, par.getDynamicFloat("scale"), smoothingSteps, par.getBool("saveAsQuality")); if(args.saveAsQuality) mm->updateDataMask(MeshModel::MM_VERTQUALITY); return FractalUtils<CMeshO>::ComputeFractalPerturbation(mm->cm, args, cb); } break; case FP_CRATERS: { if (md.meshList.size() < 2) { errorMessage = "There must be at least two layers to apply the craters generation filter."; return false; } CMeshO* samples = &(par.getMesh("samples_mesh")->cm); if (samples->face.size() > 0) { errorMessage = "The sample layer selected should be a points cloud."; return false; } CMeshO* target = &(par.getMesh("target_mesh")->cm); if (samples == target) { errorMessage = "The sample layer and the target layer must be different."; return false; } float minRadius = par.getDynamicFloat("min_radius"); float maxRadius = par.getDynamicFloat("max_radius"); if (maxRadius <= minRadius) { errorMessage = "Min radius is greater than max radius."; return false; } float minDepth = par.getDynamicFloat("min_depth"); float maxDepth = par.getDynamicFloat("max_depth"); if (maxDepth <= minDepth) { errorMessage = "Min depth is greater than max depth."; return false; } // reads parameters CratersUtils<CMeshO>::CratersArgs args(par.getMesh("target_mesh"), par.getMesh("samples_mesh"), par.getEnum("rbf"), par.getInt("seed"), minRadius, maxRadius, minDepth, maxDepth, par.getInt("smoothingSteps"), par.getBool("save_as_quality"), par.getBool("invert"), par.getBool("ppNoise"), par.getBool("successiveImpacts"), par.getDynamicFloat("elevation"), par.getEnum("blend"), par.getDynamicFloat("blendThreshold")); return CratersUtils<CMeshO>::GenerateCraters(args, cb); } break; } return false; }
/* The Real Core Function doing the actual mesh processing */ bool GeometryAgingPlugin::applyFilter(QAction *filter, MeshDocument &md, RichParameterSet ¶ms, vcg::CallBackPos *cb) { MeshModel &m=*(md.mm()); if( ID(filter) != FP_ERODE) { assert (0); return false; } m.updateDataMask(MeshModel::MM_VERTQUALITY); bool curvature = params.getBool("ComputeCurvature"); if(curvature) computeMeanCurvature(m.cm); // other plugin parameters bool smoothQ = params.getBool("SmoothQuality"); float qualityTh = params.getAbsPerc("QualityThreshold"); float edgeLenTh = params.getAbsPerc("EdgeLenThreshold"); float chipDepth = params.getAbsPerc("ChipDepth"); int octaves = params.getInt("Octaves"); float noiseScale = params.getAbsPerc("NoiseFreqScale"); float noiseClamp = params.getFloat("NoiseClamp"); int dispSteps = (int)params.getFloat("DisplacementSteps"); bool selected = params.getBool("Selected"); bool storeDispl = params.getBool("StoreDisplacement"); // error checking on parameters values if(edgeLenTh == 0.0) edgeLenTh = m.cm.bbox.Diag()*0.02; if(chipDepth == 0.0) chipDepth = m.cm.bbox.Diag()*0.05; noiseClamp = math::Clamp<float>(noiseClamp, 0.0, 1.0); // quality threshold percentage value std::pair<float, float> qRange = tri::Stat<CMeshO>::ComputePerVertexQualityMinMax(m.cm); float qperc = (qualityTh-qRange.first) / (qRange.second-qRange.first); // compute mesh quality, if requested if(curvature) { if(cb) (*cb)(0, "Computing quality values..."); computeMeanCurvature(m.cm); } // eventually, smooth quality values if(smoothQ) tri::Smooth<CMeshO>::VertexQualityLaplacian(m.cm); // if quality values have been recomputed quality threshold may not // be valid, so we recompute its absolute value using the percentage // value chosen by the user if(curvature || smoothQ) { qRange = tri::Stat<CMeshO>::ComputePerVertexQualityMinMax(m.cm); qualityTh = qRange.first + (qRange.second-qRange.first) * qperc; } // edge predicate QualityEdgePred ep = QualityEdgePred(selected, edgeLenTh, qualityTh); // refine needed edges refineMesh(m.cm, ep, selected, cb); // if requested, add erosion attribute to vertexes and initialize it if(storeDispl) { CMeshO::PerVertexAttributeHandle<Point3f> vah = (tri::HasPerVertexAttribute(m.cm, "Erosion") ? tri::Allocator<CMeshO>::GetPerVertexAttribute<Point3f>(m.cm, "Erosion") : tri::Allocator<CMeshO>::AddPerVertexAttribute<Point3f>(m.cm, std::string("Erosion"))); for(CMeshO::VertexIterator vi=m.cm.vert.begin(); vi!=m.cm.vert.end(); vi++) vah[vi] = Point3f(0.0, 0.0, 0.0); } CMeshO::PerVertexAttributeHandle<Point3f> vah = vcg::tri::Allocator<CMeshO>::GetPerVertexAttribute<Point3f>(m.cm, "Erosion"); // vertexes along selection border will not be displaced if(selected) tri::UpdateSelection<CMeshO>::VertexFromFaceStrict(m.cm); // clear vertexes V bit (will be used to mark the vertexes as displaced) tri::UpdateFlags<CMeshO>::VertexClearV(m.cm); // displace vertexes for(int i=0; i<dispSteps; i++) { GridStaticPtr<CFaceO, CMeshO::ScalarType> gM; gM.Set(m.cm.face.begin(), m.cm.face.end()); if(cb) (*cb)( (i+1)*100/dispSteps, "Aging..."); // blend toghether face normals and recompute vertex normal from these normals // to get smoother offest directions tri::Smooth<CMeshO>::FaceNormalLaplacianFF(m.cm, 3); tri::UpdateNormals<CMeshO>::PerVertexFromCurrentFaceNormal(m.cm); tri::UpdateNormals<CMeshO>::NormalizeVertex(m.cm); for(CMeshO::FaceIterator fi=m.cm.face.begin(); fi!=m.cm.face.end(); fi++) { if((*fi).IsD()) continue; for(int j=0; j<3; j++) { if(ep.qVertTest(face::Pos<CMeshO::FaceType>(&*fi,j)) && !(*fi).V(j)->IsV() && (!selected || ((*fi).IsS() && (*fi).FFp(j)->IsS())) ) { double noise; // noise value Point3f dispDir = (*fi).V(j)->N(); // displacement direction Point3f p = (*fi).V(j)->P() / noiseScale; noise = generateNoiseValue(octaves, p); // only values bigger than noiseClamp will be considered noise = (noise<noiseClamp?0.0:(noise-noiseClamp)); // displacement offset Point3f offset = -(dispDir * chipDepth * noise) / dispSteps; (*fi).V(j)->P() += offset; if(faceIntersections(m.cm, face::Pos<CMeshO::FaceType>(&*fi,j), gM)) (*fi).V(j)->P() -= offset; else if(storeDispl) // store displacement vah[(*fi).V(j)] = vah[(*fi).V(j)] + offset; // mark as visited (displaced) (*fi).V(j)->SetV(); } } } // clear vertexes V bit again tri::UpdateFlags<CMeshO>::VertexClearV(m.cm); } // update normals vcg::tri::UpdateNormals<CMeshO>::PerVertexNormalizedPerFace(m.cm); smoothPeaks(m.cm, selected, storeDispl); // readjust selection if(selected) tri::UpdateSelection<CMeshO>::VertexFromFaceLoose(m.cm); return true; }
bool CleanFilter::applyFilter(QAction *filter, MeshDocument &md, RichParameterSet & par, vcg::CallBackPos * cb) { MeshModel &m=*(md.mm()); switch(ID(filter)) { case FP_BALL_PIVOTING: { float Radius = par.getAbsPerc("BallRadius"); float Clustering = par.getFloat("Clustering") / 100.0f; float CreaseThr = math::ToRad(par.getFloat("CreaseThr")); bool DeleteFaces = par.getBool("DeleteFaces"); if(DeleteFaces) { m.cm.fn=0; m.cm.face.resize(0); } m.updateDataMask(MeshModel::MM_VERTFACETOPO); int startingFn=m.cm.fn; tri::BallPivoting<CMeshO> pivot(m.cm, Radius, Clustering, CreaseThr); // the main processing pivot.BuildMesh(cb); m.clearDataMask(MeshModel::MM_FACEFACETOPO); Log("Reconstructed surface. Added %i faces",m.cm.fn-startingFn); } break; case FP_REMOVE_ISOLATED_DIAMETER: { float minCC= par.getAbsPerc("MinComponentDiag"); std::pair<int,int> delInfo= tri::Clean<CMeshO>::RemoveSmallConnectedComponentsDiameter(m.cm,minCC); Log("Removed %2 connected components out of %1", delInfo.second, delInfo.first); }break; case FP_REMOVE_ISOLATED_COMPLEXITY: { float minCC= par.getInt("MinComponentSize"); std::pair<int,int> delInfo=tri::Clean<CMeshO>::RemoveSmallConnectedComponentsSize(m.cm,minCC); Log("Removed %i connected components out of %i", delInfo.second, delInfo.first); }break; case FP_REMOVE_WRT_Q: { int deletedFN=0; int deletedVN=0; float val=par.getAbsPerc("MaxQualityThr"); CMeshO::VertexIterator vi; for(vi=m.cm.vert.begin();vi!=m.cm.vert.end();++vi) if(!(*vi).IsD() && (*vi).Q()<val) { tri::Allocator<CMeshO>::DeleteVertex(m.cm, *vi); deletedVN++; } CMeshO::FaceIterator fi; for(fi=m.cm.face.begin();fi!=m.cm.face.end();++fi) if(!(*fi).IsD()) if((*fi).V(0)->IsD() ||(*fi).V(1)->IsD() ||(*fi).V(2)->IsD() ) { tri::Allocator<CMeshO>::DeleteFace(m.cm, *fi); deletedFN++; } m.clearDataMask(MeshModel::MM_FACEFACETOPO); Log("Deleted %i vertices and %i faces with a quality lower than %f", deletedVN,deletedFN,val); }break; case FP_REMOVE_TVERTEX_COLLAPSE : { float threshold = par.getFloat("Threshold"); bool repeat = par.getBool("Repeat"); int total = tri::Clean<CMeshO>::RemoveTVertexByCollapse(m.cm, threshold, repeat); Log("Successfully removed %d t-vertices", total); } break; case FP_REMOVE_TVERTEX_FLIP : { float threshold = par.getFloat("Threshold"); bool repeat = par.getBool("Repeat"); int total = tri::Clean<CMeshO>::RemoveTVertexByFlip(m.cm, threshold, repeat); Log("Successfully removed %d t-vertices", total); } break; case FP_MERGE_CLOSE_VERTEX : { float threshold = par.getAbsPerc("Threshold"); int total = tri::Clean<CMeshO>::MergeCloseVertex(m.cm, threshold); Log("Successfully merged %d vertices", total); } break; case FP_REMOVE_DUPLICATE_FACE : { int total = tri::Clean<CMeshO>::RemoveDuplicateFace(m.cm); Log("Successfully deleted %d duplicated faces", total); } break; case FP_REMOVE_FOLD_FACE: { m.updateDataMask(MeshModel::MM_FACECOLOR); int total = tri::Clean<CMeshO>::RemoveFaceFoldByFlip(m.cm); m.UpdateBoxAndNormals(); Log("Successfully flipped %d folded faces", total); } break; case FP_REMOVE_NON_MANIF_EDGE : { int total = tri::Clean<CMeshO>::RemoveNonManifoldFace(m.cm); Log("Successfully removed %d folded faces", total); } break; case FP_REMOVE_NON_MANIF_VERT : { float threshold = par.getFloat("VertDispRatio"); int total = tri::Clean<CMeshO>::SplitNonManifoldVertex(m.cm,threshold); Log("Successfully split %d non manifold vertices faces", total); } break; case FP_SNAP_MISMATCHED_BORDER : { float threshold = par.getFloat("EdgeDistRatio"); int total = SnapVertexBorder(m.cm, threshold,cb); Log("Successfully Splitted %d faces to snap", total); } break; case FP_COMPACT_FACE : { vcg::tri::Allocator<CMeshO>::CompactFaceVector(m.cm); break; } case FP_COMPACT_VERT : { vcg::tri::Allocator<CMeshO>::CompactVertexVector(m.cm); break; } default : assert(0); // unknown filter; } return true; }
bool FilterGeodesic::applyFilter(QAction *filter, MeshDocument &md, RichParameterSet & par, vcg::CallBackPos * /*cb*/) { MeshModel &m=*(md.mm()); CMeshO::FaceIterator fi; CMeshO::VertexIterator vi; switch (ID(filter)) { case FP_QUALITY_POINT_GEODESIC: { m.updateDataMask(MeshModel::MM_VERTFACETOPO); m.updateDataMask(MeshModel::MM_VERTMARK); m.updateDataMask(MeshModel::MM_VERTQUALITY); m.updateDataMask(MeshModel::MM_VERTCOLOR); tri::UpdateFlags<CMeshO>::FaceBorderFromVF(m.cm); tri::UpdateFlags<CMeshO>::VertexBorderFromFace(m.cm); Point3f startPoint = par.getPoint3f("startPoint"); // first search the closest point on the surface; CMeshO::VertexPointer startVertex=0; float minDist= std::numeric_limits<float>::max(); for(vi=m.cm.vert.begin();vi!=m.cm.vert.end();++vi) if(!(*vi).IsD()) if(SquaredDistance(startPoint,(*vi).P()) < minDist) { startVertex=&*vi; minDist=SquaredDistance(startPoint,(*vi).P()); } Log("Input point is %f %f %f Closest on surf is %f %f %f",startPoint[0],startPoint[1],startPoint[2],startVertex->P()[0],startVertex->P()[1],startVertex->P()[2]); // Now actually compute the geodesic distnace from the closest point float dist_thr = par.getAbsPerc("maxDistance"); tri::EuclideanDistance<CMeshO> dd; tri::Geodesic<CMeshO>::Compute(m.cm, vector<CVertexO*>(1,startVertex),dd,dist_thr); // Cleaning Quality value of the unrefernced vertices // Unreached vertexes has a quality that is maxfloat int unreachedCnt=0; float unreached = std::numeric_limits<float>::max(); for(vi=m.cm.vert.begin();vi!=m.cm.vert.end();++vi) if(!(*vi).IsD()) if((*vi).Q() == unreached) { unreachedCnt++; (*vi).Q()=0; } if(unreachedCnt >0 ) Log("Warning: %i vertices were unreacheable from the borders, probably your mesh has unreferenced vertices",unreachedCnt); tri::UpdateColor<CMeshO>::PerVertexQualityRamp(m.cm); } break; case FP_QUALITY_BORDER_GEODESIC: { m.updateDataMask(MeshModel::MM_VERTFACETOPO); m.updateDataMask(MeshModel::MM_VERTMARK); m.updateDataMask(MeshModel::MM_VERTQUALITY); m.updateDataMask(MeshModel::MM_VERTCOLOR); tri::UpdateFlags<CMeshO>::FaceBorderFromVF(m.cm); tri::UpdateFlags<CMeshO>::VertexBorderFromFace(m.cm); bool ret = tri::Geodesic<CMeshO>::DistanceFromBorder(m.cm); // Cleaning Quality value of the unrefernced vertices // Unreached vertexes has a quality that is maxfloat int unreachedCnt=0; float unreached = std::numeric_limits<float>::max(); for(vi=m.cm.vert.begin();vi!=m.cm.vert.end();++vi) if(!(*vi).IsD()) if((*vi).Q() == unreached) { unreachedCnt++; (*vi).Q()=0; } if(unreachedCnt >0 ) Log("Warning: %i vertices were unreacheable from the borders, probably your mesh has unreferenced vertices",unreachedCnt); if(!ret) Log("Mesh Has no borders. No geodesic distance computed"); else tri::UpdateColor<CMeshO>::PerVertexQualityRamp(m.cm); } break; default: assert(0); break; } return true; }