// given a RichParameterSet get back the alignment parameter (dual of the buildParemeterSet) void AlignParameter::buildAlignParameters(RichParameterSet &fps , AlignPair::Param &app) { app.SampleNum=fps.getInt("SampleNum"); app.MinDistAbs=fps.getFloat("MinDistAbs"); app.TrgDistAbs=fps.getFloat("TrgDistAbs"); app.MaxIterNum=fps.getInt("MaxIterNum"); app.SampleMode= fps.getBool("SampleMode")?AlignPair::Param::SMNormalEqualized : AlignPair::Param::SMRandom; app.ReduceFactorPerc=fps.getFloat("ReduceFactorPerc"); app.PassHiFilter=fps.getFloat("PassHiFilter"); app.MatchMode=fps.getBool("MatchMode")? AlignPair::Param::MMRigid : AlignPair::Param::MMClassic; }
// 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 IOMPlugin::save(const QString &formatName, const QString &fileName, MeshModel &m, const int mask,const RichParameterSet & par, vcg::CallBackPos *cb, QWidget *parent) { QString errorMsgFormat = "Error encountered while exportering file %1:\n%2"; m.updateDataMask(MeshModel::MM_FACEFACETOPO); int result = vcg::tri::io::ExporterM<CMeshO>::Save(m.cm,qPrintable(fileName),mask); if(par.getBool("HtmlSnippet")) { vcg::tri::io::ExporterM<CMeshO>::WriteHtmlSnippet(qPrintable(fileName),qPrintable(QString(fileName)+".html")); } if(result!=0) { QMessageBox::warning(parent, tr("Saving Error"), errorMsgFormat.arg(qPrintable(fileName), vcg::tri::io::ExporterM<CMeshO>::ErrorMsg(result))); return false; } return true; }
bool FilterCSG::applyFilter(QAction *filter, MeshDocument &md, RichParameterSet & par, vcg::CallBackPos *cb) { switch(ID(filter)) { case FP_CSG: { MeshModel *firstMesh = par.getMesh("FirstMesh"); MeshModel *secondMesh = par.getMesh("SecondMesh"); firstMesh->updateDataMask(MeshModel::MM_FACEFACETOPO | MeshModel::MM_FACENORMAL | MeshModel::MM_FACEQUALITY); secondMesh->updateDataMask(MeshModel::MM_FACEFACETOPO | MeshModel::MM_FACENORMAL | MeshModel::MM_FACEQUALITY); if (!isValid (firstMesh->cm, this->errorMessage) || !isValid (secondMesh->cm, this->errorMessage)) return false; firstMesh->updateDataMask(MeshModel::MM_FACENORMAL | MeshModel::MM_FACEQUALITY); secondMesh->updateDataMask(MeshModel::MM_FACENORMAL | MeshModel::MM_FACEQUALITY); typedef CMeshO::ScalarType scalar; typedef Intercept<mpq_class,scalar> intercept; const scalar d = par.getFloat("Delta"); const Point3f delta(d, d, d); const int subFreq = par.getInt("SubDelta"); Log(0, "Rasterizing first volume..."); InterceptVolume<intercept> v = InterceptSet3<intercept>(firstMesh->cm, delta, subFreq, cb); Log(0, "Rasterizing second volume..."); InterceptVolume<intercept> tmp = InterceptSet3<intercept>(secondMesh->cm, delta, subFreq, cb); MeshModel *mesh; switch(par.getEnum("Operator")){ case CSG_OPERATION_INTERSECTION: Log(0, "Intersection..."); v &= tmp; mesh = md.addNewMesh("","intersection"); break; case CSG_OPERATION_UNION: Log(0, "Union..."); v |= tmp; mesh = md.addNewMesh("","union"); break; case CSG_OPERATION_DIFFERENCE: Log(0, "Difference..."); v -= tmp; mesh = md.addNewMesh("","difference"); break; default: assert(0); return true; } Log(0, "Building mesh..."); typedef vcg::intercept::Walker<CMeshO, intercept> MyWalker; MyWalker walker; if (par.getBool("Extended")) { mesh->updateDataMask(MeshModel::MM_FACEFACETOPO); typedef vcg::tri::ExtendedMarchingCubes<CMeshO, MyWalker> MyExtendedMarchingCubes; MyExtendedMarchingCubes mc(mesh->cm, walker); walker.BuildMesh<MyExtendedMarchingCubes>(mesh->cm, v, mc, cb); } else { typedef vcg::tri::MarchingCubes<CMeshO, MyWalker> MyMarchingCubes; MyWalker walker; MyMarchingCubes mc(mesh->cm, walker); walker.BuildMesh<MyMarchingCubes>(mesh->cm, v, mc, cb); } Log(0, "Done"); vcg::tri::UpdateBounding<CMeshO>::Box(mesh->cm); vcg::tri::UpdateNormal<CMeshO>::PerFaceFromCurrentVertexNormal(mesh->cm); } return true; default: assert (0); } 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 ExtraMeshColorizePlugin::applyFilter(QAction *filter, MeshDocument &md, RichParameterSet & par, vcg::CallBackPos *cb){ MeshModel &m=*(md.mm()); switch(ID(filter)) { case CP_SATURATE_QUALITY:{ m.updateDataMask(MeshModel::MM_VERTFACETOPO); tri::UpdateQuality<CMeshO>::VertexSaturate(m.cm, par.getFloat("gradientThr")); if(par.getBool("updateColor")) { Histogramf H; tri::Stat<CMeshO>::ComputePerVertexQualityHistogram(m.cm,H); m.updateDataMask(MeshModel::MM_VERTCOLOR); tri::UpdateColor<CMeshO>::VertexQualityRamp(m.cm,H.Percentile(0.1f),H.Percentile(0.9f)); } Log("Saturated "); } break; case CP_MAP_VQUALITY_INTO_COLOR: m.updateDataMask(MeshModel::MM_VERTCOLOR); case CP_CLAMP_QUALITY: { float RangeMin = par.getFloat("minVal"); float RangeMax = par.getFloat("maxVal"); bool usePerc = par.getDynamicFloat("perc")>0; Histogramf H; tri::Stat<CMeshO>::ComputePerVertexQualityHistogram(m.cm,H); float PercLo = H.Percentile(par.getDynamicFloat("perc")/100.f); float PercHi = H.Percentile(1.0-par.getDynamicFloat("perc")/100.f); if(par.getBool("zeroSym")) { RangeMin = min(RangeMin, -math::Abs(RangeMax)); RangeMax = max(math::Abs(RangeMin), RangeMax); PercLo = min(PercLo, -math::Abs(PercHi)); PercHi = max(math::Abs(PercLo), PercHi); } if(usePerc) { if(ID(filter)==CP_CLAMP_QUALITY) tri::UpdateQuality<CMeshO>::VertexClamp(m.cm,PercLo,PercHi); else tri::UpdateColor<CMeshO>::VertexQualityRamp(m.cm,PercLo,PercHi); Log("Quality Range: %f %f; Used (%f %f) percentile (%f %f) ",H.MinV(),H.MaxV(),PercLo,PercHi,par.getDynamicFloat("perc"),100-par.getDynamicFloat("perc")); } else { if(ID(filter)==CP_CLAMP_QUALITY) tri::UpdateQuality<CMeshO>::VertexClamp(m.cm,RangeMin,RangeMax); else tri::UpdateColor<CMeshO>::VertexQualityRamp(m.cm,RangeMin,RangeMax); Log("Quality Range: %f %f; Used (%f %f)",H.MinV(),H.MaxV(),RangeMin,RangeMax); } break; } case CP_MAP_FQUALITY_INTO_COLOR: { m.updateDataMask(MeshModel::MM_FACECOLOR); float RangeMin = par.getFloat("minVal"); float RangeMax = par.getFloat("maxVal"); float perc = par.getDynamicFloat("perc"); Histogramf H; tri::Stat<CMeshO>::ComputePerFaceQualityHistogram(m.cm,H); float PercLo = H.Percentile(perc/100.f); float PercHi = H.Percentile(1.0-perc/100.f); // Make the range and percentile symmetric w.r.t. zero, so that // the value zero is always colored in yellow if(par.getBool("zeroSym")){ RangeMin = min(RangeMin, -math::Abs(RangeMax)); RangeMax = max(math::Abs(RangeMin), RangeMax); PercLo = min(PercLo, -math::Abs(PercHi)); PercHi = max(math::Abs(PercLo), PercHi); } tri::UpdateColor<CMeshO>::FaceQualityRamp(m.cm,PercLo,PercHi); Log("Quality Range: %f %f; Used (%f %f) percentile (%f %f) ", H.MinV(), H.MaxV(), PercLo, PercHi, perc, 100-perc); break; } case CP_DISCRETE_CURVATURE: { m.updateDataMask(MeshModel::MM_FACEFACETOPO | MeshModel::MM_VERTCURV); m.updateDataMask(MeshModel::MM_VERTCOLOR | MeshModel::MM_VERTQUALITY); tri::UpdateFlags<CMeshO>::FaceBorderFromFF(m.cm); if ( tri::Clean<CMeshO>::CountNonManifoldEdgeFF(m.cm) > 0) { errorMessage = "Mesh has some not 2-manifold faces, Curvature computation requires manifoldness"; // text return false; // can't continue, mesh can't be processed } int delvert=tri::Clean<CMeshO>::RemoveUnreferencedVertex(m.cm); if(delvert) Log("Pre-Curvature Cleaning: Removed %d unreferenced vertices",delvert); tri::Allocator<CMeshO>::CompactVertexVector(m.cm); tri::UpdateCurvature<CMeshO>::MeanAndGaussian(m.cm); int curvType = par.getEnum("CurvatureType"); switch(curvType){ case 0: tri::UpdateQuality<CMeshO>::VertexFromMeanCurvature(m.cm); Log( "Computed Mean Curvature"); break; case 1: tri::UpdateQuality<CMeshO>::VertexFromGaussianCurvature(m.cm); Log( "Computed Gaussian Curvature"); break; case 2: tri::UpdateQuality<CMeshO>::VertexFromRMSCurvature(m.cm); Log( "Computed RMS Curvature"); break; case 3: tri::UpdateQuality<CMeshO>::VertexFromAbsoluteCurvature(m.cm); Log( "Computed ABS Curvature"); break; default : assert(0); } Histogramf H; tri::Stat<CMeshO>::ComputePerVertexQualityHistogram(m.cm,H); tri::UpdateColor<CMeshO>::VertexQualityRamp(m.cm,H.Percentile(0.1f),H.Percentile(0.9f)); Log( "Curvature Range: %f %f (Used 90 percentile %f %f) ",H.MinV(),H.MaxV(),H.Percentile(0.1f),H.Percentile(0.9f)); break; } case CP_TRIANGLE_QUALITY: { m.updateDataMask(MeshModel::MM_FACECOLOR | MeshModel::MM_FACEQUALITY); CMeshO::FaceIterator fi; Distribution<float> distrib; float minV = 0; float maxV = 1.0; int metric = par.getEnum("Metric"); if(metric ==4 || metric ==5 ) { if(!m.hasDataMask(MeshModel::MM_VERTTEXCOORD) && !m.hasDataMask(MeshModel::MM_WEDGTEXCOORD)) { this->errorMessage = "This metric need Texture Coordinate"; return false; } } switch(metric){ case 0: { //area / max edge minV = 0; maxV = sqrt(3.0f)/2.0f; for(fi=m.cm.face.begin();fi!=m.cm.face.end();++fi) if(!(*fi).IsD()) (*fi).Q() = vcg::Quality((*fi).P(0), (*fi).P(1),(*fi).P(2)); } break; case 1: { //inradius / circumradius for(fi=m.cm.face.begin();fi!=m.cm.face.end();++fi) if(!(*fi).IsD()) (*fi).Q() = vcg::QualityRadii((*fi).P(0), (*fi).P(1), (*fi).P(2)); } break; case 2: { //mean ratio for(fi=m.cm.face.begin();fi!=m.cm.face.end();++fi) if(!(*fi).IsD()) (*fi).Q() = vcg::QualityMeanRatio((*fi).P(0), (*fi).P(1), (*fi).P(2)); } break; case 3: { // AREA for(fi=m.cm.face.begin();fi!=m.cm.face.end();++fi) if(!(*fi).IsD()) (*fi).Q() = vcg::DoubleArea((*fi))*0.5f; tri::Stat<CMeshO>::ComputePerFaceQualityMinMax(m.cm,minV,maxV); } break; case 4: { //TEXTURE Angle Distortion if(m.hasDataMask(MeshModel::MM_WEDGTEXCOORD)) { for(fi=m.cm.face.begin();fi!=m.cm.face.end();++fi) if(!(*fi).IsD()) (*fi).Q() = Distortion<CMeshO,true>::AngleDistortion(&*fi); } else { for(fi=m.cm.face.begin();fi!=m.cm.face.end();++fi) if(!(*fi).IsD()) (*fi).Q() = Distortion<CMeshO,false>::AngleDistortion(&*fi); } tri::Stat<CMeshO>::ComputePerFaceQualityDistribution(m.cm,distrib); minV = distrib.Percentile(0.05); maxV = distrib.Percentile(0.95); } break; case 5: { //TEXTURE Area Distortion float areaScaleVal, edgeScaleVal; if(m.hasDataMask(MeshModel::MM_WEDGTEXCOORD)) { Distortion<CMeshO,true>::MeshScalingFactor(m.cm, areaScaleVal,edgeScaleVal); for(fi=m.cm.face.begin();fi!=m.cm.face.end();++fi) if(!(*fi).IsD()) (*fi).Q() = Distortion<CMeshO,true>::AreaDistortion(&*fi,areaScaleVal); } else { Distortion<CMeshO,false>::MeshScalingFactor(m.cm, areaScaleVal,edgeScaleVal); for(fi=m.cm.face.begin();fi!=m.cm.face.end();++fi) if(!(*fi).IsD()) (*fi).Q() = Distortion<CMeshO,false>::AreaDistortion(&*fi,areaScaleVal); } tri::Stat<CMeshO>::ComputePerFaceQualityDistribution(m.cm,distrib); minV = distrib.Percentile(0.05); maxV = distrib.Percentile(0.95); } break; default: assert(0); } tri::UpdateColor<CMeshO>::FaceQualityRamp(m.cm,minV,maxV,false); break; } case CP_RANDOM_CONNECTED_COMPONENT: m.updateDataMask(MeshModel::MM_FACEFACETOPO); m.updateDataMask(MeshModel::MM_FACEMARK | MeshModel::MM_FACECOLOR); vcg::tri::UpdateColor<CMeshO>::FaceRandomConnectedComponent(m.cm); break; case CP_RANDOM_FACE: m.updateDataMask(MeshModel::MM_FACEFACETOPO); m.updateDataMask(MeshModel::MM_FACEMARK | MeshModel::MM_FACECOLOR); vcg::tri::UpdateColor<CMeshO>::MultiFaceRandom(m.cm); break; case CP_VERTEX_SMOOTH: { int iteration = par.getInt("iteration"); tri::Smooth<CMeshO>::VertexColorLaplacian(m.cm,iteration,false,cb); } break; case CP_FACE_SMOOTH: { m.updateDataMask(MeshModel::MM_FACEFACETOPO); int iteration = par.getInt("iteration"); tri::Smooth<CMeshO>::FaceColorLaplacian(m.cm,iteration,false,cb); } break; case CP_FACE_TO_VERTEX: m.updateDataMask(MeshModel::MM_VERTCOLOR); tri::UpdateColor<CMeshO>::VertexFromFace(m.cm); break; case CP_VERTEX_TO_FACE: m.updateDataMask(MeshModel::MM_FACECOLOR); tri::UpdateColor<CMeshO>::FaceFromVertex(m.cm); break; case CP_TEXTURE_TO_VERTEX: { m.updateDataMask(MeshModel::MM_VERTCOLOR); if(!HasPerWedgeTexCoord(m.cm)) break; CMeshO::FaceIterator fi; QImage tex(m.cm.textures[0].c_str()); for(fi=m.cm.face.begin();fi!=m.cm.face.end();++fi) if(!(*fi).IsD()) { for (int i=0; i<3; i++) { // note the trick for getting only the fractional part of the uv with the correct wrapping (e.g. 1.5 -> 0.5 and -0.3 -> 0.7) vcg::Point2f newcoord((*fi).WT(i).P().X()-floor((*fi).WT(i).P().X()),(*fi).WT(i).P().Y()-floor((*fi).WT(i).P().Y())); QRgb val = tex.pixel(newcoord[0]*tex.width(),(1-newcoord[1])*tex.height()-1); (*fi).V(i)->C().SetRGB(qRed(val),qGreen(val),qBlue(val)); } } } break; } return true; }
bool AlignTools::setupThenAlign(MeshModel &/*mm*/, RichParameterSet & par) { //mesh that wont move MeshModel *stuckModel = par.getMesh(StuckMesh); PickedPoints *stuckPickedPoints = 0; //mesh that will move MeshModel *modelToMove = par.getMesh(MeshToMove); PickedPoints *modelToMovePickedPoints = 0; bool useMarkers = par.getBool(UseMarkers); if(NULL == stuckModel || NULL == modelToMove) { qDebug() << "one of the input meshes to filter align was null"; return false; } //if we are going to use the markers try to load them if(useMarkers){ //first try to get points from memory if(vcg::tri::HasPerMeshAttribute(stuckModel->cm, PickedPoints::Key) ) { CMeshO::PerMeshAttributeHandle<PickedPoints*> ppHandle = vcg::tri::Allocator<CMeshO>::GetPerMeshAttribute<PickedPoints*>(stuckModel->cm, PickedPoints::Key); stuckPickedPoints = ppHandle(); if(NULL == stuckPickedPoints){ qDebug() << "problem casting to picked points"; return false; } } else { //now try to load them from a file QString ppFileName = PickedPoints::getSuggestedPickedPointsFileName(*stuckModel); QFileInfo file(ppFileName); if(file.exists()) { stuckPickedPoints = new PickedPoints(); bool success = stuckPickedPoints->open(ppFileName); if(!success){ qDebug() << "problem loading stuck picked points from a file"; return false; } } else { qDebug() << "stuck points file didnt exist: " << ppFileName; //Log(GLLogStream::WARNING, "No points were found for the Stuck mesh."); return false; } } if(vcg::tri::HasPerMeshAttribute(modelToMove->cm, PickedPoints::Key) ) { CMeshO::PerMeshAttributeHandle<PickedPoints*> ppHandle = vcg::tri::Allocator<CMeshO>::GetPerMeshAttribute<PickedPoints*>(modelToMove->cm, PickedPoints::Key); modelToMovePickedPoints = ppHandle(); if(NULL == modelToMovePickedPoints){ qDebug() << "problem casting to picked poitns"; return false; } } else { QString ppFileName = PickedPoints::getSuggestedPickedPointsFileName(*modelToMove); QFileInfo file(ppFileName); if(file.exists()) { modelToMovePickedPoints = new PickedPoints(); bool success = modelToMovePickedPoints->open(ppFileName); if(!success){ qDebug() << "failed to load modelToMove pick points"; return false; } } else { qDebug() << "model to move points file didnt exist: " << ppFileName; //Log(GLLogStream::WARNING, "No points were found for the mesh to move."); return false; } } } bool result = AlignTools::align(stuckModel, stuckPickedPoints, modelToMove, modelToMovePickedPoints, 0, par); return result; }
// The Real Core Function doing the actual mesh processing. // Move Vertex of a random quantity bool FilterMutualInfoPlugin::applyFilter(QAction *action, MeshDocument &md, RichParameterSet & par, vcg::CallBackPos *cb) { QTime filterTime; filterTime.start(); float thresDiff=par.getFloat("Threshold for refinement convergence"); std::vector<vcg::Point3f> myVec; int leap=(int)((float)md.mm()->cm.vn/1000.0f); CMeshO::VertexIterator vi; for(int i=0;i<=md.mm()->cm.vn;i=i+leap) { myVec.push_back(md.mm()->cm.vert[i].P()); } std::vector<vcg::Shotf> oldShots; for (int r=0; r<md.rasterList.size();r++) { oldShots.push_back(md.rasterList[r]->shot); } Log(0,"Sampled has %i vertices",myVec.size()); std::vector<SubGraph> Graphs; /// Preliminary singular alignment using classic MI switch(ID(action)) { case FP_IMAGE_GLOBALIGN : /// Building of the graph of images if (md.rasterList.size()==0) { Log(0, "You need a Raster Model to apply this filter!"); return false; } this->glContext->makeCurrent(); this->initGL(); if (par.getBool("Pre-alignment")) { preAlignment(md, par, cb); } if (par.getInt("Max number of refinement steps")!=0) { Graphs=buildGraph(md); Log(0, "BuildGraph completed"); for (int i=0; i<par.getInt("Max number of refinement steps"); i++) { AlignGlobal(md, Graphs); float diff=calcShotsDifference(md,oldShots,myVec); Log(0, "AlignGlobal %d of %d completed, average improvement %f pixels",i+1,par.getInt("Max number of refinement steps"),diff); if (diff<thresDiff) break; oldShots.clear(); for (int r=0; r<md.rasterList.size();r++) { oldShots.push_back(md.rasterList[r]->shot); } } } this->glContext->doneCurrent(); Log(0, "Done!"); break; default : assert(0); } Log(0,"Filter completed in %i sec",(int)((float)filterTime.elapsed()/1000.0f)); return true; }
//write to an opened file the attribute of object entity QString IORenderman::convertObject(int currentFrame, QString destDir, MeshModel* m,const RichParameterSet &par, QStringList* textureList)//, ObjValues* dummyValues) { QString name = "meshF" + QString::number(currentFrame) + "O" + QString::number(numberOfDummies) + ".rib"; numberOfDummies++; FILE *fout = fopen(qPrintable(destDir + QDir::separator() + name),"wb"); if(fout == NULL) { this->errorMessage = "Impossible to create the file: " + destDir + QDir::separator() + name; return ""; } fprintf(fout,"AttributeBegin\n"); //name fprintf(fout,"Attribute \"identifier\" \"string name\" [ \"meshlabMesh\" ]\n"); //modify the transformation matrix vcg::Matrix44f scaleMatrix = vcg::Matrix44f::Identity(); float dummyX = objectBound[1] - objectBound[0]; float dummyY = objectBound[3] - objectBound[2]; float dummyZ = objectBound[5] - objectBound[4]; //autoscale float scale = 1.0; if(par.getBool("Autoscale")) { float ratioX = dummyX / m->cm.trBB().DimX(); float ratioY = dummyY / m->cm.trBB().DimY(); float ratioZ = dummyZ / m->cm.trBB().DimZ(); scale = std::min<float>(ratioX, std::min<float>(ratioY, ratioZ)); //scale factor is min ratio scaleMatrix.SetScale(scale,scale,scale); } //center mesh vcg::Point3f c = m->cm.trBB().Center(); vcg::Matrix44f translateBBMatrix; translateBBMatrix.SetTranslate(-c[0],-c[1],-c[2]); //align float dx = 0.0, dy = 0.0, dz = 0.0; switch(par.getEnum("AlignX")) { case IORenderman::TOP: dx = (dummyX - m->cm.trBB().DimX() * scale) / 2; break; case IORenderman::BOTTOM: dx = -(dummyX - m->cm.trBB().DimX() * scale) / 2; break; case IORenderman::CENTER: break; //is already center } switch(par.getEnum("AlignY")) { case IORenderman::TOP: dy = (dummyY - m->cm.trBB().DimY() * scale) / 2; break; case IORenderman::BOTTOM: dy = -(dummyY - m->cm.trBB().DimY() * scale) / 2; break; case IORenderman::CENTER: break; //is already center } switch(par.getEnum("AlignZ")) { case IORenderman::TOP: dz = (dummyZ - m->cm.trBB().DimZ() * scale) / 2; break; case IORenderman::BOTTOM: dz = -(dummyZ - m->cm.trBB().DimZ() * scale) / 2; break; case IORenderman::CENTER: break; //is already center } vcg::Matrix44f alignMatrix; alignMatrix = alignMatrix.SetTranslate(dx,dy,dz); vcg::Matrix44f templateMatrix = transfMatrixStack.top(); //by default is identity vcg::Matrix44f result = templateMatrix * alignMatrix * scaleMatrix * translateBBMatrix; //write transformation matrix (after transpose it) writeMatrix(fout, &result); //write bounding box fprintf(fout,"Bound %g %g %g %g %g %g\n", m->cm.trBB().min.X(), m->cm.trBB().max.X(), m->cm.trBB().min.Y(), m->cm.trBB().max.Y(), m->cm.trBB().min.Z(), m->cm.trBB().max.Z()); //force the shading interpolation to smooth fprintf(fout,"ShadingInterpolation \"smooth\"\n"); //shader fprintf(fout,"%s\n",qPrintable(surfaceShaderStack.top())); //texture mapping (are TexCoord needed for texture mapping?) if(!textureList->empty() > 0 && (m->cm.HasPerWedgeTexCoord() || m->cHasPerVertexTexCoord(m))) { //multi-texture don't work!I need ad-hoc shader and to read the texture index for vertex.. //foreach(QString textureName, *textureList) { //read only the first texture QString textureName = QFileInfo(textureList->first()).completeBaseName(); fprintf(fout,"Surface \"paintedplastic\" \"Kd\" 1.0 \"Ks\" 0.0 \"texturename\" [\"%s.tx\"]\n", qPrintable(textureName)); } //geometry QString filename = "geometry.rib"; fprintf(fout,"ReadArchive \"%s\"\n", qPrintable(filename)); if(!convertedGeometry) { //make the conversion only once convertedGeometry = true; QString geometryDest = destDir + QDir::separator() + filename; int res = vcg::tri::io::ExporterRIB<CMeshO>::Save(m->cm, qPrintable(geometryDest), vcg::tri::io::Mask::IOM_ALL, false, cb); if(res != vcg::tri::io::ExporterRIB<CMeshO>::E_NOERROR) { fclose(fout); this->errorMessage = QString(vcg::tri::io::ExporterRIB<CMeshO>::ErrorMsg(res)); return ""; } else Log(GLLogStream::FILTER,"Successfully converted mesh"); } fprintf(fout,"AttributeEnd\n"); fclose(fout); return name; }
// The Real Core Function doing the actual mesh processing. bool FilterFunctionPlugin::applyFilter(QAction *filter, MeshDocument &md, RichParameterSet & par, vcg::CallBackPos *cb) { if(this->getClass(filter) == MeshFilterInterface::MeshCreation) md.addNewMesh("",this->filterName(ID(filter))); MeshModel &m=*(md.mm()); Q_UNUSED(cb); switch(ID(filter)) { case FF_VERT_SELECTION : { std::string expr = par.getString("condSelect").toStdString(); // muparser initialization and explicitely define parser variables Parser p; setPerVertexVariables(p,m.cm); // set expression inserted by user as string (required by muparser) p.SetExpr(expr); int numvert = 0; time_t start = clock(); // every parser variables is related to vertex coord and attributes. CMeshO::VertexIterator vi; for(vi = m.cm.vert.begin(); vi != m.cm.vert.end(); ++vi)if(!(*vi).IsD()) { setAttributes(vi,m.cm); bool selected = false; // use parser to evaluate boolean function specified above // in case of fail, error dialog contains details of parser's error try { selected = p.Eval(); } catch(Parser::exception_type &e) { errorMessage = e.GetMsg().c_str(); return false; } // set vertex as selected or clear selection if(selected) { (*vi).SetS(); numvert++; } else (*vi).ClearS(); } // strict face selection if(par.getBool("strictSelect")) tri::UpdateSelection<CMeshO>::FaceFromVertexStrict(m.cm); else tri::UpdateSelection<CMeshO>::FaceFromVertexLoose(m.cm); // if succeded log stream contains number of vertices and time elapsed Log( "selected %d vertices in %.2f sec.", numvert, (clock() - start) / (float) CLOCKS_PER_SEC); return true; } break; case FF_FACE_SELECTION : { QString select = par.getString("condSelect"); // muparser initialization and explicitely define parser variables Parser p; setPerFaceVariables(p,m.cm); // set expression inserted by user as string (required by muparser) p.SetExpr(select.toStdString()); int numface = 0; time_t start = clock(); // every parser variables is related to face attributes. CMeshO::FaceIterator fi; for(fi = m.cm.face.begin(); fi != m.cm.face.end(); ++fi)if(!(*fi).IsD()) { setAttributes(fi,m.cm); bool selected = false; // use parser to evaluate boolean function specified above // in case of fail, error dialog contains details of parser's error try { selected = p.Eval(); } catch(Parser::exception_type &e) { errorMessage = e.GetMsg().c_str(); return false; } // set face as selected or clear selection if(selected) { (*fi).SetS(); numface++; } else (*fi).ClearS(); } // if succeded log stream contains number of vertices and time elapsed Log( "selected %d faces in %.2f sec.", numface, (clock() - start) / (float) CLOCKS_PER_SEC); return true; } break; case FF_GEOM_FUNC : case FF_VERT_COLOR: case FF_VERT_NORMAL: { std::string func_x,func_y,func_z,func_a; // FF_VERT_COLOR : x = r, y = g, z = b // FF_VERT_NORMAL : x = r, y = g, z = b func_x = par.getString("x").toStdString(); func_y = par.getString("y").toStdString(); func_z = par.getString("z").toStdString(); if(ID(filter) == FF_VERT_COLOR) func_a = par.getString("a").toStdString(); // muparser initialization and explicitely define parser variables // function for x,y and z must use different parser and variables Parser p1,p2,p3,p4; setPerVertexVariables(p1,m.cm); setPerVertexVariables(p2,m.cm); setPerVertexVariables(p3,m.cm); setPerVertexVariables(p4,m.cm); p1.SetExpr(func_x); p2.SetExpr(func_y); p3.SetExpr(func_z); p4.SetExpr(func_a); double newx=0,newy=0,newz=0,newa=255; errorMessage = ""; time_t start = clock(); // every parser variables is related to vertex coord and attributes. CMeshO::VertexIterator vi; for(vi = m.cm.vert.begin(); vi != m.cm.vert.end(); ++vi)if(!(*vi).IsD()) { setAttributes(vi,m.cm); // every function is evaluated by different parser. // errorMessage dialog contains errors for func x, func y and func z try { newx = p1.Eval(); } catch(Parser::exception_type &e) { showParserError("1st func : ",e); } try { newy = p2.Eval(); } catch(Parser::exception_type &e) { showParserError("2nd func : ",e); } try { newz = p3.Eval(); } catch(Parser::exception_type &e) { showParserError("3rd func : ",e); } if(ID(filter) == FF_VERT_COLOR) { try { newa = p4.Eval(); } catch(Parser::exception_type &e) { showParserError("4th func : ",e); } } if(errorMessage != "") return false; if(ID(filter) == FF_GEOM_FUNC) // set new vertex coord for this iteration (*vi).P() = Point3f(newx,newy,newz); if(ID(filter) == FF_VERT_COLOR) // set new color for this iteration (*vi).C() = Color4b(newx,newy,newz,newa); if(ID(filter) == FF_VERT_NORMAL) // set new color for this iteration (*vi).N() = Point3f(newx,newy,newz); } if(ID(filter) == FF_GEOM_FUNC) { // update bounding box, normalize normals tri::UpdateNormals<CMeshO>::PerVertexNormalizedPerFace(m.cm); tri::UpdateNormals<CMeshO>::NormalizeFace(m.cm); tri::UpdateBounding<CMeshO>::Box(m.cm); } // if succeded log stream contains number of vertices processed and time elapsed Log( "%d vertices processed in %.2f sec.", m.cm.vn, (clock() - start) / (float) CLOCKS_PER_SEC); return true; } break; case FF_VERT_QUALITY: { std::string func_q = par.getString("q").toStdString(); m.updateDataMask(MeshModel::MM_VERTQUALITY); // muparser initialization and define custom variables Parser p; setPerVertexVariables(p,m.cm); // set expression to calc with parser p.SetExpr(func_q); // every parser variables is related to vertex coord and attributes. time_t start = clock(); CMeshO::VertexIterator vi; for(vi = m.cm.vert.begin(); vi != m.cm.vert.end(); ++vi) if(!(*vi).IsD()) { setAttributes(vi,m.cm); // use parser to evaluate function specified above // in case of fail, errorMessage dialog contains details of parser's error try { (*vi).Q() = p.Eval(); } catch(Parser::exception_type &e) { errorMessage = e.GetMsg().c_str(); return false; } } // normalize quality with values in [0..1] if(par.getBool("normalize")) tri::UpdateQuality<CMeshO>::VertexNormalize(m.cm); // map quality into per-vertex color if(par.getBool("map")) tri::UpdateColor<CMeshO>::VertexQualityRamp(m.cm); // if succeded log stream contains number of vertices and time elapsed Log( "%d vertices processed in %.2f sec.", m.cm.vn, (clock() - start) / (float) CLOCKS_PER_SEC); return true; } break; case FF_FACE_COLOR: { std::string func_r = par.getString("r").toStdString(); std::string func_g = par.getString("g").toStdString(); std::string func_b = par.getString("b").toStdString(); std::string func_a = par.getString("a").toStdString(); // muparser initialization and explicitely define parser variables // every function must uses own parser and variables Parser p1,p2,p3,p4; setPerFaceVariables(p1,m.cm); setPerFaceVariables(p2,m.cm); setPerFaceVariables(p3,m.cm); setPerFaceVariables(p4,m.cm); p1.SetExpr(func_r); p2.SetExpr(func_g); p3.SetExpr(func_b); p4.SetExpr(func_a); // RGB is related to every face CMeshO::FaceIterator fi; double newr=0,newg=0,newb=0,newa=255; errorMessage = ""; time_t start = clock(); // every parser variables is related to face attributes. for(fi = m.cm.face.begin(); fi != m.cm.face.end(); ++fi)if(!(*fi).IsD()) { setAttributes(fi,m.cm); // evaluate functions to generate new color // in case of fail, error dialog contains details of parser's error try { newr = p1.Eval(); } catch(Parser::exception_type &e) { showParserError("func r: ",e); } try { newg = p2.Eval(); } catch(Parser::exception_type &e) { showParserError("func g: ",e); } try { newb = p3.Eval(); } catch(Parser::exception_type &e) { showParserError("func b: ",e); } try { newa = p4.Eval(); } catch(Parser::exception_type &e) { showParserError("func a: ",e); } if(errorMessage != "") return false; // set new color for this iteration (*fi).C() = Color4b(newr,newg,newb,newa); } // if succeded log stream contains number of vertices processed and time elapsed Log( "%d faces processed in %.2f sec.", m.cm.fn, (clock() - start) / (float) CLOCKS_PER_SEC); return true; } break; case FF_FACE_QUALITY: { std::string func_q = par.getString("q").toStdString(); m.updateDataMask(MeshModel::MM_FACEQUALITY); // muparser initialization and define custom variables Parser pf; setPerFaceVariables(pf,m.cm); // set expression to calc with parser pf.SetExpr(func_q); time_t start = clock(); errorMessage = ""; // every parser variables is related to face attributes. CMeshO::FaceIterator fi; for(fi = m.cm.face.begin(); fi != m.cm.face.end(); ++fi)if(!(*fi).IsD()) { setAttributes(fi,m.cm); // evaluate functions to generate new quality // in case of fail, error dialog contains details of parser's error try { (*fi).Q() = pf.Eval(); } catch(Parser::exception_type &e) { showParserError("func q: ",e); } if(errorMessage != "") return false; } // normalize quality with values in [0..1] if(par.getBool("normalize")) tri::UpdateQuality<CMeshO>::FaceNormalize(m.cm); // map quality into per-vertex color if(par.getBool("map")) tri::UpdateColor<CMeshO>::FaceQualityRamp(m.cm); // if succeded log stream contains number of faces processed and time elapsed Log( "%d faces processed in %.2f sec.", m.cm.fn, (clock() - start) / (float) CLOCKS_PER_SEC); return true; } break; case FF_DEF_VERT_ATTRIB : { std::string name = par.getString("name").toStdString(); std::string expr = par.getString("expr").toStdString(); // add per-vertex attribute with type float and name specified by user CMeshO::PerVertexAttributeHandle<float> h; if(tri::HasPerVertexAttribute(m.cm,name)) { h = tri::Allocator<CMeshO>::GetPerVertexAttribute<float>(m.cm, name); if(!tri::Allocator<CMeshO>::IsValidHandle<float>(m.cm,h)) { errorMessage = "attribute already exists with a different type"; return false; } } else h = tri::Allocator<CMeshO>::AddPerVertexAttribute<float> (m.cm,name); std::vector<std::string> AllVertexAttribName; tri::Allocator<CMeshO>::GetAllPerVertexAttribute< float >(m.cm,AllVertexAttribName); qDebug("Now mesh has %i vertex float attribute",AllVertexAttribName.size()); Parser p; setPerVertexVariables(p,m.cm); p.SetExpr(expr); time_t start = clock(); // perform calculation of attribute's value with function specified by user CMeshO::VertexIterator vi; for(vi = m.cm.vert.begin(); vi != m.cm.vert.end(); ++vi)if(!(*vi).IsD()) { setAttributes(vi,m.cm); // add new user-defined attribute try { h[vi] = p.Eval(); } catch(Parser::exception_type &e) { errorMessage = e.GetMsg().c_str(); return false; } } // add string, double and handler to vector. // vectors keep tracks of new attributes and let muparser use explicit variables // it's possibile to use custom attributes in other filters v_attrNames.push_back(name); v_attrValue.push_back(0); v_handlers.push_back(h); // if succeded log stream contains number of vertices processed and time elapsed Log( "%d vertices processed in %.2f sec.", m.cm.vn, (clock() - start) / (float) CLOCKS_PER_SEC); return true; } break; case FF_DEF_FACE_ATTRIB : { std::string name = par.getString("name").toStdString(); std::string expr = par.getString("expr").toStdString(); // add per-face attribute with type float and name specified by user // add per-vertex attribute with type float and name specified by user CMeshO::PerFaceAttributeHandle<float> h; if(tri::HasPerFaceAttribute(m.cm,name)) { h = tri::Allocator<CMeshO>::GetPerFaceAttribute<float>(m.cm, name); if(!tri::Allocator<CMeshO>::IsValidHandle<float>(m.cm,h)) { errorMessage = "attribute already exists with a different type"; return false; } } else h = tri::Allocator<CMeshO>::AddPerFaceAttribute<float> (m.cm,name); Parser p; setPerFaceVariables(p,m.cm); p.SetExpr(expr); time_t start = clock(); // every parser variables is related to face attributes. CMeshO::FaceIterator fi; for(fi = m.cm.face.begin(); fi != m.cm.face.end(); ++fi)if(!(*fi).IsD()) { setAttributes(fi,m.cm); // add new user-defined attribute try { h[fi] = p.Eval(); } catch(Parser::exception_type &e) { errorMessage = e.GetMsg().c_str(); return false; } } // // add string, double and handler to vector. // // vectors keep tracks of new attributes and let muparser use explicit variables // // it's possibile to use custom attributes in other filters // f_attrNames.push_back(name); // f_attrValue.push_back(0); // fhandlers.push_back(h); // if succeded log stream contains number of vertices processed and time elapsed Log( "%d faces processed in %.2f sec.", m.cm.fn, (clock() - start) / (float) CLOCKS_PER_SEC); return true; } break; case FF_GRID : { // obtain parameters to generate 2D Grid int w = par.getInt("numVertX"); int h = par.getInt("numVertY"); float wl = par.getFloat("absScaleX"); float hl = par.getFloat("absScaleY"); if(w <= 0 || h <= 0) { errorMessage = "number of vertices must be positive"; return false; } // use Grid function to generate Grid std::vector<float> data(w*h,0); tri::Grid<CMeshO>(m.cm, w, h, wl, hl, &data[0]); // if "centered on origin" is checked than move generated Grid in (0,0,0) if(par.getBool("center")) { // move x and y double halfw = double(w-1)/2; double halfh = double(h-1)/2; double wld = wl/double(w); double hld = hl/float(h); CMeshO::VertexIterator vi; for(vi = m.cm.vert.begin(); vi != m.cm.vert.end(); ++vi) { (*vi).P()[0] = (*vi).P()[0] - (wld * halfw); (*vi).P()[1] = (*vi).P()[1] - (hld * halfh); } } // update bounding box, normals Matrix44f rot; rot.SetRotateDeg(180,Point3f(0,1,0)); tri::UpdatePosition<CMeshO>::Matrix(m.cm,rot,false); tri::UpdateNormals<CMeshO>::PerVertexNormalizedPerFace(m.cm); tri::UpdateNormals<CMeshO>::NormalizeFace(m.cm); tri::UpdateBounding<CMeshO>::Box(m.cm); return true; } break; case FF_ISOSURFACE : { SimpleVolume<SimpleVoxel> volume; typedef vcg::tri::TrivialWalker<CMeshO, SimpleVolume<SimpleVoxel> > MyWalker; typedef vcg::tri::MarchingCubes<CMeshO, MyWalker> MyMarchingCubes; MyWalker walker; Box3d rbb; rbb.min[0]=par.getFloat("minX"); rbb.min[1]=par.getFloat("minY"); rbb.min[2]=par.getFloat("minZ"); rbb.max[0]=par.getFloat("maxX"); rbb.max[1]=par.getFloat("maxY"); rbb.max[2]=par.getFloat("maxZ"); double step=par.getFloat("voxelSize"); Point3i siz= Point3i::Construct((rbb.max-rbb.min)*(1.0/step)); Parser p; double x,y,z; p.DefineVar("x", &x); p.DefineVar("y", &y); p.DefineVar("z", &z); std::string expr = par.getString("expr").toStdString(); p.SetExpr(expr); Log("Filling a Volume of %i %i %i",siz[0],siz[1],siz[2]); volume.Init(siz); for(double i=0;i<siz[0];i++) for(double j=0;j<siz[1];j++) for(double k=0;k<siz[2];k++) { x = rbb.min[0]+step*i; y = rbb.min[1]+step*j; z = rbb.min[2]+step*k; try { volume.Val(i,j,k)=p.Eval(); } catch(Parser::exception_type &e) { errorMessage = e.GetMsg().c_str(); return false; } } // MARCHING CUBES Log("[MARCHING CUBES] Building mesh..."); MyMarchingCubes mc(m.cm, walker); walker.BuildMesh<MyMarchingCubes>(m.cm, volume, mc, 0); Matrix44f tr; tr.SetIdentity(); tr.SetTranslate(rbb.min[0],rbb.min[1],rbb.min[2]); Matrix44f sc; sc.SetIdentity(); sc.SetScale(step,step,step); tr=tr*sc; tri::UpdatePosition<CMeshO>::Matrix(m.cm,tr); tri::UpdateNormals<CMeshO>::PerVertexNormalizedPerFace(m.cm); tri::UpdateBounding<CMeshO>::Box(m.cm); // updates bounding box return true; } break; case FF_REFINE : { std::string condSelect = par.getString("condSelect").toStdString(); std::string expr1 = par.getString("x").toStdString(); std::string expr2 = par.getString("y").toStdString(); std::string expr3 = par.getString("z").toStdString(); bool errorMidPoint = false; bool errorEdgePred = false; std::string msg = ""; // check parsing errors while creating two func obj // display error message MidPointCustom<CMeshO> mid = MidPointCustom<CMeshO>(m.cm,expr1,expr2,expr3,errorMidPoint,msg); CustomEdge<CMeshO> edge = CustomEdge<CMeshO>(condSelect,errorEdgePred,msg); if(errorMidPoint || errorEdgePred) { errorMessage = msg.c_str(); return false; } // Refine current mesh. // Only edge specified with CustomEdge pred are selected // and the new vertex is choosen with MidPointCustom created above RefineE<CMeshO, MidPointCustom<CMeshO>, CustomEdge<CMeshO> > (m.cm, mid, edge, false, cb); m.clearDataMask( MeshModel::MM_VERTMARK); vcg::tri::UpdateNormals<CMeshO>::PerVertexNormalizedPerFace(m.cm); return true; } break; default : assert (0); } return false; }
// The Real Core Function doing the actual mesh processing. // Run mesh optimization bool TriOptimizePlugin::applyFilter(QAction *filter, MeshDocument &md, RichParameterSet & par, vcg::CallBackPos *cb) { MeshModel &m=*(md.mm()); float limit = -std::numeric_limits<float>::epsilon(); if (ID(filter) == FP_CURVATURE_EDGE_FLIP) { int delvert = tri::Clean<CMeshO>::RemoveUnreferencedVertex(m.cm); if (delvert) Log( "Pre-Curvature Cleaning: Removed %d unreferenced vertices", delvert); tri::Allocator<CMeshO>::CompactVertexVector(m.cm); tri::Allocator<CMeshO>::CompactFaceVector(m.cm); m.updateDataMask(MeshModel::MM_FACEFACETOPO); vcg::tri::UpdateFlags<CMeshO>::FaceBorderFromFF(m.cm); if ( tri::Clean<CMeshO>::CountNonManifoldEdgeFF(m.cm) >0) { errorMessage = "Mesh has some not 2-manifold faces, edge flips requires manifoldness"; return false; // can't continue, mesh can't be processed } vcg::tri::PlanarEdgeFlipParameter pp; vcg::LocalOptimization<CMeshO> optimiz(m.cm,&pp); float pthr = par.getFloat("pthreshold"); time_t start = clock(); if (par.getBool("selection")) { // Mark not writable un-selected faces for (CMeshO::FaceIterator fi = m.cm.face.begin(); fi != m.cm.face.end(); ++fi) { if (!(*fi).IsS()) (*fi).ClearW(); else (*fi).SetW(); } // select vertices with at least one incident face selected tri::UpdateSelection<CMeshO>::VertexFromFaceLoose(m.cm); // Mark not writable un-selected vertices for (CMeshO::VertexIterator vi = m.cm.vert.begin(); vi != m.cm.vert.end(); ++vi){ if (!(*vi).IsS()) (*vi).ClearW(); else (*vi).SetW(); } } // VF adjacency needed for edge flips based on vertex curvature vcg::tri::UpdateTopology<CMeshO>::VertexFace(m.cm); vcg::tri::UpdateTopology<CMeshO>::TestVertexFace(m.cm); int metric = par.getEnum("curvtype"); pp.CoplanarAngleThresholdDeg = pthr; switch (metric) { case 0: optimiz.Init<MeanCEFlip>(); break; case 1: optimiz.Init<NSMCEFlip>(); break; case 2: optimiz.Init<AbsCEFlip>(); break; } // stop when flips become harmful optimiz.SetTargetMetric(limit); //optimiz.SetTargetOperations(10); optimiz.DoOptimization(); optimiz.h.clear(); Log( "%d curvature edge flips performed in %.2f sec.", optimiz.nPerfmormedOps, (clock() - start) / (float) CLOCKS_PER_SEC); } if (ID(filter) == FP_PLANAR_EDGE_FLIP) { if ( tri::Clean<CMeshO>::CountNonManifoldEdgeFF(m.cm) >0) { errorMessage = "Mesh has some not 2-manifold faces, edge flips requires manifoldness"; return false; // can't continue, mesh can't be processed } bool selection = par.getBool("selection"); tri::Allocator<CMeshO>::CompactVertexVector(m.cm); tri::Allocator<CMeshO>::CompactFaceVector(m.cm); vcg::tri::UpdateTopology<CMeshO>::FaceFace(m.cm); vcg::tri::UpdateFlags<CMeshO>::FaceBorderFromFF(m.cm); vcg::tri::PlanarEdgeFlipParameter pp; vcg::LocalOptimization<CMeshO> optimiz(m.cm,&pp); float pthr = par.getFloat("pthreshold"); pp.CoplanarAngleThresholdDeg=pthr; time_t start = clock(); int metric = par.getEnum("planartype"); switch (metric) { case 0: optimiz.Init<QEFlip>(); break; case 1: optimiz.Init<QRadiiEFlip>(); break; case 2: optimiz.Init<QMeanRatioEFlip>(); break; case 3: optimiz.Init<MyTriEFlip>(); break; case 4: optimiz.Init<MyTopoEFlip>(); break; } // stop when flips become harmful optimiz.SetTargetMetric(limit); optimiz.DoOptimization(); optimiz.h.clear(); Log( "%d planar edge flips performed in %.2f sec.", optimiz.nPerfmormedOps, (clock() - start) / (float) CLOCKS_PER_SEC); int iternum = par.getInt("iterations"); tri::Smooth<CMeshO>::VertexCoordPlanarLaplacian(m.cm, iternum, 0.0001f, selection,cb); vcg::tri::UpdateNormal<CMeshO>::PerVertexNormalizedPerFace(m.cm); if (par.getBool("selection")) { // Clear Writable flags (faces) CMeshO::FaceIterator fi; for (fi = m.cm.face.begin(); fi != m.cm.face.end(); ++fi) if (!(*fi).IsD()) (*fi).SetW(); // Clear Writable flags (vertices) CMeshO::VertexIterator vi; for (vi = m.cm.vert.begin(); vi != m.cm.vert.end(); ++vi) if (!(*vi).IsD()) (*vi).SetW(); // restore "default" selection for vertices vcg::tri::UpdateSelection<CMeshO>::VertexFromFaceStrict(m.cm); } } if (ID(filter) == FP_NEAR_LAPLACIAN_SMOOTH) { bool selection = par.getBool("selection"); if (selection) vcg::tri::UpdateSelection<CMeshO>::VertexFromFaceStrict(m.cm); int iternum = par.getInt("iterations"); float dthreshold = par.getFloat("AngleDeg"); tri::Smooth<CMeshO>::VertexCoordPlanarLaplacian(m.cm, iternum, math::ToRad(dthreshold), selection,cb); tri::UpdateNormal<CMeshO>::PerVertexNormalizedPerFace(m.cm); } return true; }
// The Real Core Function doing the actual mesh processing. bool FilterAutoalign::applyFilter(QAction *filter, MeshDocument &md, RichParameterSet & par, vcg::CallBackPos *cb) { switch(ID(filter)) { case FP_ALIGN_4PCS : { MeshModel *fixMesh= par.getMesh("fixMesh"); MeshModel *movMesh= par.getMesh("movMesh"); MeshModel *sampleMesh= 0; bool showSample = par.getBool("showSample"); if(showSample) sampleMesh = md.addOrGetMesh("sample","sample",false, RenderMode(vcg::GLW::DMPoints)); tri::UpdateNormal<CMeshO>::NormalizePerVertex(fixMesh->cm); tri::UpdateNormal<CMeshO>::NormalizePerVertex(movMesh->cm); tri::Clean<CMeshO>::RemoveUnreferencedVertex(fixMesh->cm); tri::Clean<CMeshO>::RemoveUnreferencedVertex(movMesh->cm); tri::Allocator<CMeshO>::CompactEveryVector(fixMesh->cm); tri::Allocator<CMeshO>::CompactEveryVector(movMesh->cm); fixMesh->updateDataMask(MeshModel::MM_VERTMARK); movMesh->updateDataMask(MeshModel::MM_VERTMARK); vcg::tri::FourPCS<CMeshO> fpcs; fpcs.par.Default(); fpcs.par.overlap = par.getFloat("overlap"); fpcs.par.sampleNumP = par.getInt("sampleNum"); fpcs.par.deltaPerc = par.getFloat("tolerance"); fpcs.par.seed = par.getInt("randSeed"); fpcs.Init(movMesh->cm,fixMesh->cm); Matrix44m Tr; bool res = fpcs.Align(Tr,cb); if(res) { Log("4PCS Completed, radius %f",fpcs.par.samplingRadius); Log("Tested %i candidate, best score was %i\n",fpcs.U.size(),fpcs.U[fpcs.iwinner].score); Log("Estimated overlap is now %f \n",fpcs.par.overlap); Log("Init %5.0f Coplanar Search %5.0f",fpcs.stat.init(),fpcs.stat.select()); Log("findCongruent %5.0f testAlignment %5.0f",fpcs.stat.findCongruent(),fpcs.stat.testAlignment()); movMesh->cm.Tr = Tr; if(showSample) { sampleMesh->cm.Clear(); for(size_t i=0;i<fpcs.subsetQ.size();++i) tri::Allocator<CMeshO>::AddVertex(sampleMesh->cm, fpcs.subsetQ[i]->P(), fpcs.subsetQ[i]->N()); tri::UpdateBounding<CMeshO>::Box(sampleMesh->cm); } } else Log("4PCS Failed"); } break; case FP_BEST_ROTATION : { MeshModel *fixMesh= par.getMesh("fixMesh"); MeshModel *movMesh= par.getMesh("movMesh"); int searchRange = par.getInt("searchRange"); int rotNum = par.getInt("RotationNumber"); int gridSize = par.getInt("gridSize"); int sampleSize = par.getInt("sampleSize"); MeshModel *sample=md.addOrGetMesh("sample", "sample",false); MeshModel *occ=md.addOrGetMesh("occ", "occ",false); tri::Guess<Scalarm> GG; std::vector<tri::Guess<Scalarm>::Result> ResultVec; GG.pp.MatrixNum = rotNum; GG.pp.GridSize =gridSize; GG.pp.SampleNum = sampleSize; GG.Init<CMeshO>(fixMesh->cm, movMesh->cm); for(size_t i=0;i<GG.RotMVec.size();++i) { Point3m baseTran = GG.ComputeBaseTranslation(GG.RotMVec[i]); Point3m bestTran; int res = GG.SearchBestTranslation(GG.u[0],GG.RotMVec[i],searchRange,baseTran,bestTran); ResultVec.push_back(tri::Guess<Scalarm>::Result(GG.BuildResult(GG.RotMVec[i],baseTran,bestTran), res, i, bestTran)); } sort(ResultVec.begin(),ResultVec.end()); movMesh->cm.Tr.Import(ResultVec.back().m); tri::Build(sample->cm,GG.movVertBase); sample->cm.Tr.Import(ResultVec.back().m); qDebug("Result %i",ResultVec.back().score); GG.GenerateOccupancyMesh(occ->cm,0,ResultVec.back().m); occ->UpdateBoxAndNormals(); Log("Automatic Rough Alignment Tested %i rotations, best err was %i",GG.RotMVec.size(), ResultVec.back().score); } break; default: assert (0); } return true; }
// The Real Core Function doing the actual mesh processing. bool FilterCreate::applyFilter(QAction *filter, MeshDocument &md, RichParameterSet & par, CallBackPos * /*cb*/) { MeshModel & currM = *md.mm(); MeshModel* m; switch(ID(filter)) { case CR_TETRAHEDRON : m = md.addNewMesh("", this->filterName(ID(filter))); tri::Tetrahedron<CMeshO>(m->cm); break; case CR_ICOSAHEDRON: m = md.addNewMesh("", this->filterName(ID(filter))); tri::Icosahedron<CMeshO>(m->cm); break; case CR_DODECAHEDRON: m = md.addNewMesh("", this->filterName(ID(filter))); tri::Dodecahedron<CMeshO>(m->cm); m->updateDataMask(MeshModel::MM_POLYGONAL); break; case CR_OCTAHEDRON: m = md.addNewMesh("", this->filterName(ID(filter))); tri::Octahedron<CMeshO>(m->cm); break; case CR_ANNULUS: m = md.addNewMesh("", this->filterName(ID(filter))); tri::Annulus<CMeshO>(m->cm,par.getFloat("internalRadius"), par.getFloat("externalRadius"), par.getInt("sides")); break; case CR_TORUS: { m = md.addNewMesh("", this->filterName(ID(filter))); float hRadius=par.getFloat("hRadius"); float vRadius=par.getFloat("vRadius"); int hSubdiv=par.getInt("hSubdiv"); int vSubdiv=par.getInt("vSubdiv"); tri::Torus(m->cm,hRadius,vRadius,hSubdiv,vSubdiv); } break; case CR_FITPLANE: { Box3m selBox; //boundingbox of the selected vertices std::vector< Point3m > selected_pts; //copy of selected vertices, for plane fitting if (&currM == NULL) { errorMessage = "No mesh layer selected"; return false; } if (currM.cm.svn == 0 && currM.cm.sfn == 0) // if no selection, fail { errorMessage = "No selection"; return false; } m = md.addNewMesh("", "Fitted Plane"); if (currM.cm.svn == 0 || currM.cm.sfn != 0) { tri::UpdateSelection<CMeshO>::VertexClear(currM.cm); tri::UpdateSelection<CMeshO>::VertexFromFaceLoose(currM.cm); } Point3m Naccum = Point3m(0.0, 0.0, 0.0); for (CMeshO::VertexIterator vi = currM.cm.vert.begin(); vi != currM.cm.vert.end(); ++vi) if (!(*vi).IsD() && (*vi).IsS()) { Point3m p = (*vi).P(); selBox.Add(p); selected_pts.push_back(p); Naccum = Naccum + (*vi).N(); } Log("Using %i vertexes to build a fitting plane", int(selected_pts.size())); Plane3m plane; FitPlaneToPointSet(selected_pts, plane); plane.Normalize(); // check if normal of the interpolated plane is coherent with average normal of the used points, otherwise, flip // i do this because plane fitter does not take in account source noramls, and a fliped fit is terrible to see Naccum = (Naccum / (CMeshO::ScalarType)selected_pts.size()).Normalize(); if ((plane.Direction() * Naccum) < 0.0) plane.Set(-plane.Direction(), -plane.Offset()); float errorSum = 0; for (size_t i = 0; i < selected_pts.size(); ++i) errorSum += fabs(SignedDistancePlanePoint(plane, selected_pts[i])); Log("Fitting Plane avg error is %f", errorSum / float(selected_pts.size())); Log("Fitting Plane normal is [%f, %f, %f]", plane.Direction().X(), plane.Direction().Y(), plane.Direction().Z()); Log("Fitting Plane offset is %f", plane.Offset()); // find center of selection on plane Point3m centerP; for (size_t i = 0; i < selected_pts.size(); ++i) { centerP += plane.Projection(selected_pts[i]); } centerP /= selected_pts.size(); Log("center [%f, %f, %f]", centerP.X(), centerP.Y(), centerP.Z()); // find horizontal and vertical axis Point3m dirH, dirV; int orientation = par.getEnum("orientation"); if (orientation == 0) { if ((plane.Direction().X() <= plane.Direction().Y()) && (plane.Direction().X() <= plane.Direction().Z())) dirH = Point3m(1.0, 0.0, 0.0) ^ plane.Direction(); else if ((plane.Direction().Y() <= plane.Direction().X()) && (plane.Direction().Y() <= plane.Direction().Z())) dirH = Point3m(0.0, 1.0, 0.0) ^ plane.Direction(); else dirH = Point3m(0.0, 0.0, 1.0) ^ plane.Direction(); dirH.Normalize(); dirV = dirH ^ plane.Direction(); dirV.Normalize(); } else { Matrix33m cov; vector<Point3m> PtVec; for (size_t i = 0; i < selected_pts.size(); ++i) PtVec.push_back(plane.Projection(selected_pts[i])); cov.Covariance(PtVec, centerP); Matrix33f eigenvecMatrix; Point3f eigenvecVector; Eigen::Matrix3d em; cov.ToEigenMatrix(em); Eigen::SelfAdjointEigenSolver<Eigen::Matrix3d> eig(em); Eigen::Vector3d c_val = eig.eigenvalues(); Eigen::Matrix3d c_vec = eig.eigenvectors(); eigenvecMatrix.FromEigenMatrix(c_vec); eigenvecVector.FromEigenVector(c_val); // max eigenvector is best horizontal axis, but is not guarantee is orthogonal to plane normal, so // I use eigenvector ^ plane direction and assign it to vertical plane axis if ((eigenvecVector[0]<=eigenvecVector[1]) && (eigenvecVector[0]<=eigenvecVector[2])) dirV = Point3m(eigenvecMatrix[0][0], eigenvecMatrix[0][1], eigenvecMatrix[0][2]) ^ plane.Direction(); if ((eigenvecVector[1]<=eigenvecVector[0]) && (eigenvecVector[1]<=eigenvecVector[2])) dirV = Point3m(eigenvecMatrix[1][0], eigenvecMatrix[1][1], eigenvecMatrix[1][2]) ^ plane.Direction(); else dirV = Point3m(eigenvecMatrix[2][0], eigenvecMatrix[2][1], eigenvecMatrix[2][2]) ^ plane.Direction(); dirV.Normalize(); dirH = plane.Direction() ^ dirV; dirH.Normalize(); } Log("H [%f, %f, %f]", dirH.X(), dirH.Y(), dirH.Z()); Log("V [%f, %f, %f]", dirV.X(), dirV.Y(), dirV.Z()); // find extent float dimH = -1000000; float dimV = -1000000; for (size_t i = 0; i < selected_pts.size(); ++i) { Point3m pp = plane.Projection(selected_pts[i]); float distH = fabs(((pp - centerP) * dirH)); float distV = fabs(((pp - centerP) * dirV)); if (distH > dimH) dimH = distH; if (distV > dimV) dimV = distV; } float exScale = par.getFloat("extent"); dimV = dimV * exScale; dimH = dimH * exScale; Log("extent on plane [%f, %f]", dimV, dimH); int vertNum = par.getInt("subdiv") + 1; if (vertNum <= 1) vertNum = 2; int numV, numH; numV = numH = vertNum; // UV vector, just in case float *UUs, *VVs; UUs = new float[numH*numV]; VVs = new float[numH*numV]; int vind = 0; for (int ir = 0; ir < numV; ir++) for (int ic = 0; ic < numH; ic++) { Point3m newP = (centerP + (dirV * -dimV) + (dirH * -dimH)); newP = newP + (dirH * ic * (2.0 * dimH / (numH-1))) + (dirV * ir * (2.0 * dimV / (numV-1))); tri::Allocator<CMeshO>::AddVertex(m->cm, newP, plane.Direction()); UUs[vind] = ic * (1.0 / (numH - 1)); VVs[vind] = ir * (1.0 / (numV - 1)); vind++; } FaceGrid(m->cm, numH, numV); bool hasUV = par.getBool("hasuv"); if (hasUV) { m->updateDataMask(MeshModel::MM_WEDGTEXCOORD); CMeshO::FaceIterator fi; for (fi = m->cm.face.begin(); fi != m->cm.face.end(); ++fi) { for (int i = 0; i<3; ++i) { int vind = (*fi).V(i)->Index(); (*fi).WT(i).U() = UUs[vind]; (*fi).WT(i).V() = VVs[vind]; } } } delete[] UUs; // delete temporary UV storage delete[] VVs; } break; case CR_RANDOM_SPHERE: { int pointNum = par.getInt("pointNum"); int sphereGenTech = par.getEnum("sphereGenTech"); math::MarsenneTwisterRNG rng; m = md.addNewMesh("", this->filterName(ID(filter))); m->cm.Clear(); std::vector<Point3m> sampleVec; switch(sphereGenTech) { case 0: // Montecarlo { for(int i=0;i<pointNum;++i) sampleVec.push_back(math::GeneratePointOnUnitSphereUniform<CMeshO::ScalarType>(rng)); } break; case 1: // Poisson Disk { int oversamplingFactor =100; if(pointNum <= 100) oversamplingFactor = 1000; if(pointNum >= 10000) oversamplingFactor = 50; if(pointNum >= 100000) oversamplingFactor = 20; CMeshO tt; tri::Allocator<CMeshO>::AddVertices(tt,pointNum*oversamplingFactor); for(CMeshO::VertexIterator vi=tt.vert.begin();vi!=tt.vert.end();++vi) vi->P()=math::GeneratePointOnUnitSphereUniform<CMeshO::ScalarType>(rng); tri::UpdateBounding<CMeshO>::Box(tt); const float SphereArea = 4*M_PI; float poissonRadius = 2.0*sqrt((SphereArea / float(pointNum*2))/M_PI); std::vector<Point3m> sampleVec; tri::TrivialSampler<CMeshO> pdSampler(sampleVec); tri::SurfaceSampling<CMeshO, tri::TrivialSampler<CMeshO> >::PoissonDiskParam pp; tri::SurfaceSampling<CMeshO,tri::TrivialSampler<CMeshO> >::PoissonDiskPruning(pdSampler, tt, poissonRadius, pp); } break; case 2: // Disco Ball GenNormal<CMeshO::ScalarType>::DiscoBall(pointNum,sampleVec); break; case 3: // Recursive Oct GenNormal<CMeshO::ScalarType>::RecursiveOctahedron(pointNum,sampleVec); break; case 4: // Fibonacci GenNormal<CMeshO::ScalarType>::Fibonacci(pointNum,sampleVec); break; } for(size_t i=0;i<sampleVec.size();++i) tri::Allocator<CMeshO>::AddVertex(m->cm,sampleVec[i],sampleVec[i]); } break; case CR_SPHERE_CAP: { int rec = par.getInt("subdiv"); const float angleDeg = par.getFloat("angle"); m = md.addNewMesh("", this->filterName(ID(filter))); m->updateDataMask(MeshModel::MM_FACEFACETOPO); tri::UpdateTopology<CMeshO>::FaceFace(m->cm); tri::SphericalCap(m->cm,math::ToRad(angleDeg),rec); } break; case CR_SPHERE: { int rec = par.getInt("subdiv"); float radius = par.getFloat("radius"); m = md.addNewMesh("", this->filterName(ID(filter))); m->cm.face.EnableFFAdjacency(); m->updateDataMask(MeshModel::MM_FACEFACETOPO); assert(tri::HasPerVertexTexCoord(m->cm) == false); tri::Sphere<CMeshO>(m->cm,rec); tri::UpdatePosition<CMeshO>::Scale(m->cm,radius); } break; case CR_BOX: { float sz=par.getFloat("size"); Box3m b(Point3m(1,1,1)*(-sz/2),Point3m(1,1,1)*(sz/2)); m = md.addNewMesh("", this->filterName(ID(filter))); tri::Box<CMeshO>(m->cm,b); m->updateDataMask(MeshModel::MM_POLYGONAL); } break; case CR_CONE: { float r0 = par.getFloat("r0"); float r1 = par.getFloat("r1"); float h = par.getFloat("h"); int subdiv = par.getInt("subdiv"); m = md.addNewMesh("", this->filterName(ID(filter))); tri::Cone<CMeshO>(m->cm, r0, r1, h, subdiv); } break; }//CASE FILTER tri::UpdateBounding<CMeshO>::Box(m->cm); tri::UpdateNormal<CMeshO>::PerVertexNormalizedPerFaceNormalized(m->cm); return true; }
bool AmbientOcclusionPlugin::applyFilter(QAction *filter, MeshDocument &md, RichParameterSet & par, vcg::CallBackPos *cb) { MeshModel &m=*(md.mm()); if(ID(filter)==FP_FACE_AMBIENT_OCCLUSION ) perFace=true; else perFace = false; useGPU = par.getBool("useGPU"); useVBO = par.getBool("useVBO"); depthTexSize = par.getInt("depthTexSize"); depthTexArea = depthTexSize*depthTexSize; numViews = par.getInt("reqViews"); errInit = false; float dirBias = par.getFloat("dirBias"); Point3f coneDir = par.getPoint3f("coneDir"); float coneAngle = par.getFloat("coneAngle"); if(perFace) m.updateDataMask(MeshModel::MM_FACEQUALITY | MeshModel::MM_FACECOLOR); else m.updateDataMask(MeshModel::MM_VERTQUALITY | MeshModel::MM_VERTCOLOR); std::vector<Point3f> unifDirVec; GenNormal<float>::Uniform(numViews,unifDirVec); std::vector<Point3f> coneDirVec; GenNormal<float>::UniformCone(numViews, coneDirVec, math::ToRad(coneAngle), coneDir); std::random_shuffle(unifDirVec.begin(),unifDirVec.end()); std::random_shuffle(coneDirVec.begin(),coneDirVec.end()); int unifNum = floor(unifDirVec.size() * (1.0 - dirBias )); int coneNum = floor(coneDirVec.size() * (dirBias )); viewDirVec.clear(); viewDirVec.insert(viewDirVec.end(),unifDirVec.begin(),unifDirVec.begin()+unifNum); viewDirVec.insert(viewDirVec.end(),coneDirVec.begin(),coneDirVec.begin()+coneNum); numViews = viewDirVec.size(); this->glContext->makeCurrent(); this->initGL(cb,m.cm.vn); unsigned int widgetSize = std::min(maxTexSize, depthTexSize); QSize fbosize(widgetSize,widgetSize); QGLFramebufferObjectFormat frmt; frmt.setInternalTextureFormat(GL_RGBA); frmt.setAttachment(QGLFramebufferObject::Depth); QGLFramebufferObject fbo(fbosize,frmt); qDebug("Start Painting window size %i %i", fbo.width(), fbo.height()); GLenum err = glGetError(); fbo.bind(); processGL(m,viewDirVec); fbo.release(); err = glGetError(); const GLubyte* errname = gluErrorString(err); qDebug("End Painting"); this->glContext->doneCurrent(); return !errInit; }
bool ExtraFilter_SlicePlugin::applyFilter(QAction *filter, MeshDocument &m, RichParameterSet &parlst, vcg::CallBackPos *cb) { vcg::tri::UpdateBounding<CMeshO>::Box(m.mm()->cm); switch(ID(filter)) { case FP_WAFFLE_SLICE : { MeshModel* base = m.mm(); CMeshO &cmBase = base->cm; Box3f &bbox = m.mm()->cm.bbox; if (tri::Clean<CMeshO>::CountNonManifoldEdgeFF(cmBase)>0 || (tri::Clean<CMeshO>::CountNonManifoldVertexFF(cmBase,false) != 0)) { Log("Mesh is not two manifold, cannot apply filter"); return false; } if(parlst.getFloat("spacing") >= 1) { Log("the selected distance between the planes is greater than 1. The filter had no effect"); return false; } Point3f planeAxis(0,0,0); Axis axis = (Axis) parlst.getEnum("planeAxis"); planeAxis[axis] = 1.0f; float length = parlst.getFloat("length"); bool hideBase = parlst.getBool("hideBase"); bool hideEdge = parlst.getBool("hideEdge"); bool hidePlanes = parlst.getBool("hidePlanes"); bool hideExtrudes = parlst.getBool("hideExtrudes"); // set common SVG Properties const float maxdim=m.mm()->cm.bbox.Dim()[m.mm()->cm.bbox.MaxDim()]; Point3f sizeCm=m.mm()->cm.bbox.Dim()*(length/maxdim); // to check for dimensions with custom axis Axis axisOrthog, axisJoint; Point2f sizeCmOrth; switch(axis) { case X: { axisOrthog = (Axis) Succ<X>::value; axisJoint = (Axis) Succ<Succ<X>::value>::value; pr.sizeCm = Point2f(sizeCm[1],sizeCm[2]); sizeCmOrth.X()=sizeCm[0]; sizeCmOrth.Y()=sizeCm[2]; } break; case Y: { axisOrthog = (Axis) Succ<Y>::value; axisJoint = (Axis) Succ<Succ<Y>::value>::value; pr.sizeCm = Point2f(sizeCm[0],sizeCm[2]); sizeCmOrth.X()=sizeCm[0]; sizeCmOrth.Y()=sizeCm[1]; } break; case Z: { axisOrthog = (Axis) Succ<Z>::value; axisJoint = (Axis) Succ<Succ<Z>::value>::value; pr.sizeCm = Point2f(sizeCm[0],sizeCm[1]); sizeCmOrth.X()=sizeCm[1]; sizeCmOrth.Y()=sizeCm[2]; } break; } Log("sizecm %fx%f",pr.sizeCm[0],pr.sizeCm[1]); vector<CMeshO*> ev; const float planeDist = maxdim * parlst.getFloat("spacing"); const int planeNum = (planeDist == 0) ? 1 : ( ((bbox.Dim()*planeAxis)/planeDist)+1 ); //evito la divisione per 0 const float lengthDiag = bbox.Diag()/2.0; Segment2f lati[3]; //the rectangle is made up of three segments, the fourth side is ignored, so I never use it const float eps =planeDist*parlst.getFloat("eps"); float epsTmp; float start; int rectNum; if(parlst.getFloat("eps") < 1) { start = - (planeNum/2) * planeDist; //I have to go back from the center of half the length epsTmp = eps/2.0; generateRectSeg(0, epsTmp, bbox.Diag()*2, lati); rectNum = planeNum; } else { start = 0; epsTmp = bbox.Diag(); generateRectSeg(0, bbox.Diag()*2, bbox.Diag()*2, lati); rectNum = 1; Log("thickness is greater than 1: the extrusions will overlap"); } float planeOffset = parlst.getFloat("planeOffset"); pr.lineWidthPt=200; pr.scale=2/maxdim; pr.numCol=(int)(max((int)sqrt(planeNum*1.0f),2)+1); pr.numRow=(int)(planeNum*1.0f/pr.numCol)+1; pr.projDir = planeAxis; pr.projCenter = m.mm()->cm.bbox.Center(); pr.enumeration = true; MeshModel* cap, *cap2, *extr; QString layername; for(int pl = 0; pl < 2; ++pl) { // Log("################## PLANE %i", pl); Plane3f slicingPlane; Point3f planeCenter = bbox.Center() + planeAxis*planeOffset*lengthDiag; int numAdd = 0; // int i=4; //if I want to apply only the plan number i I decomment this variable and comment the cycle for(int i = 0; i < planeNum; ++i) //cropping the plans { // Log("######## LAYER %i", i); planeCenter[axis] = start + planeDist*i;; slicingPlane.Init(planeCenter,planeAxis); layername.sprintf("EdgeMesh_%d_%d",pl,numAdd); cap= m.addNewMesh("",qPrintable(layername)); vcg::IntersectionPlaneMesh<CMeshO, CMeshO, float>(base->cm, slicingPlane, cap->cm ); tri::Clean<CMeshO>::RemoveDuplicateVertex(cap->cm); if(cap->cm.edge.size()>= 3) { Incastri temp; // int j=1; //if I want to apply only the rectangle number j I decomment this variable and comment the cycle for(int j = 0; j <rectNum ; ++j) //clipping the rectangles { // Log("#### RECTANGLE %i", j); float newDist = start + planeDist*j; modifyOnY(lati, newDist+epsTmp, newDist-epsTmp); temp = subtraction(cap->cm, lati, axis, axisOrthog, axisJoint, planeCenter[axis]); if(temp == NOT_PLANE) {Log("ATTENTION! The IntersectionPlaneMesh did not return a plane silhouette in the current plane!"); m.delMesh(cap); break;} if(temp== NOT_SAGOME) {Log("ATTENTION! The IntersectionPlaneMesh did not return a simple closed silhouette for the plane %i, on axis %i",i, pl); m.delMesh(cap); break;} } if(temp > NOT_SAGOME) { ev.push_back(&(cap->cm)); //add the silhouette to those for export to SVG layername.sprintf("CappedSlice_%d_%d",pl,numAdd); //add the silhouettes converted in mesh cap2= m.addNewMesh("",qPrintable(layername)); tri::CapEdgeMesh(cap->cm, cap2->cm); layername.sprintf("Extruded_%d_%d",pl,numAdd++); //add the mesh extruded extr= m.addNewMesh("",qPrintable(layername)); cap2->updateDataMask(MeshModel::MM_FACEFACETOPO); extr->updateDataMask(MeshModel::MM_FACEFACETOPO); tri::UpdateTopology<CMeshO>::FaceFace(cap2->cm); tri::ExtrudeBoundary<CMeshO>(cap2->cm,extr->cm,eps,planeAxis); if(hideEdge) cap->visible =false; if(hidePlanes) cap2->visible =false; if(hideExtrudes) extr->visible =false; } }else m.delMesh(cap); //if the intersection does not exist I reject the result } QString fname;//= parlst.getSaveFileName("filename"); if(fname=="") fname.sprintf("Slice_%d.svg",pl); if (!fname.endsWith(".svg")) fname+=".svg"; tri::io::ExporterSVG<CMeshO>::Save(ev, fname.toStdString().c_str(), pr); ev.clear(); planeAxis[axis] = 0.0f; planeAxis[axisOrthog] = 1.0f; flipOnX(lati); pr.sizeCm = sizeCmOrth; pr.projDir = planeAxis; Axis aSwap = axis; axis = axisOrthog; axisOrthog = aSwap; } if(hideEdge) cap->visible =false; if(hidePlanes) cap2->visible =false; if(hideExtrudes) extr->visible =false; if(hideBase) base->visible =false; if(hideBase) base->visible =false; } break; } return true; }
bool RandomFillFilter::applyFilter(QAction*, MeshDocument &md, RichParameterSet& par, vcg::CallBackPos* cb){ if(parametersAreNotCorrect(md, par)) return false; MeshSubFilter::initialize(md, par, cb); if(cb != 0) (*cb)(0, "Physics renderization of the scene started..."); MeshModel* container = par.getMesh("container"); MeshModel* filler = par.getMesh("filler"); int fillOffset = md.size(); float gravity[3] = {0.0f, par.getBool("useRandomVertices") ? 0.0f : -9.8f, 0.0f}; if(par.getBool("flipNormal")){ vcg::tri::Clean<CMeshO>::FlipMesh(container->cm); tri::UpdateNormals<CMeshO>::PerVertexNormalizedPerFace(container->cm); container->clearDataMask(MeshModel::MM_FACEFACETOPO | MeshModel::MM_FACEFLAGBORDER); } m_engine.clear(); m_engine.setGlobalForce(gravity); m_engine.setIterations(par.getInt("iterations")); m_engine.setMaxContacts(par.getInt("contacts")); m_engine.setBounciness(par.getFloat("bounciness")); m_engine.setFriction(par.getFloat("friction")); m_engine.registerTriMesh(*container, true); srand((unsigned)time(0)); vcg::tri::UpdatePosition<CMeshO>::Matrix(filler->cm, filler->cm.Tr); filler->cm.Tr.SetIdentity(); tri::Inertia<CMeshO> inertiaContainer, inertiaFiller; inertiaContainer.Compute(par.getMesh("container")->cm); inertiaFiller.Compute(par.getMesh("filler")->cm); int objects = abs(inertiaContainer.Mass()/inertiaFiller.Mass())*par.getFloat("factor"); filler->cm.Tr.SetColumn(3, - inertiaFiller.CenterOfMass()); //Restore old generated meshes int restoredMeshes = 0; for(int i = 0; i < md.size(); i++){ if(md.getMesh(i)->fileName.find("randomFillMesh") == 0){ m_engine.registerTriMesh(*md.getMesh(i)); restoredMeshes++; m_engine.integrate(1.0f/par.getInt("fps")); } } int frequency = 1 / par.getFloat("updateFrequency"); // To refactor when the right algorithm has be found if(par.getBool("useRandomVertices")){ for(int i = 0; i < objects; i++){ if(cb != 0) (*cb)(50.f*i/objects, "Computing..."); addRandomObject(md, filler, getRandomOrigin(par), restoredMeshes + i); m_engine.registerTriMesh(*md.getMesh(fillOffset++)); } for(int j = 0; j < par.getFloat("seconds") * par.getInt("fps"); j++){ if(cb != 0) (*cb)(50 + 48.f*j/(par.getFloat("seconds") * par.getInt("fps")), "Computing..."); m_engine.integrate(1.0f/par.getInt("fps")); } }else{ for(int i = 0; i < objects; i++){ if(cb != 0) (*cb)(98.f*i/objects, "Computing..."); addRandomObject(md, filler, inertiaContainer.CenterOfMass(), i); m_engine.registerTriMesh(*md.getMesh(fillOffset++)); if(i % frequency == 0) for(int j = 0; j < par.getFloat("seconds") * par.getInt("fps"); j++) m_engine.integrate(1.0f/par.getInt("fps")); } } m_engine.updateTransform(); filler->cm.Tr.SetIdentity(); m_currentFilterType = m_filterType; if(par.getBool("flipNormal")){ vcg::tri::Clean<CMeshO>::FlipMesh(container->cm); tri::UpdateNormals<CMeshO>::PerVertexNormalizedPerFace(container->cm); container->clearDataMask(MeshModel::MM_FACEFACETOPO | MeshModel::MM_FACEFLAGBORDER); } if(cb != 0) (*cb)(99, "Physics renderization of the scene completed..."); return true; }
bool FilterOutputOpticalFlowPlugin::applyFilter( QAction *act, MeshDocument &md, RichParameterSet &par, vcg::CallBackPos * /*cb*/ ) { if( glewInit() != GLEW_OK ) return false; bool retValue = true; m_Mesh = &md.mm()->cm; QList<OOCRaster> rasters; if( md.rasterList.isEmpty() ) { QString filename = QFileDialog::getOpenFileName( NULL, "Select a MeshLab project file", QString(), "MeshLab project (*.mlp)" ); if( filename.isNull() || !loadRasterList(filename,rasters) ) return false; } else { foreach( RasterModel *rm, md.rasterList ) rasters.push_back( OOCRaster(rm) ); } std::list<vcg::Shotf> initialShots; for( QList<OOCRaster>::iterator r=rasters.begin(); r!=rasters.end(); ++r ) { initialShots.push_back( r->shot ); r->shot.ApplyRigidTransformation( vcg::Inverse(m_Mesh->Tr) ); } switch( ID(act) ) { case FP_OUTPUT_OPTICAL_FLOW: { for( CMeshO::FaceIterator f=m_Mesh->face.begin(); f!=m_Mesh->face.end(); ++f ) f->ClearV(); int weightMask = 0; if( par.getBool("useDistanceWeight") ) weightMask |= DominancyClassifier::W_DISTANCE; if( par.getBool("useImgBorderWeight") ) weightMask |= DominancyClassifier::W_IMG_BORDER; if( par.getBool("useSilhouetteWeight") ) weightMask |= DominancyClassifier::W_SILHOUETTE; if( par.getBool("useOrientationWeight") ) weightMask |= DominancyClassifier::W_ORIENTATION; DominancyClassifier *set = new DominancyClassifier( *m_Mesh, rasters, weightMask ); if( par.getBool("colorFromDominancy") ) { md.mm()->updateDataMask( MeshModel::MM_VERTCOLOR ); for( CMeshO::VertexIterator v=m_Mesh->vert.begin(); v!=m_Mesh->vert.end(); ++v ) if( (*set)[v].isOnBoundary() ) { unsigned char c = (unsigned char)( 255.0f*(*set)[v].borderWeight() ); v->C() = vcg::Color4b( 255-c, 255-c, 255-c, 255 ); } else v->C() = vcg::Color4b( 0, 0, 255, 255 ); delete set; } else { RasterFaceMap facesByDomImg; set->dominancyCoverage( facesByDomImg ); delete set; //if( int n = par.getInt("dominantAreaExpansion") ) //{ // md.mm()->updateDataMask( MeshModel::MM_FACEFACETOPO ); // md.mm()->updateDataMask( MeshModel::MM_VERTFACETOPO ); // for( RasterFaceMap::iterator rm=facesByDomImg.begin(); rm!=facesByDomImg.end(); ++rm ) // expands( rm.value(), n ); //} QMap<int,QVector<int>> validPairs; retroProjection( facesByDomImg, 0.01f*par.getFloat("minCoverage"), validPairs ); saveXMLProject( par.getString("xmlFileName"), md.mm(), facesByDomImg, validPairs ); } break; } } return retValue; }
/* 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 BaseMeshIOPlugin::open(const QString &formatName, const QString &fileName, MeshModel &m, int& mask, const RichParameterSet &parlst, CallBackPos *cb, QWidget * /*parent*/) { bool normalsUpdated = false; // initializing mask mask = 0; // initializing progress bar status if (cb != NULL) (*cb)(0, "Loading..."); QString errorMsgFormat = "Error encountered while loading file:\n\"%1\"\n\nError details: %2"; //string filename = fileName.toUtf8().data(); string filename = QFile::encodeName(fileName).constData (); if (formatName.toUpper() == tr("PLY")) { tri::io::ImporterPLY<CMeshO>::LoadMask(filename.c_str(), mask); // small patch to allow the loading of per wedge color into faces. if(mask & tri::io::Mask::IOM_WEDGCOLOR) mask |= tri::io::Mask::IOM_FACECOLOR; m.Enable(mask); int result = tri::io::ImporterPLY<CMeshO>::Open(m.cm, filename.c_str(), mask, cb); if (result != 0) // all the importers return 0 on success { if(tri::io::ImporterPLY<CMeshO>::ErrorCritical(result) ) { errorMessage = errorMsgFormat.arg(fileName, tri::io::ImporterPLY<CMeshO>::ErrorMsg(result)); return false; } } } else if (formatName.toUpper() == tr("STL")) { int result = tri::io::ImporterSTL<CMeshO>::Open(m.cm, filename.c_str(), cb); if (result != 0) // all the importers return 0 on success { errorMessage = errorMsgFormat.arg(fileName, tri::io::ImporterSTL<CMeshO>::ErrorMsg(result)); return false; } } else if( (formatName.toUpper() == tr("OBJ")) || (formatName.toUpper() == tr("QOBJ")) ) { tri::io::ImporterOBJ<CMeshO>::Info oi; oi.cb = cb; if (!tri::io::ImporterOBJ<CMeshO>::LoadMask(filename.c_str(), oi)) return false; m.Enable(oi.mask); int result = tri::io::ImporterOBJ<CMeshO>::Open(m.cm, filename.c_str(), oi); if (result != tri::io::ImporterOBJ<CMeshO>::E_NOERROR) { if (result & tri::io::ImporterOBJ<CMeshO>::E_NON_CRITICAL_ERROR) errorMessage = errorMsgFormat.arg(fileName, tri::io::ImporterOBJ<CMeshO>::ErrorMsg(result)); else { errorMessage = errorMsgFormat.arg(fileName, tri::io::ImporterOBJ<CMeshO>::ErrorMsg(result)); return false; } } if(oi.mask & tri::io::Mask::IOM_WEDGNORMAL) normalsUpdated = true; m.Enable(oi.mask); if(m.hasDataMask(MeshModel::MM_POLYGONAL)) qDebug("Mesh is Polygonal!"); mask = oi.mask; } else if (formatName.toUpper() == tr("PTX")) { tri::io::ImporterPTX<CMeshO>::Info importparams; importparams.meshnum = parlst.getInt("meshindex"); importparams.anglecull =parlst.getBool("anglecull"); importparams.angle = parlst.getFloat("angle"); importparams.savecolor = parlst.getBool("usecolor"); importparams.pointcull = parlst.getBool("pointcull"); importparams.pointsonly = parlst.getBool("pointsonly"); importparams.switchside = parlst.getBool("switchside"); importparams.flipfaces = parlst.getBool("flipfaces"); // if color, add to mesh if(importparams.savecolor) importparams.mask |= tri::io::Mask::IOM_VERTCOLOR; if(importparams.pointsonly) importparams.mask |= tri::io::Mask::IOM_VERTRADIUS; // reflectance is stored in quality importparams.mask |= tri::io::Mask::IOM_VERTQUALITY; m.Enable(importparams.mask); int result = tri::io::ImporterPTX<CMeshO>::Open(m.cm, filename.c_str(), importparams, cb); if (result == 1) { errorMessage = errorMsgFormat.arg(fileName, tri::io::ImporterPTX<CMeshO>::ErrorMsg(result)); return false; } // update mask mask = importparams.mask; } else if (formatName.toUpper() == tr("OFF")) { int loadMask; if (!tri::io::ImporterOFF<CMeshO>::LoadMask(filename.c_str(),loadMask)) return false; m.Enable(loadMask); int result = tri::io::ImporterOFF<CMeshO>::Open(m.cm, filename.c_str(), mask, cb); if (result != 0) // OFFCodes enum is protected { errorMessage = errorMsgFormat.arg(fileName, tri::io::ImporterOFF<CMeshO>::ErrorMsg(result)); return false; } } else if (formatName.toUpper() == tr("VMI")) { int loadMask; if (!tri::io::ImporterVMI<CMeshO>::LoadMask(filename.c_str(),loadMask)) return false; m.Enable(loadMask); int result = tri::io::ImporterVMI<CMeshO>::Open(m.cm, filename.c_str(), mask, cb); if (result != 0) { errorMessage = errorMsgFormat.arg(fileName, tri::io::ImporterOFF<CMeshO>::ErrorMsg(result)); return false; } } else { assert(0); // Unknown File type return false; } // verify if texture files are present QString missingTextureFilesMsg = "The following texture files were not found:\n"; bool someTextureNotFound = false; for ( unsigned textureIdx = 0; textureIdx < m.cm.textures.size(); ++textureIdx) { if (!QFile::exists(m.cm.textures[textureIdx].c_str())) { missingTextureFilesMsg.append("\n"); missingTextureFilesMsg.append(m.cm.textures[textureIdx].c_str()); someTextureNotFound = true; } } if (someTextureNotFound) Log("Missing texture files: %s", qPrintable(missingTextureFilesMsg)); if (cb != NULL) (*cb)(99, "Done"); return true; }
bool FilterIsoParametrization::applyFilter(QAction *filter, MeshDocument& md, RichParameterSet & par, vcg::CallBackPos *cb) { MeshModel* m = md.mm(); //get current mesh from document CMeshO *mesh=&m->cm; switch(ID(filter)) { case ISOP_PARAM : { int targetAbstractMinFaceNum = par.getInt("targetAbstractMinFaceNum"); int targetAbstractMaxFaceNum = par.getInt("targetAbstractMaxFaceNum"); int convergenceSpeed = par.getInt("convergenceSpeed"); int stopCriteria=par.getEnum("stopCriteria"); bool doublestep=par.getBool("DoubleStep"); IsoParametrizator Parametrizator; m->updateDataMask(MeshModel::MM_FACEFACETOPO); bool isTXTenabled=m->hasDataMask(MeshModel::MM_VERTTEXCOORD); if (!isTXTenabled) m->updateDataMask(MeshModel::MM_VERTTEXCOORD); bool isVMarkenabled=m->hasDataMask(MeshModel::MM_VERTMARK); if (!isVMarkenabled) m->updateDataMask(MeshModel::MM_VERTMARK); bool isFMarkenabled=m->hasDataMask(MeshModel::MM_FACEMARK); if (!isFMarkenabled) m->updateDataMask(MeshModel::MM_FACEMARK); bool isVColorenabled=m->hasDataMask(MeshModel::MM_VERTCOLOR); if (!isVColorenabled) m->updateDataMask(MeshModel::MM_VERTCOLOR); bool isFColorenabled=m->hasDataMask(MeshModel::MM_FACECOLOR); if (!isFColorenabled) m->updateDataMask(MeshModel::MM_FACECOLOR); int tolerance = targetAbstractMaxFaceNum-targetAbstractMinFaceNum; switch (stopCriteria) { case 0:Parametrizator.SetParameters(cb,targetAbstractMinFaceNum,tolerance,IsoParametrizator::SM_Euristic,convergenceSpeed);break; case 1:Parametrizator.SetParameters(cb,targetAbstractMinFaceNum,tolerance,IsoParametrizator::SM_Corr,convergenceSpeed);break; case 2:Parametrizator.SetParameters(cb,targetAbstractMinFaceNum,tolerance,IsoParametrizator::SM_Reg,convergenceSpeed);break; case 3:Parametrizator.SetParameters(cb,targetAbstractMinFaceNum,tolerance,IsoParametrizator::SM_L2,convergenceSpeed);break; default:Parametrizator.SetParameters(cb,targetAbstractMinFaceNum,tolerance,IsoParametrizator::SM_Euristic,convergenceSpeed);break; } IsoParametrizator::ReturnCode ret=Parametrizator.Parametrize<CMeshO>(mesh,doublestep); if (ret==IsoParametrizator::Done) { Parametrizator.PrintAttributes(); float aggregate,L2; int n_faces; Parametrizator.getValues(aggregate,L2,n_faces); Log("Num Faces of Abstract Domain: %d, One way stretch efficiency: %.4f, Area+Angle Distorsion %.4f ",n_faces,L2,aggregate*100.f); } else { if (!isTXTenabled) m->clearDataMask(MeshModel::MM_VERTTEXCOORD); if (!isFMarkenabled) m->clearDataMask(MeshModel::MM_FACEMARK); if (!isVMarkenabled) m->clearDataMask(MeshModel::MM_VERTMARK); if (!isVColorenabled) m->clearDataMask(MeshModel::MM_VERTCOLOR); if (!isFColorenabled) m->clearDataMask(MeshModel::MM_FACECOLOR); if (ret==IsoParametrizator::NonPrecondition) this->errorMessage="non possible parameterization because of violated preconditions"; else if (ret==IsoParametrizator::FailParam) this->errorMessage="non possible parameterization cause because missing the intepolation for some triangle of original the mesh (maybe due to topologycal noise)"; return false; } Parametrizator.ExportMeshes(para_mesh,abs_mesh); isoPHandle=vcg::tri::Allocator<CMeshO>::AddPerMeshAttribute<IsoParametrization>(*mesh,"isoparametrization"); bool isOK=isoPHandle().Init(&abs_mesh,¶_mesh); ///copy back to original mesh isoPHandle().CopyParametrization<CMeshO>(mesh); if (!isOK) { Log("Problems gathering parameterization \n"); return false; } if (!isVMarkenabled) m->clearDataMask(MeshModel::MM_VERTMARK); if (!isFMarkenabled) m->clearDataMask(MeshModel::MM_FACEMARK); return true; } case ISOP_REMESHING : { bool b=vcg::tri::Allocator<CMeshO>::IsValidHandle<IsoParametrization>(*mesh,isoPHandle); if (!b) { this->errorMessage="You must compute the Base domain before remeshing. Use the Isoparametrization command."; return false; } int SamplingRate=par.getInt("SamplingRate"); MeshModel* mm=md.addNewMesh("Re-meshed"); CMeshO *rem=&mm->cm; DiamSampl.Init(&isoPHandle()); DiamSampl.SamplePos(SamplingRate); DiamSampl.GetMesh<CMeshO>(*rem); int n_diamonds,inFace,inEdge,inStar,n_merged; DiamSampl.getResData(n_diamonds,inFace,inEdge,inStar,n_merged); Log("INTERPOLATION DOMAINS"); Log("In Face: %d \n",inFace); Log("In Diamond: %d \n",inEdge); Log("In Star: %d \n",inStar); Log("Merged %d vertices\n",n_merged); mm->updateDataMask(MeshModel::MM_FACEFACETOPO); mm->updateDataMask(MeshModel::MM_VERTFACETOPO); PrintStats(rem); vcg::tri::UpdateNormals<CMeshO>::PerFace(*rem); return true; } case ISOP_DIAMPARAM : { bool b=vcg::tri::Allocator<CMeshO>::IsValidHandle<IsoParametrization>(*mesh,isoPHandle); if (!b) { this->errorMessage="You must compute the Base domain before remeshing. Use the Isoparametrization command."; return false; } float border_size=par.getDynamicFloat("BorderSize"); MeshModel* mm=md.addNewMesh("Diam-Parameterized"); mm->updateDataMask(MeshModel::MM_WEDGTEXCOORD); mm->updateDataMask(MeshModel::MM_VERTCOLOR); CMeshO *rem=&mm->cm; DiamondParametrizator DiaPara; DiaPara.Init(&isoPHandle()); DiaPara.SetCoordinates<CMeshO>(*rem,border_size); vcg::tri::UpdateNormals<CMeshO>::PerFace(*rem); return true; } case ISOP_LOAD : { QString AbsName = par.getString("AbsName"); bool isTXTenabled=m->hasDataMask(MeshModel::MM_VERTTEXCOORD); if (!isTXTenabled) { this->errorMessage="Per Vertex Text Coordinates are not enabled"; return false; } if(!QFile(m->fullName()).exists()) { this->errorMessage="File not exists"; return false; } bool b=vcg::tri::Allocator<CMeshO>::IsValidHandle<IsoParametrization>(*mesh,isoPHandle); if (!b) isoPHandle=vcg::tri::Allocator<CMeshO>::AddPerMeshAttribute<IsoParametrization>(*mesh,"isoparametrization"); QByteArray ba = AbsName.toLatin1(); char *path=ba.data(); bool Done=isoPHandle().LoadBaseDomain<CMeshO>(path,mesh,¶_mesh,true); if (!Done) { this->errorMessage="Abstract domain doesnt fit well with the parametrized mesh"; return false; } return true; } case ISOP_SAVE : { bool b=vcg::tri::Allocator<CMeshO>::IsValidHandle<IsoParametrization>(*mesh,isoPHandle); if (!b) { this->errorMessage="You must compute the Base domain before remeshing. Use the Isoparametrization command."; return false; } /*QString Qpath=m->fullName();*/ QString AbsName = par.getString("AbsName"); QByteArray ba = AbsName.toLatin1(); char *path=ba.data(); isoPHandle().SaveBaseDomain(path); return true; } } return false; }
bool SdfGpuPlugin::applyFilter(QAction */*filter*/, MeshDocument &md, RichParameterSet & pars, vcg::CallBackPos *cb) { MeshModel* mm = md.mm(); //RETRIEVE PARAMETERS mOnPrimitive = (ONPRIMITIVE) pars.getEnum("onPrimitive"); // assert( mOnPrimitive==ON_VERTICES && "Face mode not supported yet" ); unsigned int numViews = pars.getInt("numberRays"); int peel = pars.getInt("peelingIteration"); mTolerance = pars.getFloat("peelingTolerance"); mPeelingTextureSize = pars.getInt("DepthTextureSize"); mUseVBO = pars.getBool("useVBO"); if(mAction != SDF_DEPTH_COMPLEXITY) mMinCos = vcg::math::Cos(math::ToRad(pars.getFloat("coneAngle")/2.0)); std::vector<Point3f> coneDirVec; if(mAction == SDF_OBSCURANCE) mTau = pars.getFloat("obscuranceExponent"); else if(mAction==SDF_SDF) { mRemoveFalse = pars.getBool("removeFalse"); mRemoveOutliers = pars.getBool("removeOutliers"); } //MESH CLEAN UP setupMesh( md, mOnPrimitive ); //GL INIT if(!initGL(*mm)) return false; // if(mOnPrimitive==ON_VERTICES) vertexDataToTexture(*mm); else faceDataToTexture(*mm); //Uniform sampling of directions over a sphere std::vector<Point3f> unifDirVec; GenNormal<float>::Uniform(numViews,unifDirVec); Log(0, "Number of rays: %i ", unifDirVec.size() ); Log(0, "Number of rays for GPU outliers removal: %i ", coneDirVec.size() ); coneDirVec.clear(); vector<int> mDepthDistrib(peel,0); //Do the actual calculation of sdf or obscurance for each ray unsigned int tracedRays = 0; for(vector<vcg::Point3f>::iterator vi = unifDirVec.begin(); vi != unifDirVec.end(); vi++) { (*vi).Normalize(); TraceRay(peel, (*vi), md.mm()); cb(100*((float)tracedRays/(float)unifDirVec.size()), "Tracing rays..."); this->glContext->makeCurrent(); ++tracedRays; mDepthComplexity = std::max(mDepthComplexity, mTempDepthComplexity); mDepthDistrib[mTempDepthComplexity]++; mTempDepthComplexity = 0; } //read back the result texture and store result in the mesh if(mAction == SDF_OBSCURANCE) { if(mOnPrimitive == ON_VERTICES) applyObscurancePerVertex(*mm,unifDirVec.size()); else applyObscurancePerFace(*mm,unifDirVec.size()); } else if(mAction == SDF_SDF) { if(mOnPrimitive == ON_VERTICES) applySdfPerVertex(*mm); else applySdfPerFace(*mm); } Log(0, "Mesh depth complexity %i (The accuracy of the result depends on the value you provided for the max number of peeling iterations, \n if you get warnings try increasing" " the peeling iteration parameter)\n", mDepthComplexity ); //Depth complexity distribution log. Useful to know which is the probability to find a number of layers looking at the mesh or scene. Log(0, "Depth complexity NumberOfViews\n", mDepthComplexity ); for(int j = 0; j < peel; j++) { Log(0, " %i %i\n", j, mDepthDistrib[j] ); } //Clean & Exit releaseGL(*mm); mDepthComplexity = 0; return true; }
bool FilterMutualInfoPlugin::preAlignment(MeshDocument &md, RichParameterSet & par, vcg::CallBackPos *cb) { Solver solver; MutualInfo mutual; if (md.rasterList.size()==0) { Log(0, "You need a Raster Model to apply this filter!"); return false; } else { align.mesh=&md.mm()->cm; solver.optimize_focal=par.getBool("Estimate Focal"); solver.fine_alignment=par.getBool("Fine"); int rendmode= par.getEnum("RenderingMode"); switch(rendmode){ case 0: align.mode=AlignSet::COMBINE; break; case 1: align.mode=AlignSet::NORMALMAP; break; case 2: align.mode=AlignSet::COLOR; break; case 3: align.mode=AlignSet::SPECULAR; break; case 4: align.mode=AlignSet::SILHOUETTE; break; case 5: align.mode=AlignSet::SPECAMB; break; default: align.mode=AlignSet::COMBINE; break; } vcg::Point3f *vertices = new vcg::Point3f[align.mesh->vn]; vcg::Point3f *normals = new vcg::Point3f[align.mesh->vn]; vcg::Color4b *colors = new vcg::Color4b[align.mesh->vn]; unsigned int *indices = new unsigned int[align.mesh->fn*3]; for(int i = 0; i < align.mesh->vn; i++) { vertices[i] = align.mesh->vert[i].P(); normals[i] = align.mesh->vert[i].N(); colors[i] = align.mesh->vert[i].C(); } for(int i = 0; i < align.mesh->fn; i++) for(int k = 0; k < 3; k++) indices[k+i*3] = align.mesh->face[i].V(k) - &*align.mesh->vert.begin(); glBindBufferARB(GL_ARRAY_BUFFER_ARB, align.vbo); glBufferDataARB(GL_ARRAY_BUFFER_ARB, align.mesh->vn*sizeof(vcg::Point3f), vertices, GL_STATIC_DRAW_ARB); glBindBufferARB(GL_ARRAY_BUFFER_ARB, align.nbo); glBufferDataARB(GL_ARRAY_BUFFER_ARB, align.mesh->vn*sizeof(vcg::Point3f), normals, GL_STATIC_DRAW_ARB); glBindBufferARB(GL_ARRAY_BUFFER_ARB, align.cbo); glBufferDataARB(GL_ARRAY_BUFFER_ARB, align.mesh->vn*sizeof(vcg::Color4b), colors, GL_STATIC_DRAW_ARB); glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, align.ibo); glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, align.mesh->fn*3*sizeof(unsigned int), indices, GL_STATIC_DRAW_ARB); glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); // it is safe to delete after copying data to VBO delete []vertices; delete []normals; delete []colors; delete []indices; for (int r=0; r<md.rasterList.size();r++) { if(md.rasterList[r]->visible) { align.image=&md.rasterList[r]->currentPlane->image; align.shot=md.rasterList[r]->shot; align.resize(800); align.shot.Intrinsics.ViewportPx[0]=int((double)align.shot.Intrinsics.ViewportPx[1]*align.image->width()/align.image->height()); align.shot.Intrinsics.CenterPx[0]=(int)(align.shot.Intrinsics.ViewportPx[0]/2); if (solver.fine_alignment) solver.optimize(&align, &mutual, align.shot); else { solver.iterative(&align, &mutual, align.shot); Log(0, "Vado di rough",r); } md.rasterList[r]->shot=align.shot; float ratio=(float)md.rasterList[r]->currentPlane->image.height()/(float)align.shot.Intrinsics.ViewportPx[1]; md.rasterList[r]->shot.Intrinsics.ViewportPx[0]=md.rasterList[r]->currentPlane->image.width(); md.rasterList[r]->shot.Intrinsics.ViewportPx[1]=md.rasterList[r]->currentPlane->image.height(); md.rasterList[r]->shot.Intrinsics.PixelSizeMm[1]/=ratio; md.rasterList[r]->shot.Intrinsics.PixelSizeMm[0]/=ratio; md.rasterList[r]->shot.Intrinsics.CenterPx[0]=(int)((float)md.rasterList[r]->shot.Intrinsics.ViewportPx[0]/2.0); md.rasterList[r]->shot.Intrinsics.CenterPx[1]=(int)((float)md.rasterList[r]->shot.Intrinsics.ViewportPx[1]/2.0); Log(0, "Image %d completed",r); } else Log(0, "Image %d skipped",r); } } return true; }
// The Real Core Function doing the actual mesh processing. bool FilterHarmonicPlugin::applyFilter(QAction * action, MeshDocument & md, RichParameterSet & par, vcg::CallBackPos * cb) { switch(ID(action)) { case FP_SCALAR_HARMONIC_FIELD : { typedef vcg::GridStaticPtr<CMeshO::VertexType, CMeshO::ScalarType> VertexGrid; typedef double CoeffScalar; // TODO, when moving the code to a class make it a template (CoeffScalar = double) typedef CMeshO::ScalarType ScalarType; typedef CMeshO::CoordType CoordType; typedef CMeshO::VertexType VertexType; typedef CMeshO::FaceType FaceType; typedef Eigen::Triplet<CoeffScalar> T; typedef Eigen::SparseMatrix<CoeffScalar> SpMat; //sparse matrix type of double CMeshO & m = md.mm()->cm; vcg::tri::Allocator<CMeshO>::CompactFaceVector(m); vcg::tri::Allocator<CMeshO>::CompactVertexVector(m); md.mm()->updateDataMask(MeshModel::MM_FACEFACETOPO | MeshModel::MM_VERTMARK); vcg::tri::UpdateBounding<CMeshO>::Box(m); vcg::tri::UpdateTopology<CMeshO>::FaceFace(m); int n = m.VN(); int fn = m.FN(); std::vector<T> coeffs; // coefficients of the system std::map<size_t,CoeffScalar> sums; // row sum of the coefficient SpMat laplaceMat; // the system to be solved laplaceMat.resize(n, n); Log("Generating coefficients.`"); cb(0, "Generating coefficients..."); vcg::tri::UpdateFlags<CMeshO>::FaceClearV(m); // Iterate over the faces for (size_t i = 0; i < m.face.size(); ++i) { CMeshO::FaceType & f = m.face[i]; if (f.IsD()) { assert(int(i) == fn); break; // TODO FIX the indexing of vertices } assert(!f.IsV()); f.SetV(); // Generate coefficients for each edge for (int idx = 0; idx < 3; ++idx) { CoeffScalar weight; WeightInfo res = ComputeWeight<FaceType, CoeffScalar>(f, idx, weight); switch (res) { case EdgeAlreadyVisited : continue; case Success : break; case BorderEdge : this->errorMessage = "Mesh not closed, cannot compute harmonic field on mesh containing holes or borders"; return false; default: assert(0); } // if (weight < 0) weight = 0; // TODO check if negative weight may be an issue // Add the weight to the coefficients vector for both the vertices of the considered edge size_t v0_idx = vcg::tri::Index(m, f.V0(idx)); size_t v1_idx = vcg::tri::Index(m, f.V1(idx)); coeffs.push_back(T(v0_idx, v1_idx, -weight)); coeffs.push_back(T(v1_idx, v0_idx, -weight)); // Add the weight to the row sum sums[v0_idx] += weight; sums[v1_idx] += weight; } f.SetV(); } // Fill the system matrix Log("Fill the system matrix"); cb(10, "Filling the system matrix..."); laplaceMat.reserve(coeffs.size()); for (std::map<size_t,CoeffScalar>::const_iterator it = sums.begin(); it != sums.end(); ++it) { coeffs.push_back(T(it->first, it->first, it->second)); } laplaceMat.setFromTriplets(coeffs.begin(), coeffs.end()); // Get the two vertices with value set VertexGrid vg; vg.Set(m.vert.begin(), m.vert.end()); vcg::vertex::PointDistanceFunctor<ScalarType> pd; vcg::tri::Tmark<CMeshO, VertexType> mv; mv.SetMesh(&m); mv.UnMarkAll(); CoordType closestP; ScalarType minDist = 0; VertexType * vp0 = vcg::GridClosest(vg, pd, mv, par.getPoint3f("point1"), m.bbox.Diag(), minDist, closestP); VertexType * vp1 = vcg::GridClosest(vg, pd, mv, par.getPoint3f("point2"), m.bbox.Diag(), minDist, closestP); if (vp0 == NULL || vp1 == NULL || vp0 == vp1) { this->errorMessage = "Error occurred for selected points."; return false; } size_t v0_idx = vcg::tri::Index(m, vp0); size_t v1_idx = vcg::tri::Index(m, vp1); // Add penalty factor alpha Log("Setting up the system matrix"); const CoeffScalar alpha = pow(10, 8); Eigen::Matrix<CoeffScalar, Eigen::Dynamic, 1> b, x; // Unknown and known terms vectors b.setZero(n); b(v0_idx) = alpha * par.getFloat("value1"); b(v1_idx) = alpha * par.getFloat("value2"); laplaceMat.coeffRef(v0_idx, v0_idx) += alpha; laplaceMat.coeffRef(v1_idx, v1_idx) += alpha; // Solve system laplacianMat x = b Log("System matrix decomposition..."); cb(20, "System matrix decomposition..."); Eigen::SimplicialLDLT<Eigen::SparseMatrix<CoeffScalar> > solver; // TODO eventually use another solver solver.compute(laplaceMat); if(solver.info() != Eigen::Success) { // decomposition failed this->errorMessage = "System matrix decomposition failed: "; if (solver.info() == Eigen::NumericalIssue) this->errorMessage += "numerical issue."; else if (solver.info() == Eigen::NoConvergence) this->errorMessage += "no convergence."; else if (solver.info() == Eigen::InvalidInput) this->errorMessage += "invalid input."; return false; } Log("Solving the system..."); cb(85, "Solving the system..."); x = solver.solve(b); if(solver.info() != Eigen::Success) { // solving failed this->errorMessage = "System solving failed."; return false; } // Colorize bands for the 0-1 interval if (par.getBool("colorize")) { float steps = 20.0f; for (size_t i = 0; int(i) < n; ++i) { bool on = (int)(x[i]*steps)%2 == 1; if (on) { m.vert[i].C() = vcg::Color4b::ColorRamp(0,2,x[i]); } else { m.vert[i].C() = vcg::Color4b::White; } } } // Set field value into vertex quality attribute for (size_t i = 0; int(i) < n; ++i) { m.vert[i].Q() = x[i]; } cb(100, "Done."); return true; } default : assert(0); } return false; }
bool AlignTools::align(MeshModel *stuckModel, PickedPoints *stuckPickedPoints, MeshModel *modelToMove, PickedPoints *modelToMovePickedPoints, GLArea *modelToMoveGLArea, RichParameterSet &filterParameters, QWidget *parentWidget, bool confirm) { vcg::Matrix44f result; bool useMarkers = filterParameters.getBool(UseMarkers); bool allowScaling = filterParameters.getBool(AllowScaling); bool useICP = filterParameters.getBool(UseICP); if(useMarkers){ //get the picked points std::vector<vcg::Point3f> *stuckPoints = stuckPickedPoints->getPoint3fVector(); std::vector<vcg::Point3f> *meshToMovePoints = modelToMovePickedPoints->getPoint3fVector(); //number of points are not the same so return false if(stuckPoints->size() != meshToMovePoints->size()) return false; //this will calculate the transform for the destination mesh model which we will be moving //into alignment with the source if(allowScaling) { qDebug() << "Scaling allowed"; vcg::PointMatching<float>::ComputeSimilarityMatchMatrix(result, *stuckPoints, *meshToMovePoints); } else vcg::PointMatching<float>::ComputeRigidMatchMatrix(result, *stuckPoints, *meshToMovePoints); //set the transform modelToMove->cm.Tr = result; if(NULL != modelToMoveGLArea) modelToMoveGLArea->update(); } if(useICP) { qDebug("Now on to ICP"); //create a meshtree MeshTree meshTree; //put both meshes in it meshTree.nodeList.push_back(new MeshNode(stuckModel, 0)); meshTree.nodeList.push_back(new MeshNode(modelToMove, 1)); //set both to glued foreach(MeshNode *mn, meshTree.nodeList) mn->glued=true; vcg::AlignPair::Param ICPParameters; //get the parameter values AlignParameter::buildAlignParameters(filterParameters, ICPParameters); meshTree.Process(ICPParameters); qDebug() << "done with process for ICP"; if(NULL != modelToMoveGLArea) modelToMoveGLArea->update(); } if(useMarkers || useICP) { if(confirm && NULL != modelToMoveGLArea) { bool removeMeshAddedForQuestion = false; vcg::Color4b oldStuckColor; vcg::Color4b oldToMoveColor; vcg::GLW::ColorMode oldColorMode; //if the stuck model is not displayed next to the model to move, //then temporarily display it if(!modelToMoveGLArea->md()->meshList.contains(stuckModel)) { removeMeshAddedForQuestion = true; modelToMoveGLArea->md()->meshList.push_back(stuckModel); //save the old colors oldStuckColor = stuckModel->cm.C(); oldToMoveColor = modelToMove->cm.C(); //set the color of the objects stuckModel->cm.C() = vcg::Color4b::LightBlue; modelToMove->cm.C() = vcg::Color4b::LightGray; //save the old colorMode oldColorMode = modelToMoveGLArea->rm.colorMode; //set the new colorMode modelToMoveGLArea->rm.colorMode = GLW::CMPerMesh; modelToMoveGLArea->update(); } int returnValue = QMessageBox::question(parentWidget, "MeshLab", "Do you want accept this alignment?", QMessageBox::Yes|QMessageBox::No, QMessageBox::No); //if we added the other model in for comparing if(removeMeshAddedForQuestion) { //remove the mesh that was added modelToMoveGLArea->md()->meshList.pop_back(); //set back to how things were before stuckModel->cm.C() = oldStuckColor; modelToMove->cm.C() = oldToMoveColor; modelToMoveGLArea->rm.colorMode = oldColorMode; modelToMoveGLArea->update(); } if(returnValue == QMessageBox::No) { modelToMove->cm.Tr.SetIdentity(); modelToMoveGLArea->update(); return false; } } //if there are points (may not be if you just used ICP if(NULL != modelToMovePickedPoints) { //now translate the picked points points modelToMovePickedPoints->translatePoints(modelToMove->cm.Tr); //update the metadata CMeshO::PerMeshAttributeHandle<PickedPoints*> ppHandle = (vcg::tri::HasPerMeshAttribute(modelToMove->cm, PickedPoints::Key) ? vcg::tri::Allocator<CMeshO>::GetPerMeshAttribute<PickedPoints*> (modelToMove->cm, PickedPoints::Key) : vcg::tri::Allocator<CMeshO>::AddPerMeshAttribute<PickedPoints*> (modelToMove->cm, PickedPoints::Key) ); ppHandle() = modelToMovePickedPoints; } //now save the transform as perMeshData so that we can undo it in the future CMeshO::PerMeshAttributeHandle<vcg::Matrix44f> transformHandle = (vcg::tri::HasPerMeshAttribute(modelToMove->cm, getKey()) ? vcg::tri::Allocator<CMeshO>::GetPerMeshAttribute<vcg::Matrix44f> (modelToMove->cm, getKey()) : vcg::tri::Allocator<CMeshO>::AddPerMeshAttribute<vcg::Matrix44f> (modelToMove->cm, getKey()) ); transformHandle() = modelToMove->cm.Tr; //now translate all the points in the mesh //TODO probably should call a function to do this so if meshlab changes we dont have to //taken from meshlab/src/meshlabplugins/meshfilter/meshfilter.cpp //if (ID(filter) == (FP_FREEZE_TRANSFORM) ) { vcg::tri::UpdatePosition<CMeshO>::Matrix(modelToMove->cm, modelToMove->cm.Tr); vcg::tri::UpdateNormals<CMeshO>::PerVertexNormalizedPerFace(modelToMove->cm); vcg::tri::UpdateBounding<CMeshO>::Box(modelToMove->cm); modelToMove->cm.Tr.SetIdentity(); return true; } else { qDebug() << "you ran align without choosing a method"; } return false; }
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; }
bool FilterIsoParametrization::applyFilter(QAction *filter, MeshDocument& md, RichParameterSet & par, vcg::CallBackPos *cb) { MeshModel* m = md.mm(); //get current mesh from document CMeshO *mesh=&m->cm; switch(ID(filter)) { case ISOP_PARAM : { int targetAbstractMinFaceNum = par.getInt("targetAbstractMinFaceNum"); int targetAbstractMaxFaceNum = par.getInt("targetAbstractMaxFaceNum"); int convergenceSpeed = par.getInt("convergenceSpeed"); int stopCriteria=par.getEnum("stopCriteria"); bool doublestep=par.getBool("DoubleStep"); IsoParametrizator Parametrizator; m->updateDataMask(MeshModel::MM_FACEFACETOPO); m->updateDataMask(MeshModel::MM_VERTQUALITY); // needed to store patch index bool isTXTenabled=m->hasDataMask(MeshModel::MM_VERTTEXCOORD); if (!isTXTenabled) m->updateDataMask(MeshModel::MM_VERTTEXCOORD); bool isVMarkenabled=m->hasDataMask(MeshModel::MM_VERTMARK); if (!isVMarkenabled) m->updateDataMask(MeshModel::MM_VERTMARK); bool isFMarkenabled=m->hasDataMask(MeshModel::MM_FACEMARK); if (!isFMarkenabled) m->updateDataMask(MeshModel::MM_FACEMARK); bool isVColorenabled=m->hasDataMask(MeshModel::MM_VERTCOLOR); if (!isVColorenabled) m->updateDataMask(MeshModel::MM_VERTCOLOR); bool isFColorenabled=m->hasDataMask(MeshModel::MM_FACECOLOR); if (!isFColorenabled) m->updateDataMask(MeshModel::MM_FACECOLOR); int tolerance = targetAbstractMaxFaceNum-targetAbstractMinFaceNum; switch (stopCriteria) { case 0: Parametrizator.SetParameters(cb,targetAbstractMinFaceNum,tolerance,IsoParametrizator::SM_Euristic,convergenceSpeed); break; case 1: Parametrizator.SetParameters(cb,targetAbstractMinFaceNum,tolerance,IsoParametrizator::SM_Corr,convergenceSpeed); break; case 2: Parametrizator.SetParameters(cb,targetAbstractMinFaceNum,tolerance,IsoParametrizator::SM_Reg,convergenceSpeed); break; case 3: Parametrizator.SetParameters(cb,targetAbstractMinFaceNum,tolerance,IsoParametrizator::SM_L2,convergenceSpeed); break; default: Parametrizator.SetParameters(cb,targetAbstractMinFaceNum,tolerance,IsoParametrizator::SM_Euristic,convergenceSpeed); break; } tri::ParamEdgeCollapseParameter pecp; IsoParametrizator::ReturnCode ret=Parametrizator.Parametrize<CMeshO>(mesh,pecp,doublestep); if (ret==IsoParametrizator::Done) { Parametrizator.PrintAttributes(); float aggregate,L2; int n_faces; Parametrizator.getValues(aggregate,L2,n_faces); Log("Num Faces of Abstract Domain: %d, One way stretch efficiency: %.4f, Area+Angle Distorsion %.4f ",n_faces,L2,aggregate*100.f); } else { if (!isTXTenabled) m->clearDataMask(MeshModel::MM_VERTTEXCOORD); if (!isFMarkenabled) m->clearDataMask(MeshModel::MM_FACEMARK); if (!isVMarkenabled) m->clearDataMask(MeshModel::MM_VERTMARK); if (!isVColorenabled) m->clearDataMask(MeshModel::MM_VERTCOLOR); if (!isFColorenabled) m->clearDataMask(MeshModel::MM_FACECOLOR); switch(ret) { case IsoParametrizator::MultiComponent: this->errorMessage="non possible parameterization because of multi componet mesh"; return false; case IsoParametrizator::NonSizeCons: this->errorMessage="non possible parameterization because of non size consistent mesh"; return false; case IsoParametrizator::NonManifoldE: this->errorMessage="non possible parameterization because of non manifold edges"; return false; case IsoParametrizator::NonManifoldV: this->errorMessage="non possible parameterization because of non manifold vertices"; return false; case IsoParametrizator::NonWatertigh: this->errorMessage="non possible parameterization because of non watertight mesh"; return false; case IsoParametrizator::FailParam: this->errorMessage="non possible parameterization cause one of the following reasons:\n Topologycal noise \n Too Low resolution mesh \n Too Bad triangulation \n"; return false; default: this->errorMessage="unknown error"; return false; } } // At this point we are sure that everithing went ok so we can allocate surely the abstract AbstractMesh *abs_mesh = new AbstractMesh(); ParamMesh *para_mesh = new ParamMesh(); Parametrizator.ExportMeshes(*para_mesh,*abs_mesh); CMeshO::PerMeshAttributeHandle<IsoParametrization> isoPHandle; isoPHandle=tri::Allocator<CMeshO>::AddPerMeshAttribute<IsoParametrization>(*mesh,"isoparametrization"); bool isOK=isoPHandle().Init(abs_mesh,para_mesh); ///copy back to original mesh isoPHandle().CopyParametrization<CMeshO>(mesh); if (!isOK) { this->errorMessage="Problems gathering parameterization \n"; return false; } if (!isVMarkenabled) m->clearDataMask(MeshModel::MM_VERTMARK); if (!isFMarkenabled) m->clearDataMask(MeshModel::MM_FACEMARK); return true; } case ISOP_REMESHING : { CMeshO::PerMeshAttributeHandle<IsoParametrization> isoPHandle = tri::Allocator<CMeshO>::FindPerMeshAttribute<IsoParametrization>(*mesh,"isoparametrization"); bool b=tri::Allocator<CMeshO>::IsValidHandle<IsoParametrization>(*mesh,isoPHandle); if (!b) { this->errorMessage="You must compute the Base domain before remeshing. Use the Isoparametrization command."; return false; } int SamplingRate=par.getInt("SamplingRate"); if (!SamplingRate>2) { this->errorMessage="Sampling rate must be >1"; return false; } MeshModel* mm=md.addNewMesh("","Re-meshed"); CMeshO *rem=&mm->cm; DiamSampler DiamSampl; DiamSampl.Init(&isoPHandle()); bool done=DiamSampl.SamplePos(SamplingRate); assert(done); DiamSampl.GetMesh<CMeshO>(*rem); int n_diamonds,inFace,inEdge,inStar,n_merged; DiamSampl.getResData(n_diamonds,inFace,inEdge,inStar,n_merged); Log("INTERPOLATION DOMAINS"); Log("In Face: %d \n",inFace); Log("In Diamond: %d \n",inEdge); Log("In Star: %d \n",inStar); Log("Merged %d vertices\n",n_merged); mm->updateDataMask(MeshModel::MM_FACEFACETOPO); mm->updateDataMask(MeshModel::MM_VERTFACETOPO); PrintStats(rem); tri::UpdateNormal<CMeshO>::PerFace(*rem); return true; } case ISOP_DIAMPARAM : { CMeshO::PerMeshAttributeHandle<IsoParametrization> isoPHandle = tri::Allocator<CMeshO>::FindPerMeshAttribute<IsoParametrization>(*mesh,"isoparametrization"); bool b=tri::Allocator<CMeshO>::IsValidHandle<IsoParametrization>(*mesh,isoPHandle); if (!b) { this->errorMessage="You must compute the Base domain before remeshing. Use the Isoparametrization command."; return false; } float border_size=par.getDynamicFloat("BorderSize"); MeshModel* mm=md.addNewMesh("","Diam-Parameterized"); mm->updateDataMask(MeshModel::MM_WEDGTEXCOORD); mm->updateDataMask(MeshModel::MM_VERTCOLOR); CMeshO *rem=&mm->cm; DiamondParametrizator DiaPara; DiaPara.Init(&isoPHandle()); DiaPara.SetCoordinates<CMeshO>(*rem,border_size); tri::UpdateNormal<CMeshO>::PerFace(*rem); return true; } case ISOP_LOAD : { QString AbsName = par.getString("AbsName"); m->updateDataMask(MeshModel::MM_WEDGTEXCOORD); m->updateDataMask(MeshModel::MM_VERTTEXCOORD); m->updateDataMask(MeshModel::MM_FACECOLOR); m->updateDataMask(MeshModel::MM_VERTQUALITY); m->updateDataMask(MeshModel::MM_FACEMARK); if(!QFile(m->fullName()).exists()) { this->errorMessage="File not exists"; return false; } CMeshO::PerMeshAttributeHandle<IsoParametrization> isoPHandle = tri::Allocator<CMeshO>::FindPerMeshAttribute<IsoParametrization>(*mesh,"isoparametrization"); bool b=tri::Allocator<CMeshO>::IsValidHandle<IsoParametrization>(*mesh,isoPHandle); if (!b) isoPHandle=tri::Allocator<CMeshO>::AddPerMeshAttribute<IsoParametrization>(*mesh,"isoparametrization"); QByteArray ba = AbsName.toLatin1(); char *path=ba.data(); AbstractMesh *abs_mesh = new AbstractMesh(); ParamMesh *para_mesh = new ParamMesh(); bool Done=isoPHandle().LoadBaseDomain<CMeshO>(path,mesh,para_mesh,abs_mesh,true); if (!Done) { this->errorMessage="Abstract domain doesnt fit well with the parametrized mesh"; delete para_mesh; delete abs_mesh; return false; } return true; } case ISOP_SAVE : { m->updateDataMask(MeshModel::MM_VERTQUALITY); CMeshO::PerMeshAttributeHandle<IsoParametrization> isoPHandle = tri::Allocator<CMeshO>::FindPerMeshAttribute<IsoParametrization>(*mesh,"isoparametrization"); bool b=tri::Allocator<CMeshO>::IsValidHandle<IsoParametrization>(*mesh,isoPHandle); if (!b) { this->errorMessage="You must compute the Base domain before remeshing. Use the Isoparametrization command."; return false; } /*QString Qpath=m->fullName();*/ QString AbsName = par.getString("AbsName"); QByteArray ba = AbsName.toLatin1(); char *path=ba.data(); isoPHandle().SaveBaseDomain(path); return true; } case ISOP_TRANSFER: { MeshModel *mmtrg = par.getMesh("targetMesh"); MeshModel *mmsrc = par.getMesh("targetMesh"); CMeshO *trgMesh=&mmtrg->cm; CMeshO *srcMesh=&mmsrc->cm; CMeshO::PerMeshAttributeHandle<IsoParametrization> isoPHandle = tri::Allocator<CMeshO>::FindPerMeshAttribute<IsoParametrization>(*mesh,"isoparametrization"); bool b=tri::Allocator<CMeshO>::IsValidHandle<IsoParametrization>(*srcMesh,isoPHandle); if (!b) { this->errorMessage="Your source mesh must have the abstract isoparametrization. Use the Isoparametrization command."; return false; } IsoTransfer IsoTr; AbstractMesh *abs_mesh = isoPHandle().AbsMesh(); ParamMesh *para_mesh = isoPHandle().ParaMesh(); mmtrg->updateDataMask(MeshModel::MM_WEDGTEXCOORD); mmtrg->updateDataMask(MeshModel::MM_VERTTEXCOORD); mmtrg->updateDataMask(MeshModel::MM_FACECOLOR); mmtrg->updateDataMask(MeshModel::MM_VERTQUALITY); mmtrg->updateDataMask(MeshModel::MM_FACEMARK); IsoTr.Transfer<CMeshO>(isoPHandle(),*trgMesh); isoPHandle().Clear(); tri::Allocator<CMeshO>::DeletePerMeshAttribute(*srcMesh,isoPHandle); isoPHandle=tri::Allocator<CMeshO>::AddPerMeshAttribute<IsoParametrization>(*trgMesh,"isoparametrization"); isoPHandle().AbsMesh()=abs_mesh; isoPHandle().SetParamMesh<CMeshO>(trgMesh,para_mesh); return true; } } return false; }