void EditVirtualScanPlugin::go( void ) { assert( glArea && inputMeshModel ); CMeshO* firstCloud = 0, *secondCloud = 0; MeshDocument* mDoc = glArea->meshDoc; MeshModel* tmpModel = 0; if( unifyClouds ) { tmpModel = mDoc->addNewMesh( "VS Point Cloud", 0, false ); firstCloud = &( tmpModel->cm ); secondCloud = firstCloud; } else { tmpModel = mDoc->addNewMesh( "VS Uniform Samples", 0, false ); firstCloud = &( tmpModel->cm ); tmpModel = mDoc->addNewMesh( "VS Feature Samples", 0, false ); secondCloud = &( tmpModel->cm ); } MyGLWidget* tmpWidget = new MyGLWidget ( ¶ms, inputMeshModel, firstCloud, secondCloud, glArea ); bool ok = tmpWidget->result; if( !ok ) { QString errorMessage = tmpWidget->errorString; Log( errorMessage.toStdString().c_str() ); } delete tmpWidget; }
bool FilterSSynth::applyFilter(QAction* filter, MeshDocument &md, RichParameterSet & par, vcg::CallBackPos *cb) { md.addNewMesh("",this->filterName(ID(filter))); QWidget * parent=(QWidget*)this->parent(); RichParameter* grammar=par.findParameter(QString("grammar")); RichParameter* seed=par.findParameter(QString("seed")); int sphereres=par.findParameter("sphereres")->val->getInt(); this->renderTemplate=GetTemplate(sphereres); if(this->renderTemplate!=QString::Null()){ QString path=ssynth(grammar->val->getString(),-50,seed->val->getInt(),cb); if(QFile::exists(path)){ QFile file(path); int mask; QString name(file.fileName()); openX3D(name,*(md.mm()),mask,cb); file.remove(); return true; } else{ QString message=QString("An error occurred during the mesh generation:" ).append(path); QMessageBox::critical(parent,"Error",message); return false; } } else{ QMessageBox::critical(parent,"Error","Sphere resolution must be between 1 and 4"); return false; } }
bool MeshDocumentFromNvm(MeshDocument &md, QString filename_nvm, QString model_filename) { md.addNewMesh(model_filename,QString("model")); std::vector<vcg::Shotf> shots; const QString path = QFileInfo(filename_nvm).absolutePath(); //const QString path_im = QFileInfo(image_list_filename).absolutePath()+QString("/"); std::vector<std::string> image_filenames; vcg::tri::io::ImporterNVM<CMeshO>::Open(md.mm()->cm,shots,image_filenames,qPrintable(filename_nvm)); md.mm()->updateDataMask(MeshModel::MM_VERTCOLOR); QString curr_path = QDir::currentPath(); //QFileInfo imi(image_list_filename); //QDir::setCurrent(imi.absoluteDir().absolutePath()); QStringList image_filenames_q; for(unsigned int i = 0; i < image_filenames.size(); ++i) image_filenames_q.push_back(QString::fromStdString(image_filenames[i])); for(size_t i=0 ; i<shots.size() ; i++){ md.addNewRaster(); const QString fullpath_image_filename = image_filenames_q[i]; md.rm()->addPlane(new Plane(fullpath_image_filename,Plane::RGBA)); md.rm()->setLabel(image_filenames_q[i].section('/',1,2)); md.rm()->shot = shots[i]; /*md.rm()->shot.Intrinsics.ViewportPx[0]=md.rm()->currentPlane->image.width(); md.rm()->shot.Intrinsics.ViewportPx[1]=md.rm()->currentPlane->image.height(); md.rm()->shot.Intrinsics.CenterPx[0]=(int)((double)md.rm()->shot.Intrinsics.ViewportPx[0]/2.0f); md.rm()->shot.Intrinsics.CenterPx[1]=(int)((double)md.rm()->shot.Intrinsics.ViewportPx[1]/2.0f);*/ } QDir::setCurrent(curr_path); return true; }
bool MeshGridPlugin::applyFilter(QAction *algo, MeshDocument &md, RichParameterSet & par, vcg::CallBackPos *cb) { int cols = par.getInt("numVertX"); int rows = par.getInt("numVertY"); float totalw = 1.0; float totalh = 1.0; int w = cols+1; int h = rows+1; float wl = 1.0/cols; float hl = 1.0/rows; qDebug("w %d h %d",w,h); if(w <= 0 || h <= 0) { return false; } md.addNewMesh("",QString("%1_%2").arg(rows).arg(cols)); MeshModel &m=*(md.mm()); // use Grid function to generate Grid std::vector<float> data(w*h,0); tri::Grid<CMeshO>(m.cm, w, h, 1, 1, &data[0]); { // 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) // { // // qDebug("pos x: %f y: %f",(*vi).P()[0],(*vi).P()[1]); // //(*vi).P()[0] = (*vi).P()[0] - (wld * halfw); // //(*vi).P()[1] = (*vi).P()[1] - (hld * halfh); // // (*vi).P()[0] = (*vi).P()[0] - totalw/2; // // (*vi).P()[1] = (*vi).P()[1] - totalh/2; // // qDebug("after pos x: %f y: %f",(*vi).P()[0],(*vi).P()[1]); // } } // update bounding box, normals // Matrix44f rot; rot.SetRotateDeg(180,Point3f(0,1,0)); // tri::UpdatePosition<CMeshO>::Matrix(m.cm,rot,false); tri::UpdateNormal<CMeshO>::PerVertexNormalizedPerFace(m.cm); tri::UpdateNormal<CMeshO>::NormalizePerFace(m.cm); tri::UpdateBounding<CMeshO>::Box(m.cm); CMeshO::VertexIterator vi; return true; }
bool FilterCreateIso::applyFilter(QAction *filter, MeshDocument &md, RichParameterSet & par, vcg::CallBackPos * cb) { md.addNewMesh("",this->filterName(ID(filter))); MeshModel &m=*(md.mm()); if(filter->text() == filterName(FP_CREATEISO) ) { SimpleVolume<SimpleVoxel<Scalarm> > volume; typedef vcg::tri::TrivialWalker<CMeshO, SimpleVolume<SimpleVoxel<Scalarm> > > MyWalker; typedef vcg::tri::MarchingCubes<CMeshO, MyWalker> MyMarchingCubes; MyWalker walker; const int gridSize=par.getInt("Resolution"); // Simple initialization of the volume with some cool perlin noise volume.Init(Point3i(gridSize,gridSize,gridSize), Box3m(Point3m(0,0,0),Point3m(1,1,1))); for(int i=0;i<gridSize;i++) for(int j=0;j<gridSize;j++) for(int k=0;k<gridSize;k++) volume.Val(i,j,k)=(j-gridSize/2)*(j-gridSize/2)+(k-gridSize/2)*(k-gridSize/2) + i*gridSize/5*(float)math::Perlin::Noise(i*.2,j*.2,k*.2); printf("[MARCHING CUBES] Building mesh..."); MyMarchingCubes mc(m.cm, walker); walker.BuildMesh<MyMarchingCubes>(m.cm, volume, mc, (gridSize*gridSize)/10,cb); m.UpdateBoxAndNormals(); } return true; }
bool AlgoDemoPlugin::applyFilter(QAction *algo, MeshDocument &md, RichParameterSet & par, vcg::CallBackPos *cb) { MeshModel* pm = md.mm(); if(pm == NULL) return false; /* MainWindow* mainwindow; foreach (QWidget *widget, QApplication::topLevelWidgets()) { MainWindow* mainwindow = dynamic_cast<MainWindow*>(widget); if (mainwindow) { break; } } if (mainwindow == NULL) { return false; } MeshModel* prm = mainwindow->newProjectAddMesh("resultant mesh","resultant mesh"); GLArea* newGLA = mainwindow->newProject("resultant mesh"); MeshModel* prm = newGLA->md()->addNewMesh("","resultant mesh",true); */ MeshModel* prm = md.addNewMesh("","resultant mesh",true); pm->cm.vert; //vertics pm->cm.face; //faces pm->cm.selVertVector; //landmarks vcg::tri::Append<CMeshO,CMeshO>::MeshCopy(prm->cm,pm->cm); CMeshO::VertexIterator vi; for(vi = pm->cm.vert.begin(); vi != pm->cm.vert.end(); ++vi) { //prm->cm.addVertex (/*const aol::Vec3< RealType > &coords*/); // qDebug("pos x: %f y: %f",(*vi).P()[0],(*vi).P()[1]); //(*vi).P()[0] = (*vi).P()[0] - (wld * halfw); //(*vi).P()[1] = (*vi).P()[1] - (hld * halfh); // (*vi).P()[0] = (*vi).P()[0] - totalw/2; // (*vi).P()[1] = (*vi).P()[1] - totalh/2; // qDebug("after pos x: %f y: %f",(*vi).P()[0],(*vi).P()[1]); } CMeshO::FaceIterator vf; for(vf = pm->cm.face.begin(); vf!= pm->cm.face.end(); ++vf) { //(*vf).V() } return true; }
void RandomFillFilter::addRandomObject(MeshDocument& md, MeshModel* filler, const vcg::Point3<float>& origin, int meshID){ ostringstream meshName; meshName << "randomFillMesh" << meshID; MeshModel* meshCopy = md.addNewMesh(meshName.str().c_str()); vcg::tri::Append<CMeshO,CMeshO>::Mesh(meshCopy->cm, filler->cm, false, true); meshCopy->cm.Tr = filler->cm.Tr; meshCopy->cm.Tr.SetColumn(3, meshCopy->cm.Tr.GetColumn3(3) + origin); }
bool MeshDocumentFromBundler(MeshDocument &md, QString filename_out,QString image_list_filename, QString model_filename) { md.addNewMesh(model_filename,QString("model")); std::vector<Shotm> shots; const QString path = QFileInfo(filename_out).absolutePath(); const QString path_im = QFileInfo(image_list_filename).absolutePath()+QString("/"); std::vector<std::string> image_filenames; vcg::tri::io::ImporterOUT<CMeshO>::Open(md.mm()->cm,shots,image_filenames, qUtf8Printable(filename_out), qUtf8Printable(image_list_filename)); md.mm()->updateDataMask(MeshModel::MM_VERTCOLOR); QString curr_path = QDir::currentPath(); QFileInfo imi(image_list_filename); // QStringList image_filenames_q; for(unsigned int i = 0; i < image_filenames.size(); ++i) { QImageReader sizeImg(QString::fromStdString(image_filenames[i])); if(sizeImg.size()==QSize(-1,-1)) image_filenames_q.push_back(path_im+QString::fromStdString(image_filenames[i])); else image_filenames_q.push_back(QString::fromStdString(image_filenames[i])); } QDir::setCurrent(imi.absoluteDir().absolutePath()); for(size_t i=0 ; i<shots.size() ; i++) { md.addNewRaster(); const QString fullpath_image_filename = image_filenames_q[int(i)]; md.rm()->addPlane(new Plane(fullpath_image_filename,Plane::RGBA)); int count=fullpath_image_filename.count('\\'); if (count==0) { count=fullpath_image_filename.count('/'); md.rm()->setLabel(fullpath_image_filename.section('/',count,1)); } else md.rm()->setLabel(fullpath_image_filename.section('\\',count,1)); md.rm()->shot = shots[i]; } QDir::setCurrent(curr_path); 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; }
// 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; }
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; }
// The Real Core Function doing the actual mesh processing. bool FilterCreate::applyFilter(QAction *filter, MeshDocument &md, RichParameterSet & par, vcg::CallBackPos * /*cb*/) { MeshModel* m=md.addNewMesh("",this->filterName(ID(filter))); switch(ID(filter)) { case CR_TETRAHEDRON : vcg::tri::Tetrahedron<CMeshO>(m->cm); break; case CR_ICOSAHEDRON: vcg::tri::Icosahedron<CMeshO>(m->cm); break; case CR_DODECAHEDRON: vcg::tri::Dodecahedron<CMeshO>(m->cm); m->updateDataMask(MeshModel::MM_POLYGONAL); break; case CR_OCTAHEDRON: vcg::tri::Octahedron<CMeshO>(m->cm); break; case CR_TORUS: { float hRadius=par.getFloat("hRadius"); float vRadius=par.getFloat("vRadius"); int hSubdiv=par.getInt("hSubdiv"); int vSubdiv=par.getInt("vSubdiv"); vcg::tri::Torus(m->cm,hRadius,vRadius,hSubdiv,vSubdiv); break; } case CR_RANDOM_SPHERE: { CMeshO tt; int pointNum = par.getInt("pointNum"); int oversamplingFactor =100; if(pointNum <= 100) oversamplingFactor = 1000; if(pointNum >= 10000) oversamplingFactor = 50; if(pointNum >= 100000) oversamplingFactor = 20; vcg::math::MarsenneTwisterRNG rng; vcg::tri::Allocator<CMeshO>::AddVertices(tt,pointNum*50); for(CMeshO::VertexIterator vi=tt.vert.begin();vi!=tt.vert.end();++vi) vcg::math::GeneratePointOnUnitSphereUniform(rng,vi->P()); vcg::tri::UpdateBounding<CMeshO>::Box(tt); const float SphereArea = 4*M_PI; float poissonRadius = 2.0*sqrt((SphereArea / float(pointNum*2))/M_PI); std::vector<vcg::Point3f> poissonSamples; vcg::tri::TrivialSampler<CMeshO> pdSampler(poissonSamples); vcg::tri::SurfaceSampling<CMeshO, vcg::tri::TrivialSampler<CMeshO> >::PoissonDiskParam pp; vcg::tri::SurfaceSampling<CMeshO,vcg::tri::TrivialSampler<CMeshO> >::PoissonDiskPruning(pdSampler, tt, poissonRadius, pp); m->cm.Clear(); vcg::tri::Allocator<CMeshO>::AddVertices(m->cm,poissonSamples.size()); for(size_t i=0;i<poissonSamples.size();++i) { m->cm.vert[i].P()=poissonSamples[i]; m->cm.vert[i].N()=m->cm.vert[i].P(); } } break; case CR_SPHERE: { int rec = par.getInt("subdiv"); float radius = par.getFloat("radius"); m->cm.face.EnableFFAdjacency(); m->updateDataMask(MeshModel::MM_FACEFACETOPO); assert(vcg::tri::HasPerVertexTexCoord(m->cm) == false); vcg::tri::Sphere<CMeshO>(m->cm,rec); for(CMeshO::VertexIterator vi = m->cm.vert.begin();vi!= m->cm.vert.end();++vi) vi->P()=vi->P()*radius; break; } case CR_BOX: { float sz=par.getFloat("size"); vcg::Box3f b(vcg::Point3f(1,1,1)*(sz/2),vcg::Point3f(1,1,1)*(-sz/2)); vcg::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"); vcg::tri::Cone<CMeshO>(m->cm,r0,r1,h,subdiv); break; } vcg::tri::UpdateBounding<CMeshO>::Box(m->cm); vcg::tri::UpdateNormal<CMeshO>::PerVertexNormalizedPerFaceNormalized(m->cm); return true; }
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; }
// The Real Core Function doing the actual mesh processing. // Move Vertex of a random quantity bool PoissonPlugin::applyFilter(QAction *filter, MeshDocument &md, RichParameterSet & par, vcg::CallBackPos *cb) { MeshModel &m=*md.mm(); MeshModel &pm =*md.addNewMesh("","Poisson mesh"); vector<Point3D<float> > Pts(m.cm.vn); vector<Point3D<float> > Nor(m.cm.vn); CoredVectorMeshData mesh; if (m.hasDataMask(MeshModel::MM_WEDGTEXCOORD)){ m.clearDataMask(MeshModel::MM_WEDGTEXCOORD); } if (m.hasDataMask(MeshModel::MM_VERTTEXCOORD)){ m.clearDataMask(MeshModel::MM_VERTTEXCOORD); } //Useless control on the normals. It can just avoid crashes derived from an importer setting up to [0.0f,0.0f,0.0f] the normal vectors of a mesh without per-vertex normal attribute. int zeronrm = 0; for(CMeshO::VertexIterator vi=m.cm.vert.begin(); vi!=m.cm.vert.end(); ++vi) { if(!(*vi).IsD()) { if ((*vi).N() == vcg::Point3f(0.0f,0.0f,0.0f)) ++zeronrm; } } if (zeronrm == m.cm.vn) { Log(GLLogStream::SYSTEM,"All the normal vectors are set to [0.0,0.0,0.0]. Poisson reconstruction filter requires a set of valid per-vertex normal. Filter will be aborted."); return false; } int cnt=0; for(CMeshO::VertexIterator vi=m.cm.vert.begin(); vi!=m.cm.vert.end(); ++vi) if(!(*vi).IsD()){ (*vi).N().Normalize(); for(int ii=0;ii<3;++ii){ Pts[cnt].coords[ii]=(*vi).P()[ii]; Nor[cnt].coords[ii]=(*vi).N()[ii]; } ++cnt; } assert(cnt==m.cm.vn); // Log function dump textual info in the lower part of the MeshLab screen. PoissonParam pp; pp.Depth=par.getInt("OctDepth"); pp.SamplesPerNode = par.getFloat("SamplesPerNode"); pp.SolverDivide=par.getInt("SolverDivide"); pp.Offset = par.getFloat("Offset"); Point3D<float> center; float scale; int ret= Execute2(pp, Pts, Nor, mesh,center,scale,cb); mesh.resetIterator(); int vm = mesh.outOfCorePointCount()+mesh.inCorePoints.size(); int fm = mesh.triangleCount(); Log("Successfully created a mesh of %i vert and %i faces",vm,fm); //m.cm.Clear(); tri::Allocator<CMeshO>::AddVertices(pm.cm,vm); tri::Allocator<CMeshO>::AddFaces(pm.cm,fm); Point3D<float> p; int i; for (i=0; i < int(mesh.inCorePoints.size()); i++){ p=mesh.inCorePoints[i]; pm.cm.vert[i].P()[0] = p.coords[0]*scale+center.coords[0]; pm.cm.vert[i].P()[1] = p.coords[1]*scale+center.coords[1]; pm.cm.vert[i].P()[2] = p.coords[2]*scale+center.coords[2]; } for (int ii=0; ii < mesh.outOfCorePointCount(); ii++){ mesh.nextOutOfCorePoint(p); pm.cm.vert[ii+i].P()[0] = p.coords[0]*scale+center.coords[0]; pm.cm.vert[ii+i].P()[1] = p.coords[1]*scale+center.coords[1]; pm.cm.vert[ii+i].P()[2] = p.coords[2]*scale+center.coords[2]; } TriangleIndex tIndex; int inCoreFlag; int nr_faces=mesh.triangleCount(); for (i=0; i < nr_faces; i++){ // // create and fill a struct that the ply code can handle // mesh.nextTriangle(tIndex,inCoreFlag); if(!(inCoreFlag & CoredMeshData::IN_CORE_FLAG[0])){tIndex.idx[0]+=int(mesh.inCorePoints.size());} if(!(inCoreFlag & CoredMeshData::IN_CORE_FLAG[1])){tIndex.idx[1]+=int(mesh.inCorePoints.size());} if(!(inCoreFlag & CoredMeshData::IN_CORE_FLAG[2])){tIndex.idx[2]+=int(mesh.inCorePoints.size());} for(int j=0; j < 3; j++) { pm.cm.face[i].V(j) = &pm.cm.vert[tIndex.idx[j]]; } //ply_put_element(ply, (void *) &ply_face); //delete[] ply_face.vertices; } // for, write faces // for(int i=0;i<mesh.inCorePoints.size();++i){ // mesh.triangles[i].idx[0]+=mesh.inCorePoints.size(); // mesh.triangles[i].idx[1]+=mesh.inCorePoints.size(); // mesh.triangles[i].idx[2]+=mesh.inCorePoints.size(); // } // Build(m.cm,mesh.inCorePoints,mesh.triangles); Log("Successfully created a mesh of %i faces",pm.cm.vn); pm.UpdateBoxAndNormals(); 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 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; }
// 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; }