typename ALIGNER_TYPE::Result FilterFeatureAlignment::RansacOperation(MeshModel& mFix, MeshModel& mMov, typename ALIGNER_TYPE::Parameters& param, CallBackPos *cb) { typedef ALIGNER_TYPE AlignerType; typedef typename AlignerType::MeshType MeshType; typedef typename AlignerType::FeatureType FeatureType; typedef typename MeshType::ScalarType ScalarType; typedef typename AlignerType::Result ResultType; //enables needed attributes. MM_VERTMARK is used by the getClosest functor. mFix.updateDataMask(MeshModel::MM_VERTMARK|FeatureType::getRequirements()); mMov.updateDataMask(MeshModel::MM_VERTMARK|FeatureType::getRequirements()); AlignerType aligner; param.log = &mylogger; //set the callback used to print infos inside the procedure ResultType res = aligner.init(mFix.cm, mMov.cm, param, cb); if(res.exitCode==ResultType::FAILED) return res; //perform RANSAC and get best transformation matrix res = aligner.align(mFix.cm, mMov.cm, param, cb); //apply transformation. If ransac don't find a good matrix, identity is returned; so nothing is wrong here... mMov.cm.Tr = res.tr * mMov.cm.Tr; return res; }
typename ALIGNER_TYPE::Result FilterFeatureAlignment::RansacDiagramOperation(MeshModel& mFix, MeshModel& mMov, typename ALIGNER_TYPE::Parameters& param, int trials, int from, int to, int step, CallBackPos *cb) { typedef ALIGNER_TYPE AlignerType; typedef typename AlignerType::MeshType MeshType; typedef typename AlignerType::FeatureType FeatureType; typedef typename MeshType::ScalarType ScalarType; typedef typename AlignerType::Result ResultType; //variables needed for progress bar callback float progBar = 0.0f; float offset = 100.0f/(trials); //enables needed attributes. MM_VERTMARK is used by the getClosest functor. mFix.updateDataMask(MeshModel::MM_VERTMARK|FeatureType::getRequirements()); mMov.updateDataMask(MeshModel::MM_VERTMARK|FeatureType::getRequirements()); ResultType res; FILE* file = fopen("Diagram.txt","w+"); fprintf(file,"Fix Mesh#%s\nMove Mesh#%s\nFeature#%s\nNum. of vertices of Fix Mesh#%i\nNum. of vertices of Move Mesh#%i\nOverlap#%.2f%%\nFull consensus threshold#%.2f%% overlap#%.2f%% of Move Mesh#\nTrials#%i\n",mFix.fileName.c_str(),mMov.fileName.c_str(),FeatureType::getName(),mFix.cm.VertexNumber(),mMov.cm.VertexNumber(),param.overlap,param.consOffset,(param.consOffset*param.overlap/100.0f),trials); fflush(file); fprintf(file,"Iterazioni#Tempo di inizializzazione#Tempo di esecuzione#Prob. Succ.#Prob. Fall. per Sec#Num. medio basi\n0#0#0#0#0\n"); fflush(file); float probSucc = 0.0f, meanTime = 0.0f, meanInitTime = 0.0f, failPerSec = -1.0f; int numWon = 0, trialsTotTime = 0, trialsInitTotTime = 0, numBases = 0; param.ransacIter = from; //param.log = &mylogger; //this is the way to assign a pointer to log function //move res here while(param.ransacIter<=to) { for(int i=0; i<trials; i++){ //callback handling if(cb){ progBar+=offset; cb(int(progBar),"Computing diagram..."); } AlignerType aligner; res = aligner.init(mFix.cm, mMov.cm, param); if(res.exitCode==ResultType::FAILED) return res; trialsInitTotTime+=res.initTime; res = aligner.align(mFix.cm, mMov.cm, param); trialsTotTime+=res.totalTime; numBases+=res.numBasesFound; if(res.exitCode==ResultType::ALIGNED) numWon++; if(res.exitCode==ResultType::FAILED) return res; //failure: stop everything and return error } probSucc = numWon/float(trials); //k = prob succ in 1 iteration meanTime = trialsTotTime/float(trials); //t=sec elapsed to perform N ransac iterations meanInitTime = trialsInitTotTime/float(trials); failPerSec = std::pow(1-probSucc,1.0f/(meanTime/1000)); //fail rate per sec is: (1-k)^(1/t) fprintf(file,"%i#=%.0f/1000#=%.0f/1000#=%.0f/100#=%.0f/100#%i\n", param.ransacIter, meanInitTime, meanTime, 100*probSucc, 100*failPerSec,numBases/trials); fflush(file); numWon = 0; trialsTotTime = 0; trialsInitTotTime=0; progBar=0.0f; numBases=0; param.ransacIter+=step; } fclose(file); return res; //all right }
// // Apply filter // bool FilterTopoPlugin::applyFilter(QAction *filter, MeshModel &m, RichParameterSet & par, vcg::CallBackPos *cb) { // To run the retopology algorithm an istance of RetopoMeshBuilder is needed RetopMeshBuilder rm; // Load topology mesh MeshModel *userMesh = par.getMesh("userMesh"); // Load (input) original mesh MeshModel *inMesh = par.getMesh("inMesh"); // Load iterations value int it = par.getInt("it"); // Load distance value float dist = par.getAbsPerc("dist"); // Destination meshmodel: retopology mesh will replace flat topology mesh MeshModel * outM = par.getMesh("userMesh"); // Prepare mesh inMesh->updateDataMask(MeshModel::MM_FACEMARK); tri::UpdateNormals<CMeshO>::PerFaceNormalized(inMesh->cm); tri::UpdateFlags<CMeshO>::FaceProjection(inMesh->cm); // Init the retopology builder with original input mesh and distance value rm.init(inMesh, dist); // Apply the algorithm return rm.applyTopoMesh(*userMesh, *inMesh, it, dist, *outM); }
void SdfGpuPlugin::setupMesh(MeshDocument& md, ONPRIMITIVE onPrimitive ) { MeshModel* mm = md.mm(); CMeshO& m = mm->cm; //If on vertices, do some cleaning first if( onPrimitive == ON_VERTICES ) { int dup = tri::Clean<CMeshO>::RemoveDuplicateVertex(m); int unref = tri::Clean<CMeshO>::RemoveUnreferencedVertex(m); if (dup > 0 || unref > 0) Log("Removed %i duplicate and %i unreferenced vertices\n",dup,unref); } //Updating mesh metadata tri::UpdateBounding<CMeshO>::Box(m); vcg::tri::Allocator<CMeshO>::CompactVertexVector(m); vcg::tri::Allocator<CMeshO>::CompactFaceVector(m); vcg::tri::UpdateNormals<CMeshO>::PerVertexAngleWeighted(m); //Enable & Reset the necessary attributes switch(onPrimitive) { case ON_VERTICES: mm->updateDataMask(MeshModel::MM_VERTQUALITY); tri::UpdateQuality<CMeshO>::VertexConstant(m,0); break; case ON_FACES: mm->updateDataMask(MeshModel::MM_FACEQUALITY); mm->updateDataMask(MeshModel::MM_FACENORMAL); mm->updateDataMask(MeshModel::MM_FACECOLOR); tri::UpdateQuality<CMeshO>::FaceConstant(m,0); break; } if(!vcg::tri::HasPerVertexAttribute(m,"maxQualityDir") && onPrimitive == ON_VERTICES) mMaxQualityDirPerVertex = vcg::tri::Allocator<CMeshO>::AddPerVertexAttribute<Point3f>(m,std::string("maxQualityDir")); else if(!vcg::tri::HasPerFaceAttribute(m,"maxQualityDir") && onPrimitive == ON_FACES) mMaxQualityDirPerFace = vcg::tri::Allocator<CMeshO>::AddPerFaceAttribute<Point3f>(m,std::string("maxQualityDir")); }
template<class MESH_TYPE, class FEATURE_TYPE> bool FilterFeatureAlignment::ComputeFeatureOperation(MeshModel& m, typename FEATURE_TYPE::Parameters& param, CallBackPos *cb) { typedef MESH_TYPE MeshType; typedef FEATURE_TYPE FeatureType; //enables needed attributes m.updateDataMask(FeatureType::getRequirements()); //compute feature for the given mesh return FeatureType::ComputeFeature(m.cm, param, cb); }
float FilterFeatureAlignment::ConsensusOperation(MeshModel& mFix, MeshModel& mMov, typename CONSENSUS_TYPE::Parameters& param, CallBackPos *cb) { typedef CONSENSUS_TYPE ConsensusType; typedef typename ConsensusType::MeshType MeshType; typedef typename MeshType::ScalarType ScalarType; typedef typename MeshType::VertexType VertexType; typedef typename ConsensusType::Parameters ParamType; //enables needed attributes. These are used by the getClosest functor. mFix.updateDataMask(MeshModel::MM_VERTMARK); mMov.updateDataMask(MeshModel::MM_VERTMARK); ConsensusType cons; cons.SetFix(mFix.cm); cons.SetMove(mMov.cm); if(!cons.Init(param)) return -1.0f; return cons.Compute(param); }
bool EditSelectPlugin::StartEdit(MeshModel &m, GLArea *gla ) { gla->setCursor(QCursor(QPixmap(":/images/sel_rect.png"),1,1)); connect(this, SIGNAL(setSelectionRendering(bool)),gla,SLOT(setSelectFaceRendering(bool)) ); connect(this, SIGNAL(setSelectionRendering(bool)),gla,SLOT(setSelectVertRendering(bool)) ); setSelectionRendering(true); if(selectionMode) m.updateDataMask(MeshModel::MM_FACEFACETOPO); 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 FilterScreenedPoissonPlugin::applyFilter( const QString& filterName,MeshDocument& md,EnvWrap& env, vcg::CallBackPos* cb) { if (filterName == "Screened Poisson Surface Reconstruction") { MeshModel *mm =md.mm(); MeshModel *pm =md.addNewMesh("","Poisson mesh",false); md.setVisible(pm->id(),false); pm->updateDataMask(MeshModel::MM_VERTQUALITY); PoissonParam<Scalarm> pp; MeshModelPointStream<Scalarm> meshStream(mm->cm); MeshDocumentPointStream<Scalarm> documentStream(md); pp.MaxDepthVal = env.evalInt("depth"); pp.FullDepthVal = env.evalInt("fullDepth"); pp.CGDepthVal= env.evalInt("cgDepth"); pp.ScaleVal = env.evalFloat("scale"); pp.SamplesPerNodeVal = env.evalFloat("samplesPerNode"); pp.PointWeightVal = env.evalFloat("pointWeight"); pp.ItersVal = env.evalInt("iters"); pp.ConfidenceFlag = env.evalBool("confidence"); pp.NormalWeightsFlag = env.evalBool("nWeights"); pp.DensityFlag = true; if(env.evalBool("visibleLayer")) { MeshModel *m=0; while(m=md.nextVisibleMesh(m)) PoissonClean(m->cm, (pp.ConfidenceFlag || pp.NormalWeightsFlag)); Execute<Scalarm>(&documentStream,pm->cm,pp,cb); } else { PoissonClean(mm->cm, (pp.ConfidenceFlag || pp.NormalWeightsFlag)); Execute<Scalarm>(&meshStream,pm->cm,pp,cb); } pm->UpdateBoxAndNormals(); md.setVisible(pm->id(),true); return true; } return false; }
// // Plugin init // bool edit_topo::StartEdit(MeshModel &m, GLArea *gla) { parentGla = gla; gla->setCursor(QCursor(QPixmap(":/images/cursor_paint.png"),1,1)); // Init uniform grid float dist = m.cm.bbox.Diag(); // Init data masks m.updateDataMask(MeshModel::MM_FACEMARK); tri::UpdateNormals<CMeshO>::PerFaceNormalized(m.cm); tri::UpdateFlags<CMeshO>::FaceProjection(m.cm); // Init retopology model builder object rm.init(&m, dist); // Init miminum visible distance param (used only for labels rendering) _md = 0.03; // Init ui if (edit_topodialogobj == 0) { edit_topodialogobj = new edit_topodialog(gla->window()); dock = new QDockWidget(gla->window()); dock->setAllowedAreas(Qt::NoDockWidgetArea); dock->setWidget(edit_topodialogobj); QPoint p = gla->window()->mapToGlobal(QPoint(0,0)); dock->setGeometry(-5+p.x()+gla->window()->width()-edit_topodialogobj->width(),p.y(),edit_topodialogobj->width(),edit_topodialogobj->height()); dock->setFloating(true); } dock->setVisible(true); dock->layout()->update(); gla->update(); gla->setMouseTracking(true); // Connect slots connect(edit_topodialogobj, SIGNAL( mesh_create() ), this, SLOT( on_mesh_create() ) ); connect(edit_topodialogobj, SIGNAL( update_request() ), this, SLOT( on_update_request() ) ); return true; }
bool FilterFeatureAlignment::ExtractionOperation(MeshModel& m, typename ALIGNER_TYPE::Parameters& param, CallBackPos *cb) { typedef ALIGNER_TYPE AlignerType; typedef typename AlignerType::MeshType MeshType; typedef typename AlignerType::FeatureType FeatureType; //enables needed attributes m.updateDataMask(FeatureType::getRequirements()); //extract features vector<FeatureType*>* vecF = AlignerType::extractFeatures(param.numMovFeatureSelected, m.cm, param.samplingStrategy, cb); if(!vecF) return false; //something wrong! //clear old picked points, then, if requested, add all new points AlignerType::ClearPickedPoints(m.cm); if(param.pickPoints) AlignerType::AddPickedPoints(m.cm, *vecF); //add points //clean up vecF->clear(); delete vecF; vecF = NULL; return true; }
bool QualityMapperPlugin::StartEdit(MeshModel& m, GLArea *gla ) { if(!m.hasDataMask(MeshModel::MM_VERTQUALITY)) { QMessageBox::warning(gla, tr("Quality Mapper"), tr("The model has no vertex quality"), QMessageBox::Ok); return false; } QMap<int,RenderMode>::iterator it = gla->rendermodemap.find(m.id()); m.updateDataMask(MeshModel::MM_VERTCOLOR | MeshModel::MM_VERTQUALITY); if (it != gla->rendermodemap.end()) { it.value().setColorMode(GLW::CMPerVert); gla->update(); } if(_qualityMapperDialog==0) _qualityMapperDialog = new QualityMapperDialog(gla->window(), m, gla); //drawing histogram //bool ret = _qualityMapperDialog->initEqualizerHistogram(); if ( !_qualityMapperDialog->initEqualizerHistogram() ) { //EndEdit(m, gla); return false; } //drawing transferFunction _qualityMapperDialog->drawTransferFunction(); //dialog ready to be displayed. Show it now! _qualityMapperDialog->show(); connect(_qualityMapperDialog, SIGNAL(closingDialog()),gla,SLOT(endEdit()) ); return true; }
bool SdfPlugin::applyFilter(MeshDocument& md, RichParameterSet& pars, vcg::CallBackPos* cb){ enum ONPRIMITIVE{ON_VERTICES, ON_FACES} onPrimitive; MeshModel* mm = md.mm(); CMeshO& m = mm->cm; //--- Retrieve parameters float widenessRad = math::ToRad(pars.getFloat("coneWidth")); int raysPerCone = pars.getInt("numberRays"); onPrimitive = (ONPRIMITIVE) pars.getEnum("onPrimitive"); qDebug() << "which primitive?" << onPrimitive; float lo01pec = pars.getFloat("lowQuantile"); float hi01pec = pars.getFloat("hiQuantile"); assert( onPrimitive==ON_VERTICES && "Face mode not supported yet" ); //--- If on vertices, do some cleaning first if( onPrimitive == ON_VERTICES ){ int dup = tri::Clean<CMeshO>::RemoveDuplicateVertex(m); int unref = tri::Clean<CMeshO>::RemoveUnreferencedVertex(m); if (dup > 0 || unref > 0) Log("Removed %i duplicate and %i unreferenced vertices\n",dup,unref); } //--- Updating mesh metadata tri::UpdateBounding<CMeshO>::Box(m); tri::UpdateNormals<CMeshO>::PerFaceNormalized(m); tri::UpdateNormals<CMeshO>::PerVertexAngleWeighted(m); tri::UpdateNormals<CMeshO>::NormalizeVertex(m); tri::UpdateFlags<CMeshO>::FaceProjection(m); //--- Enable & Reset the necessary attributes switch(onPrimitive){ case ON_VERTICES: // qDebug() << "initializing vert quality"; mm->updateDataMask(MeshModel::MM_VERTQUALITY); tri::UpdateQuality<CMeshO>::VertexConstant(m,0); break; case ON_FACES: mm->updateDataMask(MeshModel::MM_FACEQUALITY); tri::UpdateQuality<CMeshO>::FaceConstant(m,0); break; } //--- Add the mesh to an indexing structure (fast ray intersection) Log("Initializing spatial accelleration..."); mm->updateDataMask(MeshModel::MM_FACEMARK); TriMeshGrid static_grid; //TODO: rename spatial index static_grid.Set(m.face.begin(), m.face.end()); Log("Initializing spatial accelleration... DONE!"); // since we are measuring the interior of the shape // A ray should never go beyond this value float maxDist=m.bbox.Diag(); // This is a small number to avoid self-intersection during ray // casting. It's a very common trick float epsilon = maxDist / 10000.0; //--- Ray casting vector<Ray3f> cone; vector<float> coneSdf; Ray3f ray; float t; for(unsigned int i=0; i<m.vert.size(); i++){ CVertexO& v = m.vert[i]; //--- Update progressbar cb( i/m.vert.size(), "Casting rays into volume..."); //--- Generate the set of cones ray.Set( v.P(), -v.N() ); ray.SetOrigin( ray.P(epsilon) ); generateRayCone( ray, widenessRad, raysPerCone, cone, coneSdf, (i==266) ); //--- Trace rays in cone float mind = +numeric_limits<float>::max(); float maxd = -numeric_limits<float>::max(); for(unsigned int j=0; j<cone.size(); j++){ bool hasInt = tri::DoRay<CMeshO,TriMeshGrid>(m,static_grid,cone[j],maxDist,t); coneSdf[j] = (hasInt==true) ? t : numeric_limits<float>::quiet_NaN(); mind = (hasInt && (t<mind)) ? t : mind; maxd = (hasInt && (t>maxd)) ? t : maxd; if( i==266 ){ qDebug() << " sampled: " << coneSdf[j] << " dir: " << toString(cone[j].Direction()) << " hasInt: " << hasInt; } } //--- Compute per-cone statistics Histogram<float> H; H.Clear(); H.SetRange( mind, maxd, 100); for(unsigned int j=0; j<cone.size(); j++) if(!math::IsNAN(coneSdf[j])) H.Add(coneSdf[j]); float loperc = H.Percentile(lo01pec); float hiperc = H.Percentile(hi01pec); if( i == 266){ qDebug() << "percentiles: " << loperc << " " << hiperc; } //--- Compute average of samples, throwing away outliers if( i == 266) qDebug() << "averaging samples"; float totVal = 0, totCnt = 0; for(unsigned int j=0; j<coneSdf.size(); j++) if( !math::IsNAN(coneSdf[j]) ){ // Histogram statistics valid only for dense sets (more 3 members..) if( coneSdf[j]<loperc || coneSdf[j]>hiperc && coneSdf.size()>3) continue; // Weight giving more importance to aligned samples float weight = cone[j].Direction().dot( ray.Direction() ); // Even more importance weight = powf( weight, 10 ); if( i==266 ){ qDebug() << "sampled: " << coneSdf[j] << "weight " << weight << " dir:" << toString(cone[j].Direction()); } totVal += weight*coneSdf[j]; totCnt += weight; } //--- Save in mesh v.Q() = totCnt>0 ? (totVal/totCnt) : 0; } //----------------------------------------------------------------------------// // // STEROIDS STARTS HERE // //----------------------------------------------------------------------------// //--- Create the medial cloud by offsetting the samples of the medial amount MeshModel* medCloud = md.addNewMesh("medial cloud.obj", NULL, false); for(unsigned int i=0; i<m.vert.size(); i++){ Ray3f r; r.Set(m.vert[i].P(), -m.vert[i].N()); tri::Allocator<CMeshO>::AddVertices(medCloud->cm,1); medCloud->cm.vert.back().P() = r.P(m.vert[i].Q() / 2 ); } //--- Data for distance queries vcg::tri::FaceTmark<CMeshO> mf; mf.SetMesh( &m ); vcg::face::PointDistanceBaseFunctor<float> PDistFunct; Log("querying real distances"); // Query the location of closest point on the mesh, then measure the difference float allowedDiff = .02; vector<float> realdistances(m.vn, 0); for(unsigned int i=0; i<m.vert.size(); i++){ Point3f currp = medCloud->cm.vert[i].P(); float minDist = maxDist; Point3f closest; GridClosest(static_grid, PDistFunct, mf, currp, maxDist, minDist, closest); float difference = m.vert[i].Q()/2.0 - minDist; m.vert[i].Q() = exp( -powf(difference/allowedDiff,2) ); } // Correct the viewmodel so that after this is done the original mesh // is shown in wireframe and the medial as a cloud. // mm->glw.cdm = vcg::GLW::DMWire; // show original mesh in wireframe medCloud->glw.cdm = vcg::GLW::DMPoints; // show cloud return true; }
bool BaseMeshIOPlugin::save(const QString &formatName,const QString &fileName, MeshModel &m, const int mask, const RichParameterSet & par, CallBackPos *cb, QWidget */*parent*/) { QString errorMsgFormat = "Error encountered while exportering file %1:\n%2"; string filename = QFile::encodeName(fileName).constData (); //string filename = fileName.toUtf8().data(); string ex = formatName.toUtf8().data(); bool binaryFlag = false; if(formatName.toUpper() == tr("STL") || formatName.toUpper() == tr("PLY")) binaryFlag = par.findParameter("Binary")->val->getBool(); if(formatName.toUpper() == tr("PLY")) { int result = tri::io::ExporterPLY<CMeshO>::Save(m.cm,filename.c_str(),mask,binaryFlag,cb); if(result!=0) { errorMessage = errorMsgFormat.arg(fileName, tri::io::ExporterPLY<CMeshO>::ErrorMsg(result)); return false; } return true; } if(formatName.toUpper() == tr("STL")) { int result = tri::io::ExporterSTL<CMeshO>::Save(m.cm,filename.c_str(),binaryFlag); if(result!=0) { errorMessage = errorMsgFormat.arg(fileName, tri::io::ExporterSTL<CMeshO>::ErrorMsg(result)); return false; } return true; } if(formatName.toUpper() == tr("WRL")) { int result = tri::io::ExporterWRL<CMeshO>::Save(m.cm,filename.c_str(),mask,cb); if(result!=0) { errorMessage = errorMsgFormat.arg(fileName, tri::io::ExporterWRL<CMeshO>::ErrorMsg(result)); return false; } return true; } if( formatName.toUpper() == tr("OFF")) { if(mask && tri::io::Mask::IOM_BITPOLYGONAL) m.updateDataMask(MeshModel::MM_FACEFACETOPO); int result = tri::io::Exporter<CMeshO>::Save(m.cm,filename.c_str(),mask,cb); if(result!=0) { errorMessage = errorMsgFormat.arg(fileName, tri::io::Exporter<CMeshO>::ErrorMsg(result)); return false; } return true; } if( formatName.toUpper() == tr("DXF") || formatName.toUpper() == tr("OBJ") ) { int result = tri::io::Exporter<CMeshO>::Save(m.cm,filename.c_str(),mask,cb); if(result!=0) { errorMessage = errorMsgFormat.arg(fileName, tri::io::Exporter<CMeshO>::ErrorMsg(result)); return false; } return true; } assert(0); // unknown format 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); 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 EditHolePlugin::StartEdit(MeshModel &m, GLArea *gla ) { m.updateDataMask(MeshModel::MM_FACEFACETOPO); if ( tri::Clean<CMeshO>::CountNonManifoldEdgeFF(m.cm) >0) { QMessageBox::critical(0, tr("Manifoldness Failure"), QString("Hole's managing requires manifoldness.")); return false; // can't continue, mesh can't be processed } // necessario per evitare di avere 2 istanze del filtro se si cambia mesh // senza chidere il filtro if(dialogFiller != 0) //EndEdit(m, gla); return false; // if plugin restart with another mesh, recomputing of hole is forced if(mesh != &m) { this->mesh = &m; this->gla = gla; mesh->clearDataMask(MeshModel::MM_FACEMARK); mesh->updateDataMask(MeshModel::MM_FACEMARK); } bridgeOptSldVal = 50; dialogFiller=new FillerDialog(gla->window()); dialogFiller->show(); dialogFiller->setAllowedAreas(Qt::NoDockWidgetArea); connect(dialogFiller->ui.operationTab, SIGNAL(currentChanged(int)), this, SLOT(skipTab(int)) ); connect(dialogFiller->ui.fillButton, SIGNAL(clicked()), this,SLOT(fill())); connect(dialogFiller->ui.acceptFillBtn, SIGNAL(clicked()), this, SLOT(acceptFill()) ); connect(dialogFiller->ui.cancelFillBtn, SIGNAL(clicked()), this, SLOT(cancelFill()) ); connect(dialogFiller->ui.manualBridgeBtn, SIGNAL(clicked()), this, SLOT(manualBridge()) ); connect(dialogFiller->ui.autoBridgeBtn, SIGNAL(clicked()), this, SLOT(autoBridge()) ); connect(dialogFiller->ui.nmHoleClosureBtn, SIGNAL(clicked()), this, SLOT(closeNMHoles()) ); connect(dialogFiller->ui.acceptBridgeBtn, SIGNAL(clicked()), this, SLOT(acceptBridges()) ); connect(dialogFiller->ui.clearBridgeBtn, SIGNAL(clicked()), this, SLOT(clearBridge()) ); connect(dialogFiller->ui.selfHoleChkB, SIGNAL(stateChanged(int)), this, SLOT(chekSingleBridgeOpt()) ); connect(dialogFiller->ui.diedralWeightSld, SIGNAL(valueChanged(int)), this, SLOT(updateDWeight(int))); connect(dialogFiller->ui.bridgeParamSld, SIGNAL(valueChanged(int)), this, SLOT(updateBridgeSldValue(int))); connect(dialogFiller, SIGNAL(SGN_Closing()),gla,SLOT(endEdit()) ); connect(dialogFiller->ui.holeTree->header(), SIGNAL(sectionCountChanged(int, int)), this, SLOT(resizeViewColumn()) ); if(holesModel != 0) { delete holeSorter; delete holesModel; } holesModel = new HoleListModel(&m); holesModel->holesManager.autoBridgeCB = new EditHoleAutoBridgingCB(dialogFiller->ui.infoLbl, 800); connect(holesModel, SIGNAL(SGN_Closing()),gla,SLOT(endEdit()) ); connect(holesModel, SIGNAL(SGN_needUpdateGLA()), this, SLOT(upGlA()) ); connect(holesModel, SIGNAL(SGN_ExistBridge(bool)), dialogFiller, SLOT(SLOT_ExistBridge(bool)) ); holeSorter = new HoleSorterFilter(); holeSorter->setSourceModel(holesModel); dialogFiller->ui.holeTree->setModel( holeSorter ); if(holesModel->holesManager.holes.size()==0) { QMessageBox::information(0, tr("No holes"), QString("Mesh have no hole to edit.")); //EndEdit(m, gla); return false; } else { Decorate(m, gla); //Decorate(m, gla); upGlA(); } return true; }
bool EditAreslpPlugin::StartEdit(MeshModel &mm, GLArea *gla) { qDebug()<<"EditAreslpPlugin StartEdit"; if(!mm.hasDataMask(MeshModel::MM_VERTQUALITY)) { mm.updateDataMask(MeshModel::MM_VERTQUALITY); } if(!mm.hasDataMask(MeshModel::MM_FACEQUALITY)) { mm.updateDataMask(MeshModel::MM_FACEQUALITY); } AreslpDialog dialog; dialog.exec(); std::vector<int> pointset=dialog.pointset_; std::vector<int> faceset=dialog.faceset_; std::vector<int> patchset=dialog.patchset_; //Debug the content of above two vector for(int i = 0; i < pointset.size(); i++) { qDebug()<<pointset[i]; } for(int i = 0; i < faceset.size(); i++) { qDebug()<<faceset[i]; } for(int i = 0; i < patchset.size(); i++) { qDebug()<<patchset[i]; } CMeshO& cm = mm.cm; int point_size = cm.vert.size(); if(pointset.size()!=0){ //先把之前设置的值清空 for(int i = 0; i < point_size; i++) { cm.vert[i].Q() = 0; } for(int i = 0; i < pointset.size(); i++) { cm.vert[pointset[i]].Q() = 1; } } int face_size=cm.face.size(); if(faceset.size()!=0){ //先把之前设置的值清空 for(int i = 0; i < face_size; i++) { cm.face[i].Q() = 0; } for(int i = 0; i < faceset.size(); i++) { cm.face[faceset[i]].Q() = 1; } } if(patchset.size()!=0){ //patch std::map<int,double> qm; for (int i = 0; i < patchset.size(); i++) { std::string tstring="faceq"; tstring.append(boost::lexical_cast<std::string>(patchset[i])); tstring.append(".txt"); qDebug()<<tstring.c_str(); std::ifstream ifile(tstring.c_str()); int ii; double v; while(ifile >> ii >> v) { // qDebug()<<i<<" "<<v; qm.insert(make_pair<int,double>(ii,v)); } ifile.close(); } for (int i = 0; i < face_size; i++) { if (qm.find(i)!=qm.end()) { cm.face[i].Q()=qm[i]; }else{ cm.face[i].Q()=0; } } }
bool EpochIO::open(const QString &formatName, const QString &fileName, MeshModel &m, int& mask,const RichParameterSet & /*par*/, CallBackPos *cb, QWidget *parent) { EpochReconstruction er; mask = vcg::tri::io::Mask::IOM_VERTCOLOR | vcg::tri::io::Mask::IOM_VERTQUALITY; // just to be sure... if (fileName.isEmpty()) return false; // initializing progress bar status if (cb != NULL) (*cb)(0, "Loading..."); // this change of dir is needed for subsequent texture/material loading QString FileNameDir = fileName.left(fileName.lastIndexOf("/")); QDir::setCurrent(FileNameDir); QString errorMsgFormat = "Error encountered while loading file %1:\n%2"; string stdfilename = QFile::encodeName(fileName).constData (); //string filename = fileName.toUtf8().data(); QDomDocument doc; if(formatName.toUpper() == tr("V3D") && fileName.endsWith(".v3d")) { QFile file(fileName); if (file.open(QIODevice::ReadOnly) && doc.setContent(&file)) { file.close(); QDomElement root = doc.documentElement(); if (root.nodeName() == tr("reconstruction")) { QDomNode nhead = root.firstChildElement("head"); for(QDomNode n = nhead.firstChildElement("meta"); !n.isNull(); n = n.nextSiblingElement("meta")) { if(!n.hasAttributes()) return false; QDomNamedNodeMap attr= n.attributes(); if(attr.contains("name")) er.name = (attr.namedItem("name")).nodeValue() ; if(attr.contains("author")) er.author = (attr.namedItem("author")).nodeValue() ; if(attr.contains("created")) er.created = (attr.namedItem("created")).nodeValue() ; } for(QDomNode n = root.firstChildElement("model"); !n.isNull(); n = n.nextSiblingElement("model")) { EpochModel em; em.Init(n); er.modelList.push_back(em); } } } } epochDialog->setEpochReconstruction( &er, cb); do { epochDialog->exportToPLY=false; //Here we invoke the modal dialog and wait for its termination int continueValue = epochDialog->exec(); // The user has pressed the ok button: now start the real processing: if(epochDialog->exportToPLY == true) qDebug("Starting the ply exporting process"); int t0=clock(); logFP=fopen("epoch.log","w"); int subSampleVal = epochDialog->subsampleSpinBox->value(); int minCountVal= epochDialog->minCountSpinBox->value(); float maxCCDiagVal= epochDialog->maxCCDiagSpinBox->value(); int mergeResolution=epochDialog->mergeResolutionSpinBox->value(); int smoothSteps=epochDialog->smoothSpinBox->value(); bool closeHole = epochDialog->holeCheckBox->isChecked(); int maxHoleSize = epochDialog->holeSpinBox->value(); if (continueValue == QDialog::Rejected) { QMessageBox::warning(parent, "Open V3d format","Aborted"); return false; } CMeshO mm; QTableWidget *qtw=epochDialog->imageTableWidget; float MinAngleCos=cos(vcg::math::ToRad(epochDialog->qualitySpinBox->value())); bool clustering=epochDialog->fastMergeCheckBox->isChecked(); bool removeSmallCC=epochDialog->removeSmallCCCheckBox->isChecked(); vcg::tri::Clustering<CMeshO, vcg::tri::AverageColorCell<CMeshO> > Grid; int selectedNum=0,selectedCount=0; int i; for(i=0;i<qtw->rowCount();++i) if(qtw->isItemSelected(qtw->item(i,0))) ++selectedNum; if(selectedNum==0) { QMessageBox::warning(parent, "Open V3d format","No range map selected. Nothing loaded"); return false; } bool dilationFlag = epochDialog->dilationCheckBox->isChecked(); int dilationN = epochDialog->dilationNumPassSpinBox->value(); int dilationSz = epochDialog->dilationSizeSlider->value() * 2 + 1; bool erosionFlag = epochDialog->erosionCheckBox->isChecked(); int erosionN = epochDialog->erosionNumPassSpinBox->value(); int erosionSz = epochDialog->erosionSizeSlider->value() * 2 + 1; float scalingFactor = epochDialog->scaleLineEdit->text().toFloat(); std::vector<string> savedMeshVector; bool firstTime=true; QList<EpochModel>::iterator li; for(li=er.modelList.begin(), i=0;li!=er.modelList.end();++li,++i) { if(qtw->isItemSelected(qtw->item(i,0))) { ++selectedCount; mm.Clear(); int tt0=clock(); (*li).BuildMesh(mm,subSampleVal,minCountVal,MinAngleCos,smoothSteps, dilationFlag, dilationN, dilationSz, erosionFlag, erosionN, erosionSz,scalingFactor); int tt1=clock(); if(logFP) fprintf(logFP,"** Mesh %i : Build in %i\n",selectedCount,tt1-tt0); if(epochDialog->exportToPLY) { QString plyFilename =(*li).textureName.left((*li).textureName.length()-4); plyFilename.append(".x.ply"); savedMeshVector.push_back(qPrintable(plyFilename)); int mask= tri::io::Mask::IOM_VERTCOORD + tri::io::Mask::IOM_VERTCOLOR + tri::io::Mask::IOM_VERTQUALITY; tri::io::ExporterPLY<CMeshO>::Save(mm,qPrintable(plyFilename),mask); } else { if(clustering) { if (firstTime) { //Grid.Init(mm.bbox,100000); vcg::tri::UpdateBounding<CMeshO>::Box(mm); //Grid.Init(mm.bbox,1000.0*pow(10.0,mergeResolution),mm.bbox.Diag()/1000.0f); Grid.Init(mm.bbox,100000.0*pow(10.0,mergeResolution)); firstTime=false; } Grid.AddMesh(mm); } else tri::Append<CMeshO,CMeshO>::Mesh(m.cm,mm); // append mesh mr to ml } int tt2=clock(); if(logFP) fprintf(logFP,"** Mesh %i : Append in %i\n",selectedCount,tt2-tt1); } if (cb)(*cb)(selectedCount*90/selectedNum, "Building meshes"); } if (cb != NULL) (*cb)(90, "Final Processing: clustering"); if(clustering) { Grid.ExtractPointSet(m.cm); } if(epochDialog->exportToPLY) { QString ALNfilename = fileName.left(fileName.length()-4).append(".aln"); ALNParser::SaveALN(qPrintable(ALNfilename), savedMeshVector); } int t1=clock(); if(logFP) fprintf(logFP,"Extracted %i meshes in %i\n",selectedCount,t1-t0); if (cb != NULL) (*cb)(95, "Final Processing: Removing Small Connected Components"); if(removeSmallCC) { vcg::tri::UpdateBounding<CMeshO>::Box(m.cm); // updates bounding box m.updateDataMask(MeshModel::MM_FACEFACETOPO | MeshModel::MM_FACEFLAGBORDER | MeshModel::MM_FACEMARK); tri::Clean<CMeshO>::RemoveSmallConnectedComponentsDiameter(m.cm,m.cm.bbox.Diag()*maxCCDiagVal/100.0); } int t2=clock(); if(logFP) fprintf(logFP,"Topology and removed CC in %i\n",t2-t1); vcg::tri::UpdateBounding<CMeshO>::Box(m.cm); // updates bounding box if (cb != NULL) (*cb)(97, "Final Processing: Closing Holes"); if(closeHole) { m.updateDataMask(MeshModel::MM_FACEFACETOPO | MeshModel::MM_FACEFLAGBORDER | MeshModel::MM_FACEMARK); tri::UpdateNormals<CMeshO>::PerVertexNormalizedPerFace(m.cm); vcg::tri::Hole<CMeshO>::EarCuttingFill<vcg::tri::MinimumWeightEar< CMeshO> >(m.cm,maxHoleSize,false); } if (cb != NULL) (*cb)(100, "Done"); // vcg::tri::UpdateNormals<CMeshO>::PerVertex(m.cm); // updates normals m.updateDataMask(MeshModel::MM_VERTCOLOR); int t3=clock(); if(logFP) fprintf(logFP,"---------- Total Processing Time%i\n\n\n",t3-t0); if(logFP) fclose(logFP); logFP=0; } while(epochDialog->exportToPLY); 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 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); } // LP: save output if(mOnPrimitive == ON_FACES) { CMeshO& cm=mm->cm; if(!mm->hasDataMask(MeshModel::MM_VERTFACETOPO)) { mm->updateDataMask(MeshModel::MM_VERTFACETOPO); } if(!mm->hasDataMask(MeshModel::MM_VERTCURV)) { mm->updateDataMask(MeshModel::MM_VERTCURV); // vcg::tri::UpdateCurvature<CMeshO>::VertexCurvature(cm); } //当前目录 QDir dir; //dir.currentPath(); //设置输出文件 std::string ofs=dir.currentPath().toStdString(); ofs.append("/fq_ml.txt"); qDebug()<<"ofs:"<<ofs.c_str(); ofstream oo(ofs.c_str()); int face_size=cm.face.size(); for (int i = 0; i < face_size; i++) { float gc=cm.face[i].Q(); oo<<i<<" "<<gc<<endl; } oo.close(); } 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; }
// 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 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; }