void Surface_DifferentialProperties_Plugin::computeNormal( const QString& mapName, const QString& positionAttributeName, const QString& normalAttributeName, bool autoUpdate) { MapHandler<PFP2>* mh = static_cast<MapHandler<PFP2>*>(m_schnapps->getMap(mapName)); if(mh == NULL) return; VertexAttribute<PFP2::VEC3, PFP2::MAP> position = mh->getAttribute<PFP2::VEC3, VERTEX>(positionAttributeName); if(!position.isValid()) return; VertexAttribute<PFP2::VEC3, PFP2::MAP> normal = mh->getAttribute<PFP2::VEC3, VERTEX>(normalAttributeName); if(!normal.isValid()) normal = mh->addAttribute<PFP2::VEC3, VERTEX>(normalAttributeName); PFP2::MAP* map = mh->getMap(); Algo::Surface::Geometry::computeNormalVertices<PFP2>(*map, position, normal); computeNormalLastParameters[mapName] = ComputeNormalParameters(positionAttributeName, normalAttributeName, autoUpdate); mh->notifyAttributeModification(normal); }
void Surface_Subdivision_Plugin::CCSubdivision( const QString& mapName, const QString& positionAttributeName, bool interp) { MapHandler<PFP2>* mh = static_cast<MapHandler<PFP2>*>(m_schnapps->getMap(mapName)); if(mh == NULL) return; VertexAttribute<PFP2::VEC3, PFP2::MAP> position = mh->getAttribute<PFP2::VEC3, VERTEX>(positionAttributeName); if(!position.isValid()) return; pythonRecording("CCSubdivision", "", mapName, positionAttributeName,interp); PFP2::MAP* map = mh->getMap(); if (interp) Algo::Surface::Modelisation::CatmullClarkInterpolSubdivision<PFP2>(*map, position); else Algo::Surface::Modelisation::CatmullClarkSubdivision<PFP2>(*map, position); mh->notifyAttributeModification(position); mh->notifyConnectivityModification(); foreach(View* view, mh->getLinkedViews()) view->updateGL(); }
/** * @brief test if map has a Vertex Attribute of VEC3 named name * @param map the map * @param name name of attribute */ void testVAbyNames(MAP& map, const std::string& name) { VertexAttribute<VEC3, MAP> testPos = map.getAttribute<VEC3, VERTEX, MAP>(name); if (testPos.isValid()) std::cout << "Attribute "<< name <<" valid"<< std::endl; else std::cout << "Attribute "<< name <<"invalid"<< std::endl; }
void UniversalLoader<MapType, AttrTypeLoader>::UnpackOnVertex(MapType& map, const unsigned int* verticesId, const AHEMHeader* hdr, const char* attrName, const void* buffer) const { VertexAttribute<typename AttrTypeLoader::ATTR_TYPE> attr = map.template getAttribute<typename AttrTypeLoader::ATTR_TYPE, VERTEX>(attrName); if (!attr.isValid()) attr = map.template addAttribute<typename AttrTypeLoader::ATTR_TYPE, VERTEX>(attrName); char* p = (char*)buffer; for(unsigned int i = 0 ; i < hdr->meshHdr.vxCount ; i++) { AttrTypeLoader::Extract(&attr[verticesId[i]], p); p += AttrTypeLoader::TYPE_SIZE_IN_BUFFER; } }
void AHEMImporter<PFP>::LoadPosition(AHEMAttributeDescriptor* posDescr) { VertexAttribute<typename PFP::VEC3, typename PFP::MAP> position = map->template getAttribute<typename PFP::VEC3, VERTEX, typename PFP::MAP>("position"); if (!position.isValid()) position = map->template addAttribute<typename PFP::VEC3, VERTEX, typename PFP::MAP>("position"); f.seekg(posDescr->fileStartOffset, std::ios_base::beg); f.read(buffer, posDescr->attributeChunkSize); float* q = (float*)buffer; for(unsigned int i = 0 ; i < hdr.meshHdr.vxCount ; i++) { position[verticesId[i]] = typename PFP::VEC3(q[0], q[1], q[2]); q += 3; } }
bool MeshTablesVolume<PFP>::importTs(const std::string& filename, std::vector<std::string>& attrNames) { // VertexAttribute<VEC3> position = m_map.template getAttribute<VEC3, VERTEX>("position") ; if (!position.isValid()) position = m_map.template addAttribute<VEC3, VERTEX>("position") ; attrNames.push_back(position.name()) ; // VertexAttribute<REAL> scalar = m_map.template getAttribute<REAL, VERTEX>("scalar"); if (!scalar.isValid()) scalar = m_map.template addAttribute<REAL, VERTEX>("scalar") ; attrNames.push_back(scalar.name()) ; // AttributeContainer& container = m_map.template getAttributeContainer<VERTEX>() ; // open file std::ifstream fp(filename.c_str(), std::ios::in); if (!fp.good()) { CGoGNerr << "Unable to open file " << filename << CGoGNendl; return false; } std::string ligne; // reading number of vertices/tetrahedra std::getline (fp, ligne); std::stringstream oss(ligne); oss >> m_nbVertices; oss >> m_nbVolumes; //reading vertices std::vector<unsigned int> verticesID; verticesID.reserve(m_nbVertices); for(unsigned int i = 0; i < m_nbVertices; ++i) { do { std::getline (fp, ligne); } while (ligne.size() == 0); std::stringstream oss(ligne); float x,y,z; oss >> x; oss >> y; oss >> z; VEC3 pos(x,y,z); unsigned int id = container.insertLine(); position[id] = pos; verticesID.push_back(id); float scal; oss >> scal; scalar[id] = scal; } //Read and embed all tetrahedrons for(unsigned int i = 0; i < m_nbVolumes ; ++i) { do { std::getline(fp,ligne); } while(ligne.size() == 0); std::stringstream oss(ligne); m_nbFaces.push_back(4); int s0,s1,s2,s3,nbe; oss >> s0; oss >> s1; oss >> s2; oss >> s3; typename PFP::VEC3 P = position[verticesID[s0]]; typename PFP::VEC3 A = position[verticesID[s1]]; typename PFP::VEC3 B = position[verticesID[s2]]; typename PFP::VEC3 C = position[verticesID[s3]]; if(Geom::testOrientation3D<typename PFP::VEC3>(P,A,B,C) == Geom::UNDER) { int ui = s1; s1 = s2; s2 = ui; } //if regions are defined use this number oss >> nbe; //ignored here m_emb.push_back(verticesID[s0]); m_emb.push_back(verticesID[s1]); m_emb.push_back(verticesID[s2]); m_emb.push_back(verticesID[s3]); } fp.close(); return true; }
bool MeshTablesVolume<PFP>::importTetmesh(const std::string& filename, std::vector<std::string>& attrNames) { VertexAttribute<VEC3> position = m_map.template getAttribute<VEC3, VERTEX>("position") ; if (!position.isValid()) position = m_map.template addAttribute<VEC3, VERTEX>("position") ; attrNames.push_back(position.name()) ; AttributeContainer& container = m_map.template getAttributeContainer<VERTEX>() ; //open file std::ifstream fp(filename.c_str(), std::ios::in); if (!fp.good()) { CGoGNerr << "Unable to open file " << filename << CGoGNendl; return false; } std::string line; fp >> line; if (line!="Vertices") CGoGNerr << "Warning tetmesh file problem"<< CGoGNendl; fp >> m_nbVertices; std::cout << "READ: "<< m_nbVertices << std::endl; std::getline (fp, line); //reading vertices std::vector<unsigned int> verticesID; verticesID.reserve(m_nbVertices+1); verticesID.push_back(0xffffffff); for(unsigned int i = 0; i < m_nbVertices; ++i) { do { std::getline (fp, line); } while (line.size() == 0); std::stringstream oss(line); float x,y,z; oss >> x; oss >> y; oss >> z; // TODO : if required read other vertices attributes here VEC3 pos(x,y,z); unsigned int id = container.insertLine(); position[id] = pos; verticesID.push_back(id); } fp >> line; if (line!="Tetrahedra") CGoGNerr << "Warning tetmesh file problem"<< CGoGNendl; fp >> m_nbVolumes; std::getline (fp, line); // reading tetrahedra m_nbFaces.reserve(m_nbVolumes*4); m_emb.reserve(m_nbVolumes*12); for(unsigned i = 0; i < m_nbVolumes ; ++i) { do { std::getline(fp,line); } while(line.size() == 0); std::stringstream oss(line); m_nbFaces.push_back(4); int s0,s1,s2,s3; oss >> s0; oss >> s1; oss >> s2; oss >> s3; typename PFP::VEC3 P = position[verticesID[s0]]; typename PFP::VEC3 A = position[verticesID[s1]]; typename PFP::VEC3 B = position[verticesID[s2]]; typename PFP::VEC3 C = position[verticesID[s3]]; if (Geom::testOrientation3D<typename PFP::VEC3>(P,A,B,C) == Geom::UNDER) { int ui=s1; s1 = s2; s2 = ui; } m_emb.push_back(verticesID[s0]); m_emb.push_back(verticesID[s1]); m_emb.push_back(verticesID[s2]); m_emb.push_back(verticesID[s3]); } fp.close(); return true; }
bool MeshTablesVolume<PFP>::importNodeWithELERegions(const std::string& filenameNode, const std::string& filenameELE, std::vector<std::string>& attrNames) { VertexAttribute<VEC3> position = m_map.template getAttribute<VEC3, VERTEX>("position") ; if (!position.isValid()) position = m_map.template addAttribute<VEC3, VERTEX>("position") ; attrNames.push_back(position.name()) ; AttributeContainer& container = m_map.template getAttributeContainer<VERTEX>() ; //open file std::ifstream fnode(filenameNode.c_str(), std::ios::in); if (!fnode.good()) { CGoGNerr << "Unable to open file " << filenameNode << CGoGNendl; return false; } std::ifstream fele(filenameELE.c_str(), std::ios::in); if (!fele.good()) { CGoGNerr << "Unable to open file " << filenameELE << CGoGNendl; return false; } std::string line; //Reading NODE file //First line: [# of points] [dimension (must be 3)] [# of attributes] [# of boundary markers (0 or 1)] unsigned int nbe; { do { std::getline(fnode,line); }while(line.size() == 0); std::stringstream oss(line); oss >> m_nbVertices; oss >> nbe; oss >> nbe; oss >> nbe; } //Reading number of tetrahedra in ELE file unsigned int nbv; { do { std::getline(fele,line); }while(line.size() == 0); std::stringstream oss(line); oss >> m_nbVolumes; oss >> nbv ; oss >> nbv; } //Reading vertices std::map<unsigned int,unsigned int> verticesMapID; for(unsigned int i = 0 ; i < m_nbVertices ; ++i) { do { std::getline(fnode,line); }while(line.size() == 0); std::stringstream oss(line); int idv; oss >> idv; float x,y,z; oss >> x; oss >> y; oss >> z; //we can read colors informations if exists VEC3 pos(x,y,z); unsigned int id = container.insertLine(); position[id] = pos; verticesMapID.insert(std::pair<unsigned int, unsigned int>(idv,id)); } // reading tetrahedra m_nbFaces.reserve(m_nbVolumes*4); m_emb.reserve(m_nbVolumes*12); for(unsigned i = 0; i < m_nbVolumes ; ++i) { do { std::getline(fele,line); } while(line.size() == 0); std::stringstream oss(line); oss >> nbe; m_nbFaces.push_back(4); int s0,s1,s2,s3; oss >> s0; oss >> s1; oss >> s2; oss >> s3; typename PFP::VEC3 P = position[verticesMapID[s0]]; typename PFP::VEC3 A = position[verticesMapID[s1]]; typename PFP::VEC3 B = position[verticesMapID[s2]]; typename PFP::VEC3 C = position[verticesMapID[s3]]; if (Geom::testOrientation3D<typename PFP::VEC3>(P,A,B,C) == Geom::UNDER) { int ui= s0; s0 = s3; s3 = s2; s2 = s1; s1 = ui; } m_emb.push_back(verticesMapID[s0]); m_emb.push_back(verticesMapID[s1]); m_emb.push_back(verticesMapID[s2]); m_emb.push_back(verticesMapID[s3]); } fnode.close(); fele.close(); return true; }
bool MeshTablesVolume<PFP>::importOFFWithELERegions(const std::string& filenameOFF, const std::string& filenameELE, std::vector<std::string>& attrNames) { VertexAttribute<VEC3> position = m_map.template getAttribute<VEC3, VERTEX>("position") ; if (!position.isValid()) position = m_map.template addAttribute<VEC3, VERTEX>("position") ; attrNames.push_back(position.name()) ; AttributeContainer& container = m_map.template getAttributeContainer<VERTEX>() ; // open files std::ifstream foff(filenameOFF.c_str(), std::ios::in); if (!foff.good()) { CGoGNerr << "Unable to open OFF file " << CGoGNendl; return false; } std::ifstream fele(filenameELE.c_str(), std::ios::in); if (!fele.good()) { CGoGNerr << "Unable to open ELE file " << CGoGNendl; return false; } std::string line; //OFF reading std::getline(foff, line); if(line.rfind("OFF") == std::string::npos) { CGoGNerr << "Problem reading off file: not an off file"<<CGoGNendl; CGoGNerr << line << CGoGNendl; return false; } //Reading number of vertex/faces/edges in OFF file unsigned int nbe; { do { std::getline(foff,line); }while(line.size() == 0); std::stringstream oss(line); oss >> m_nbVertices; oss >> nbe; oss >> nbe; oss >> nbe; } //Reading number of tetrahedra in ELE file unsigned int nbv; { do { std::getline(fele,line); }while(line.size() == 0); std::stringstream oss(line); oss >> m_nbVolumes; oss >> nbv ; oss >> nbv; } //Reading vertices std::vector<unsigned int> verticesID; verticesID.reserve(m_nbVertices); for(unsigned int i = 0 ; i < m_nbVertices ; ++i) { do { std::getline(foff,line); }while(line.size() == 0); std::stringstream oss(line); float x,y,z; oss >> x; oss >> y; oss >> z; //we can read colors informations if exists VEC3 pos(x,y,z); unsigned int id = container.insertLine(); position[id] = pos; verticesID.push_back(id); } // reading tetrahedra m_nbFaces.reserve(m_nbVolumes*4); m_emb.reserve(m_nbVolumes*12); for(unsigned i = 0; i < m_nbVolumes ; ++i) { do { std::getline(fele,line); } while(line.size() == 0); std::stringstream oss(line); oss >> nbe; m_nbFaces.push_back(4); int s0,s1,s2,s3; oss >> s0; oss >> s1; oss >> s2; oss >> s3; typename PFP::VEC3 P = position[verticesID[s0]]; typename PFP::VEC3 A = position[verticesID[s1]]; typename PFP::VEC3 B = position[verticesID[s2]]; typename PFP::VEC3 C = position[verticesID[s3]]; if (Geom::testOrientation3D<typename PFP::VEC3>(P,A,B,C) == Geom::UNDER) { int ui= s0; s0 = s3; s3 = s2; s2 = s1; s1 = ui; } m_emb.push_back(verticesID[s0]); m_emb.push_back(verticesID[s1]); m_emb.push_back(verticesID[s2]); m_emb.push_back(verticesID[s3]); } foff.close(); fele.close(); return true; }
bool MeshTablesVolume<PFP>::importTet(const std::string& filename, std::vector<std::string>& attrNames) { VertexAttribute<VEC3, MAP> position = m_map.template getAttribute<VEC3, VERTEX, MAP>("position") ; if (!position.isValid()) position = m_map.template addAttribute<VEC3, VERTEX, MAP>("position") ; attrNames.push_back(position.name()) ; AttributeContainer& container = m_map.template getAttributeContainer<VERTEX>() ; //open file std::ifstream fp(filename.c_str(), std::ios::in); if (!fp.good()) { CGoGNerr << "Unable to open file " << filename << CGoGNendl; return false; } std::string ligne; // reading number of vertices std::getline (fp, ligne); std::stringstream oss(ligne); oss >> m_nbVertices; // reading number of tetrahedra std::getline (fp, ligne); std::stringstream oss2(ligne); oss2 >> m_nbVolumes; //reading vertices std::vector<unsigned int> verticesID; verticesID.reserve(m_nbVertices); for(unsigned int i = 0; i < m_nbVertices; ++i) { do { std::getline (fp, ligne); } while (ligne.size() == 0); std::stringstream oss(ligne); float x,y,z; oss >> x; oss >> y; oss >> z; // TODO : if required read other vertices attributes here VEC3 pos(x,y,z); unsigned int id = container.insertLine(); position[id] = pos; verticesID.push_back(id); } // reading volumes m_nbFaces.reserve(m_nbVolumes*4); m_emb.reserve(m_nbVolumes*12); unsigned int nbc = 0; for (unsigned int i = 0; i < m_nbVolumes ; ++i) { do { std::getline (fp, ligne); } while (ligne.size()==0); std::stringstream oss(ligne); int n; oss >> n; // type of volumes if(!oss.good()) { oss.clear(); char dummy; oss >> dummy; // type of volumes oss >> dummy; if(dummy == 'C')// connector { ++nbc; m_nbFaces.push_back(3); int s0,s1,s2,s3; oss >> s0; oss >> s1; oss >> s2; oss >> s3; //std::cout << "connector " << s0 << " " << s1 << " " << s2 << " " << s3 << std::endl; m_emb.push_back(verticesID[s0]); m_emb.push_back(verticesID[s1]); m_emb.push_back(verticesID[s2]); m_emb.push_back(verticesID[s3]); } }
void AHEMImporter<PFP>::LoadTopology() { // Allocate vertices AttributeContainer& vxContainer = map->template getAttributeContainer<VERTEX>(); verticesId = new unsigned int[hdr.meshHdr.vxCount]; for(unsigned int i = 0 ; i < hdr.meshHdr.vxCount ; i++) verticesId[i] = vxContainer.insertLine(); // Ensure vertices are created by querying the position attribute VertexAttribute<typename PFP::VEC3, typename PFP::MAP> position = map->template getAttribute<typename PFP::VEC3, VERTEX, typename PFP::MAP>("position"); if (!position.isValid()) position = map->template addAttribute<typename PFP::VEC3, VERTEX, typename PFP::MAP>("position"); // Read faces stream and create faces [only intra-face links] HESorter* addedHE = new HESorter[hdr.meshHdr.heCount]; facesId = new Dart[hdr.meshHdr.faceCount]; f.read(buffer, hdr.meshHdr.meshChunkSize); char* batch = buffer; unsigned int fId = 0; unsigned int heId = 0; while(fId < hdr.meshHdr.faceCount) { AHEMFaceBatchDescriptor* fbd = (AHEMFaceBatchDescriptor*)batch; stUInt32* ix = (stUInt32*)(batch + sizeof(AHEMFaceBatchDescriptor)); for(unsigned int i = 0 ; i < fbd->batchLength ; i++) { Dart d = map->newFace(fbd->batchFaceSize); // create face facesId[fId++] = d; unsigned int firstVx = verticesId[*ix++]; // setup face's vertices up to last HE unsigned int prevVx = firstVx; for(unsigned int k = 0 ; k < fbd->batchFaceSize - 1 ; k++) { addedHE[heId].d = d; addedHE[heId].vxIdFrom = prevVx; addedHE[heId].vxIdTo = verticesId[*ix]; map->setDartEmbedding<VERTEX>(d, prevVx); d = map->phi1(d); prevVx = *ix++; heId++; } // last HE addedHE[heId].d = d; addedHE[heId].vxIdFrom = prevVx; addedHE[heId].vxIdTo = firstVx; map->setDartEmbedding<VERTEX>(d, prevVx); heId++; } batch = (char*)ix; } // Sort the HE for fast retrieval std::sort(addedHE, addedHE + hdr.meshHdr.heCount); // Sew faces [inter-face links] for(unsigned int i = 0 ; i < hdr.meshHdr.heCount ; i++) { HESorter* opposite = (HESorter*)bsearch(addedHE + i, addedHE, hdr.meshHdr.heCount, sizeof(HESorter), OppositeSearch); if(opposite && opposite->d == map->phi2(opposite->d)) map->sewFaces(addedHE[i].d, opposite->d); } }
void Surface_DifferentialProperties_Plugin::computeCurvature( const QString& mapName, const QString& positionAttributeName, const QString& normalAttributeName, const QString& KmaxAttributeName, const QString& kmaxAttributeName, const QString& KminAttributeName, const QString& kminAttributeName, const QString& KnormalAttributeName, bool compute_kmean, bool compute_kgaussian, bool autoUpdate) { MapHandler<PFP2>* mh = static_cast<MapHandler<PFP2>*>(m_schnapps->getMap(mapName)); if(mh == NULL) return; VertexAttribute<PFP2::VEC3, PFP2::MAP> position = mh->getAttribute<PFP2::VEC3, VERTEX>(positionAttributeName); if(!position.isValid()) return; VertexAttribute<PFP2::VEC3, PFP2::MAP> normal = mh->getAttribute<PFP2::VEC3, VERTEX>(normalAttributeName); if(!normal.isValid()) return; VertexAttribute<PFP2::VEC3, PFP2::MAP> Kmax = mh->getAttribute<PFP2::VEC3, VERTEX>(KmaxAttributeName); if(!Kmax.isValid()) Kmax = mh->addAttribute<PFP2::VEC3, VERTEX>(KmaxAttributeName); VertexAttribute<PFP2::REAL, PFP2::MAP> kmax = mh->getAttribute<PFP2::REAL, VERTEX>(kmaxAttributeName); if(!kmax.isValid()) kmax = mh->addAttribute<PFP2::REAL, VERTEX>(kmaxAttributeName); VertexAttribute<PFP2::VEC3, PFP2::MAP> Kmin = mh->getAttribute<PFP2::VEC3, VERTEX>(KminAttributeName); if(!Kmin.isValid()) Kmin = mh->addAttribute<PFP2::VEC3, VERTEX>(KminAttributeName); VertexAttribute<PFP2::REAL, PFP2::MAP> kmin = mh->getAttribute<PFP2::REAL, VERTEX>(kminAttributeName); if(!kmin.isValid()) kmin = mh->addAttribute<PFP2::REAL, VERTEX>(kminAttributeName); VertexAttribute<PFP2::VEC3, PFP2::MAP> Knormal = mh->getAttribute<PFP2::VEC3, VERTEX>(KnormalAttributeName); if(!Knormal.isValid()) Knormal = mh->addAttribute<PFP2::VEC3, VERTEX>(KnormalAttributeName); EdgeAttribute<PFP2::REAL, PFP2::MAP> edgeAngle = mh->getAttribute<PFP2::REAL, EDGE>("edgeAngle"); if(!edgeAngle.isValid()) edgeAngle = mh->addAttribute<PFP2::REAL, EDGE>("edgeAngle"); PFP2::MAP* map = mh->getMap(); Algo::Surface::Geometry::computeAnglesBetweenNormalsOnEdges<PFP2>(*map, position, edgeAngle); Algo::Surface::Geometry::computeCurvatureVertices_NormalCycles_Projected<PFP2>(*map, 0.01f * mh->getBBdiagSize(), position, normal, edgeAngle, kmax, kmin, Kmax, Kmin, Knormal); computeCurvatureLastParameters[mapName] = ComputeCurvatureParameters( positionAttributeName, normalAttributeName, KmaxAttributeName, kmaxAttributeName, KminAttributeName, kminAttributeName, KnormalAttributeName, compute_kmean, compute_kgaussian, autoUpdate); mh->notifyAttributeModification(Kmax); mh->notifyAttributeModification(kmax); mh->notifyAttributeModification(Kmin); mh->notifyAttributeModification(kmin); mh->notifyAttributeModification(Knormal); if(compute_kmean) { VertexAttribute<PFP2::REAL, PFP2::MAP> kmean = mh->getAttribute<PFP2::REAL, VERTEX>("kmean"); if(!kmean.isValid()) kmean = mh->addAttribute<PFP2::REAL, VERTEX>("kmean"); for(unsigned int i = kmin.begin(); i != kmin.end(); kmin.next(i)) kmean[i] = (kmin[i] + kmax[i]) / 2.0; mh->notifyAttributeModification(kmean); } if(compute_kgaussian) { VertexAttribute<PFP2::REAL, PFP2::MAP> kgaussian = mh->getAttribute<PFP2::REAL, VERTEX>("kgaussian"); if(!kgaussian.isValid()) kgaussian = mh->addAttribute<PFP2::REAL, VERTEX>("kgaussian"); for(unsigned int i = kmin.begin(); i != kmin.end(); kmin.next(i)) kgaussian[i] = kmin[i] * kmax[i]; mh->notifyAttributeModification(kgaussian); } }
int main() { // declare a map to handle the mesh MAP myMap; // add position attribute on vertices and get handler on it VertexAttribute<VEC3, MAP> positionAtt = myMap.addAttribute<VEC3, VERTEX, MAP>("position"); if (!positionAtt.isValid()) std::cerr << "impossible to create an attribute with name position (already used ?)"<< std::endl; // create a topo grid of 2x2 squares Algo::Surface::Tilings::Square::Grid<PFP> grid(myMap, 2, 2, true); // and embed it using position attribute grid.embedIntoGrid(positionAtt, 1.,1.,0.); VertexGeneric(myMap,positionAtt); // ATTRIBUTE DECLARATION // add an attribute of type float on orbit EDGE EdgeAttribute<float, MAP> lengthAtt = myMap.addAttribute<float, EDGE, MAP>("length"); if (!lengthAtt.isValid()) std::cerr << "impossible to create the attribute"<< std::endl; computeLengthEdges(myMap,positionAtt,lengthAtt); // add an attribute of type std::string on orbit FACE FaceAttribute<std::string, MAP> nameAtt = myMap.addAttribute<std::string, FACE, MAP>("name"); if (!nameAtt.isValid()) std::cerr << "impossible to create the attribute"<< std::endl; // for complex type use following template (function nameOfType not applicable) EdgeAttribute< NoTypeNameAttribute< std::vector<int> >, MAP> vectAtt = myMap.addAttribute< NoTypeNameAttribute< std::vector<int> >, EDGE, MAP>("vector_of_int"); if (!vectAtt.isValid()) std::cerr << "impossible to create the attribute"<< std::endl; Dart d = myMap.begin(); // define a vertex from a dart Vertex v(d); // define a face from a dart Face f(d); // ATTRIBUTE ACCESS // [] operator can take a dart, a cell (only same off attribute), or an unsigned inf // access to any attributes with darts std::cout << positionAtt[d]<< std::endl; nameAtt[d] = "Hello"; lengthAtt[myMap.phi1(d)] = 54.0f; std::vector<int> vi = {3,5,7,9,11}; vectAtt[d]= vi; vectAtt[d].push_back(11); // access to VertexAttribute with a Vertex std::cout << positionAtt[v]<< std::endl; // access to FaceAttribute with a Face std::cout << nameAtt[f]<< std::endl; // following line does not compile because of wrong cell type // std::cout << positionAtt[f]<< std::endl; // possible to bypass using dart access std::cout << positionAtt[f.dart]<< std::endl; // access with unsigned int is dangerous, index must be obtain with begin/end/next (see dumpAttribute) // COPY, REMOVE, SWAP // possible to have any number of attribute a same ORBIT VertexAttribute<VEC3, MAP> position2Att = myMap.addAttribute<VEC3, VERTEX, MAP>("other_position"); // copy of attribute of same type (linear complexity) myMap.copyAttribute(position2Att,positionAtt); positionAtt[v] += VEC3(0,0,1); computeNewPositions(myMap,positionAtt); dumpAttribute(positionAtt); //check if there is a Vertex Attribute of VEC3 named position => yes testVAbyNames(myMap,"position"); // remove the attribute myMap.removeAttribute(positionAtt); //check if there is a Vertex Attribute of VEC3 named position => no testVAbyNames(myMap,"position"); return 0; }
void Surface_Radiance_Plugin::decimate(const QString& mapName, const QString& positionAttributeName, const QString& normalAttributeName, float decimationGoal, bool halfCollapse, bool exportMeshes) { MapHandler<PFP2>* mh = static_cast<MapHandler<PFP2>*>(m_schnapps->getMap(mapName)); if(mh == NULL) return; VertexAttribute<PFP2::VEC3, PFP2::MAP> position = mh->getAttribute<PFP2::VEC3, VERTEX>(positionAttributeName); if(!position.isValid()) return; VertexAttribute<PFP2::VEC3, PFP2::MAP> normal = mh->getAttribute<PFP2::VEC3, VERTEX>(normalAttributeName); if(!normal.isValid()) return; PFP2::MAP* map = mh->getMap(); unsigned int nbVertices = Algo::Topo::getNbOrbits<VERTEX>(*map); MapParameters& mapParams = h_mapParameterSet[mh]; if (halfCollapse) { if (mapParams.positionApproximator == NULL) { mapParams.positionApproximator = new Algo::Surface::Decimation::Approximator_HalfCollapse<PFP2, PFP2::VEC3>(*map, position); } if (mapParams.normalApproximator == NULL) { mapParams.normalApproximator = new Algo::Surface::Decimation::Approximator_HalfCollapse<PFP2, PFP2::VEC3>(*map, normal); } if (mapParams.radianceApproximator == NULL) { mapParams.radianceApproximator = new Algo::Surface::Decimation::Approximator_HalfCollapse<PFP2, Utils::SphericalHarmonics<PFP2::REAL, PFP2::VEC3> >(*map, mapParams.radiance); } if (mapParams.selector == NULL) { mapParams.selector = new HalfEdgeSelector_Radiance<PFP2>( *map, position, normal, mapParams.radiance, *(Algo::Surface::Decimation::Approximator<PFP2, PFP2::VEC3, DART>*)(mapParams.positionApproximator), *(Algo::Surface::Decimation::Approximator<PFP2, PFP2::VEC3, DART>*)(mapParams.normalApproximator), *(Algo::Surface::Decimation::Approximator<PFP2, Utils::SphericalHarmonics<PFP2::REAL, PFP2::VEC3>, DART>*)(mapParams.radianceApproximator) ); } } else { if (mapParams.positionApproximator == NULL) { mapParams.positionApproximator = new Algo::Surface::Decimation::Approximator_QEM<PFP2>(*map, position); } if (mapParams.normalApproximator == NULL) { mapParams.normalApproximator = new Algo::Surface::Decimation::Approximator_InterpolateAlongEdge<PFP2, PFP2::VEC3>( *map, normal, position, ((Algo::Surface::Decimation::Approximator<PFP2, PFP2::VEC3, EDGE>*)(mapParams.positionApproximator))->getApproximationResultAttribute() ); } if (mapParams.radianceApproximator == NULL) { mapParams.radianceApproximator = new Algo::Surface::Decimation::Approximator_InterpolateAlongEdge<PFP2, Utils::SphericalHarmonics<PFP2::REAL, PFP2::VEC3> >( *map, mapParams.radiance, position, ((Algo::Surface::Decimation::Approximator<PFP2, PFP2::VEC3, EDGE>*)(mapParams.positionApproximator))->getApproximationResultAttribute() ); } if (mapParams.selector == NULL) { mapParams.selector = new EdgeSelector_Radiance<PFP2>( *map, position, normal, mapParams.radiance, *(Algo::Surface::Decimation::Approximator<PFP2, PFP2::VEC3, EDGE>*)(mapParams.positionApproximator), *(Algo::Surface::Decimation::Approximator<PFP2, PFP2::VEC3, EDGE>*)(mapParams.normalApproximator), *(Algo::Surface::Decimation::Approximator<PFP2, Utils::SphericalHarmonics<PFP2::REAL, PFP2::VEC3>, EDGE>*)(mapParams.radianceApproximator) ); mapParams.selector = new Algo::Surface::Decimation::EdgeSelector_QEM<PFP2>( *map, position, *(Algo::Surface::Decimation::Approximator<PFP2, PFP2::VEC3, EDGE>*)(mapParams.positionApproximator) ); } } std::vector<Algo::Surface::Decimation::ApproximatorGen<PFP2>*> approximators; approximators.push_back(mapParams.positionApproximator); approximators.push_back(mapParams.normalApproximator); approximators.push_back(mapParams.radianceApproximator); exportNbVert.clear(); if (exportMeshes) { unsigned int goalNbV = decimationGoal * nbVertices; unsigned int curNbV = nbVertices / 2; while (curNbV > goalNbV) { exportNbVert.push_back(curNbV); curNbV /= 2; } exportNbVert.push_back(goalNbV); nextExportIndex = 0; } std::cout << "nb vert -> " << nbVertices << std::endl; for (unsigned int v : exportNbVert) { std::cout << v << std::endl; } m_currentlyDecimatedMap = mh; m_currentDecimationHalf = halfCollapse; Algo::Surface::Decimation::decimate<PFP2>(*map, mapParams.selector, approximators, decimationGoal * nbVertices, true, NULL, (void (*)(void*, const void*))(Surface_Radiance_Plugin::checkNbVerticesAndExport), (void*)(this)); m_currentlyDecimatedMap = NULL; mh->notifyConnectivityModification(); mh->notifyAttributeModification(position); }
bool MeshTablesSurface<PFP>::importObj(const std::string& filename, std::vector<std::string>& attrNames) { VertexAttribute<typename PFP::VEC3> positions = m_map.template getAttribute<typename PFP::VEC3, VERTEX>("position") ; if (!positions.isValid()) positions = m_map.template addAttribute<typename PFP::VEC3, VERTEX>("position") ; attrNames.push_back(positions.name()) ; AttributeContainer& container = m_map.template getAttributeContainer<VERTEX>() ; // open file std::ifstream fp(filename.c_str(), std::ios::binary); if (!fp.good()) { CGoGNerr << "Unable to open file " << filename << CGoGNendl; return false; } // fp.seekg(0, std::ios::end); // int ab = fp.tellg(); // fp.seekg(0, std::ios::beg); // int ac = fp.tellg(); std::string ligne; std::string tag; do { fp >> tag; std::getline (fp, ligne); }while (tag != std::string("v")); // lecture des sommets std::vector<unsigned int> verticesID; verticesID.reserve(102400); // on tape large (400Ko wahouuuuu !!) unsigned int i = 0; do { if (tag == std::string("v")) { std::stringstream oss(ligne); float x,y,z; oss >> x; oss >> y; oss >> z; VEC3 pos(x,y,z); unsigned int id = container.insertLine(); positions[id] = pos; verticesID.push_back(id); i++; } fp >> tag; std::getline(fp, ligne); } while (!fp.eof());
bool MeshTablesSurface<PFP>::importMeshBin(const std::string& filename, std::vector<std::string>& attrNames) { VertexAttribute<typename PFP::VEC3> positions = m_map.template getAttribute<typename PFP::VEC3, VERTEX>("position") ; if (!positions.isValid()) { positions = m_map.template addAttribute<typename PFP::VEC3, VERTEX>("position") ; } attrNames.push_back(positions.name()) ; AttributeContainer& container = m_map.template getAttributeContainer<VERTEX>() ; // open file std::ifstream fp(filename.c_str(), std::ios::in | std::ios::binary); if (!fp.good()) { CGoGNerr << "Unable to open file " << filename << CGoGNendl; return false; } // Read header unsigned int Fmin, Fmax ; fp.read((char*)&m_nbVertices, sizeof(unsigned int)) ; fp.read((char*)&m_nbFaces, sizeof(unsigned int)) ; fp.read((char*)&Fmin, sizeof(unsigned int)) ; fp.read((char*)&Fmax, sizeof(unsigned int)) ; assert((Fmin == 3 && Fmax == 3) || !"Only triangular faces are handled yet") ; // Read foreach vertex std::vector<unsigned int> verticesID ; verticesID.reserve(m_nbVertices) ; for (unsigned int vxNum = 0 ; vxNum < m_nbVertices ; ++vxNum) { Geom::Vec3f pos ; fp.read((char*) &pos[0], sizeof(float)) ; fp.read((char*) &pos[1], sizeof(float)) ; fp.read((char*) &pos[2], sizeof(float)) ; unsigned int id = container.insertLine() ; positions[id] = pos ; verticesID.push_back(id) ; } // Read foreach face m_nbEdges.reserve(m_nbFaces) ; m_emb.reserve(m_nbVertices * 8) ; for (unsigned int fNum = 0; fNum < m_nbFaces; ++fNum) { const unsigned int faceSize = 3 ; fp.read((char*) &faceSize, sizeof(float)) ; m_nbEdges.push_back(faceSize) ; for (unsigned int i = 0 ; i < faceSize; ++i) { unsigned int index ; // index of embedding fp.read((char*) &index, sizeof(unsigned int)) ; m_emb.push_back(verticesID[index]) ; } } fp.close() ; return true ; }
bool MeshTablesSurface<PFP>::importOff(const std::string& filename, std::vector<std::string>& attrNames) { VertexAttribute<typename PFP::VEC3> positions = m_map.template getAttribute<typename PFP::VEC3, VERTEX>("position") ; if (!positions.isValid()) positions = m_map.template addAttribute<typename PFP::VEC3, VERTEX>("position") ; attrNames.push_back(positions.name()) ; AttributeContainer& container = m_map.template getAttributeContainer<VERTEX>() ; // open file std::ifstream fp(filename.c_str(), std::ios::in); if (!fp.good()) { CGoGNerr << "Unable to open file " << filename << CGoGNendl; return false; } std::string ligne; // lecture de OFF std::getline (fp, ligne); if (ligne.rfind("OFF") == std::string::npos) { CGoGNerr << "Problem reading off file: not an off file" << CGoGNendl; CGoGNerr << ligne << CGoGNendl; return false; } // lecture des nombres de sommets/faces/aretes int nbe; { do { std::getline (fp, ligne); } while (ligne.size() == 0); std::stringstream oss(ligne); oss >> m_nbVertices; oss >> m_nbFaces; oss >> nbe; } //lecture sommets std::vector<unsigned int> verticesID; verticesID.reserve(m_nbVertices); for (unsigned int i = 0; i < m_nbVertices;++i) { do { std::getline (fp, ligne); } while (ligne.size() == 0); std::stringstream oss(ligne); float x,y,z; oss >> x; oss >> y; oss >> z; // on peut ajouter ici la lecture de couleur si elle existe VEC3 pos(x,y,z); unsigned int id = container.insertLine(); positions[id] = pos; verticesID.push_back(id); } // lecture faces // normalement nbVertices*8 devrait suffire largement m_nbEdges.reserve(m_nbFaces); m_emb.reserve(m_nbVertices*8); for (unsigned int i = 0; i < m_nbFaces; ++i) { do { std::getline (fp, ligne); } while (ligne.size() == 0); std::stringstream oss(ligne); unsigned int n; oss >> n; m_nbEdges.push_back(n); for (unsigned int j = 0; j < n; ++j) { int index; // index du plongement oss >> index; m_emb.push_back(verticesID[index]); } // on peut ajouter ici la lecture de couleur si elle existe } fp.close(); return true; }
bool MeshTablesSurface<PFP>::importTrianBinGz(const std::string& filename, std::vector<std::string>& attrNames) { VertexAttribute<typename PFP::VEC3> positions = m_map.template getAttribute<typename PFP::VEC3, VERTEX>("position") ; if (!positions.isValid()) positions = m_map.template addAttribute<typename PFP::VEC3, VERTEX>("position") ; attrNames.push_back(positions.name()) ; AttributeContainer& container = m_map.template getAttributeContainer<VERTEX>() ; // open file igzstream fs(filename.c_str(), std::ios::in|std::ios::binary); if (!fs.good()) { CGoGNerr << "Unable to open file " << filename << CGoGNendl; return false; } // read nb of points fs.read(reinterpret_cast<char*>(&m_nbVertices), sizeof(int)); // read points std::vector<unsigned int> verticesID; { // juste pour limiter la portee des variables verticesID.reserve(m_nbVertices); float* buffer = new float[m_nbVertices*3]; fs.read(reinterpret_cast<char*>(buffer), 3*m_nbVertices*sizeof(float)); float *ptr = buffer; for (unsigned int i = 0; i < m_nbVertices; ++i) { VEC3 pos; pos[0]= *ptr++; pos[1]= *ptr++; pos[2]= *ptr++; unsigned int id = container.insertLine(); positions[id] = pos; verticesID.push_back(id); } delete[] buffer; } // read nb of faces fs.read(reinterpret_cast<char*>(&m_nbFaces), sizeof(int)); m_nbEdges.reserve(m_nbFaces); m_emb.reserve(3*m_nbFaces); // read indices of faces { // juste pour limiter la portee des variables int* buffer = new int[m_nbFaces*6]; fs.read(reinterpret_cast<char*>(buffer),6*m_nbFaces*sizeof(float)); int *ptr = buffer; for (unsigned int i = 0; i < m_nbFaces; i++) { m_nbEdges.push_back(3); m_emb.push_back(verticesID[*ptr++]); m_emb.push_back(verticesID[*ptr++]); m_emb.push_back(verticesID[*ptr++]); } } fs.close(); return true; }
bool MeshTablesSurface<PFP>::importTrian(const std::string& filename, std::vector<std::string>& attrNames) { VertexAttribute<typename PFP::VEC3> positions = m_map.template getAttribute<typename PFP::VEC3, VERTEX>("position") ; if (!positions.isValid()) positions = m_map.template addAttribute<typename PFP::VEC3, VERTEX>("position") ; attrNames.push_back(positions.name()) ; AttributeContainer& container = m_map.template getAttributeContainer<VERTEX>() ; // open file std::ifstream fp(filename.c_str(), std::ios::in); if (!fp.good()) { CGoGNerr << "Unable to open file " << filename << CGoGNendl; return false; } // read nb of points fp >> m_nbVertices; // read points std::vector<unsigned int> verticesID; verticesID.reserve(m_nbVertices); for (unsigned int i = 0; i < m_nbVertices; ++i) { VEC3 pos; fp >> pos[0]; fp >> pos[1]; fp >> pos[2]; unsigned int id = container.insertLine(); positions[id] = pos; verticesID.push_back(id); } // read nb of faces fp >> m_nbFaces; m_nbEdges.reserve(m_nbFaces); m_emb.reserve(3*m_nbFaces); // read indices of faces for (unsigned int i = 0; i < m_nbFaces; ++i) { m_nbEdges.push_back(3); // read the three vertices of triangle int pt; fp >> pt; m_emb.push_back(verticesID[pt]); fp >> pt; m_emb.push_back(verticesID[pt]); fp >> pt; m_emb.push_back(verticesID[pt]); // neighbour not always good in files !! int neigh; fp >> neigh; fp >> neigh; fp >> neigh; } fp.close(); return true; }
void Surface_Radiance_Plugin::exportPLY( const QString& mapName, const QString& positionAttributeName, const QString& normalAttributeName, const QString& filename) { typedef PFP2::MAP MAP; typedef PFP2::REAL REAL; typedef PFP2::VEC3 VEC3; MapHandler<PFP2>* mh = static_cast<MapHandler<PFP2>*>(m_schnapps->getMap(mapName)); if(mh == NULL) return; VertexAttribute<VEC3, MAP> position = mh->getAttribute<VEC3, VERTEX>(positionAttributeName); if(!position.isValid()) return; VertexAttribute<VEC3, MAP> normal = mh->getAttribute<VEC3, VERTEX>(normalAttributeName); if(!normal.isValid()) return; VertexAttribute<Utils::SphericalHarmonics<REAL, VEC3>, MAP> radiance = h_mapParameterSet[mh].radiance; if(!radiance.isValid()) return; // open file std::ofstream out ; out.open(filename.toStdString(), std::ios::out | std::ios::binary) ; if (!out.good()) { CGoGNerr << "Unable to open file " << CGoGNendl ; return ; } MAP* map = mh->getMap(); unsigned int nbDarts = map->getNbDarts() ; std::vector<unsigned int> facesSize ; std::vector<std::vector<unsigned int> > facesIdx ; facesSize.reserve(nbDarts/3) ; facesIdx.reserve(nbDarts/3) ; std::map<unsigned int, unsigned int> vIndex ; unsigned int vCpt = 0 ; std::vector<unsigned int> vertices ; vertices.reserve(nbDarts/6) ; // Go over all faces CellMarker<MAP, VERTEX> markV(*map) ; TraversorF<MAP> t(*map) ; for(Dart d = t.begin(); d != t.end(); d = t.next()) { std::vector<unsigned int> fidx ; fidx.reserve(8) ; unsigned int degree = 0 ; Traversor2FV<MAP> tfv(*map, d) ; for(Dart it = tfv.begin(); it != tfv.end(); it = tfv.next()) { ++degree ; unsigned int vNum = map->getEmbedding<VERTEX>(it) ; if(!markV.isMarked(it)) { markV.mark(it) ; vIndex[vNum] = vCpt++ ; vertices.push_back(vNum) ; } fidx.push_back(vIndex[vNum]) ; } facesSize.push_back(degree) ; facesIdx.push_back(fidx) ; } // Start writing the file out << "ply" << std::endl ; // test endianness union { uint32_t i ; char c[4] ; } bint = {0x01020304} ; if (bint.c[0] == 1) // big endian out << "format binary_big_endian 1.0" << std::endl ; else out << "format binary_little_endian 1.0" << std::endl ; out << "comment File generated by the CGoGN library" << std::endl ; out << "comment See : http://cgogn.unistra.fr/" << std::endl ; out << "comment or contact : [email protected]" << std::endl ; // Vertex elements out << "element vertex " << vertices.size() << std::endl ; std::string nameOfTypePly_REAL(nameOfTypePly(position[0][0])) ; out << "property " << nameOfTypePly_REAL << " x" << std::endl ; out << "property " << nameOfTypePly_REAL << " y" << std::endl ; out << "property " << nameOfTypePly_REAL << " z" << std::endl ; out << "property " << nameOfTypePly_REAL << " nx" << std::endl ; out << "property " << nameOfTypePly_REAL << " ny" << std::endl ; out << "property " << nameOfTypePly_REAL << " nz" << std::endl ; int res = Utils::SphericalHarmonics<REAL, VEC3>::get_resolution() ; for (int l = 0 ; l <= res ; ++l) { for (int m = -l ; m <= l ; ++m) { out << "property " << nameOfTypePly_REAL << " SHcoef_" << l << "_" << m << "_r" << std::endl ; out << "property " << nameOfTypePly_REAL << " SHcoef_" << l << "_" << m << "_g" << std::endl ; out << "property " << nameOfTypePly_REAL << " SHcoef_" << l << "_" << m << "_b" << std::endl ; } } // Face element out << "element face " << facesSize.size() << std::endl ; out << "property list uint8 " << nameOfTypePly(facesIdx[0][0]) << " vertex_indices" << std::endl ; out << "end_header" << std::endl ; // binary vertices for(unsigned int i = 0; i < vertices.size(); ++i) { const VEC3& p = position[vertices[i]] ; out.write((char*)(&(p[0])), sizeof(p)) ; const VEC3& n = normal[vertices[i]] ; out.write((char*)(&(n[0])), sizeof(n)) ; for (int l=0 ; l <= res ; ++l) { for (int m=-l ; m <= l ; ++m) { const VEC3& r = radiance[vertices[i]].get_coef(l,m) ; out.write((char*)(&(r[0])), sizeof(r)) ; } } } // binary faces for(unsigned int i = 0; i < facesSize.size(); ++i) { uint8_t nbe = facesSize[i] ; out.write((char*)(&nbe), sizeof(uint8_t)) ; out.write((char*)(&(facesIdx[i][0])), facesSize[i] * sizeof(facesIdx[i][0])) ; } out.close() ; this->pythonRecording("exportPLY", "", mapName, positionAttributeName, normalAttributeName, filename); }
bool MeshTablesVolume<PFP>::importTet(const std::string& filename, std::vector<std::string>& attrNames, float scaleFactor) { VertexAttribute<VEC3> positions = m_map.template getAttribute<VEC3, VERTEX>("position") ; if (!positions.isValid()) positions = m_map.template addAttribute<VEC3, VERTEX>("position") ; attrNames.push_back(positions.name()) ; AttributeContainer& container = m_map.template getAttributeContainer<VERTEX>() ; //open file std::ifstream fp(filename.c_str(), std::ios::in); if (!fp.good()) { CGoGNerr << "Unable to open file " << filename << CGoGNendl; return false; } std::string ligne; unsigned int nbv, nbt; // reading number of vertices std::getline (fp, ligne); std::stringstream oss(ligne); oss >> nbv; // reading number of tetrahedra std::getline (fp, ligne); std::stringstream oss2(ligne); oss2 >> nbt; //reading vertices std::vector<unsigned int> verticesID; verticesID.reserve(nbv); for(unsigned int i = 0; i < nbv;++i) { do { std::getline (fp, ligne); } while (ligne.size() == 0); std::stringstream oss(ligne); float x,y,z; oss >> x; oss >> y; oss >> z; // TODO : if required read other vertices attributes here VEC3 pos(x*scaleFactor,y*scaleFactor,z*scaleFactor); unsigned int id = container.insertLine(); positions[id] = pos; verticesID.push_back(id); } m_nbVertices = nbv; m_nbVolumes = nbt; // lecture tetra // normalement m_nbVolumes*12 (car on ne charge que des tetra) m_nbFaces=nbt*4; m_emb.reserve(nbt*12); for (unsigned int i = 0; i < m_nbVolumes ; ++i) { do { std::getline (fp, ligne); } while (ligne.size()==0); std::stringstream oss(ligne); int n; oss >> n; // nb de faces d'un volume ? m_nbEdges.push_back(3); m_nbEdges.push_back(3); m_nbEdges.push_back(3); m_nbEdges.push_back(3); int s0,s1,s2,s3; oss >> s0; oss >> s1; oss >> s2; oss >> s3; m_emb.push_back(verticesID[s0]); m_emb.push_back(verticesID[s1]); m_emb.push_back(verticesID[s2]); m_emb.push_back(verticesID[s1]); m_emb.push_back(verticesID[s0]); m_emb.push_back(verticesID[s3]); m_emb.push_back(verticesID[s2]); m_emb.push_back(verticesID[s1]); m_emb.push_back(verticesID[s3]); m_emb.push_back(verticesID[s0]); m_emb.push_back(verticesID[s2]); m_emb.push_back(verticesID[s3]); } fp.close(); return true; }