#ifndef POLYMESH_HPP #define POLYMESH_HPP #include "mesh.hpp" #include "vcg/complex/complex.h" #include #include #include #include #ifdef POLYSCOPE_DEFINED #include #endif class PFace; class PVertex; class PEdge; struct PUsedTypes : public vcg::UsedTypes::AsVertexType, vcg::Use::AsFaceType, vcg::Use::AsEdgeType> {}; class PVertex : public vcg::Vertex {}; class PEdge : public vcg::Edge {}; class PFace : public vcg::Face {}; class VCGPolyMesh : public vcg::tri::TriMesh, std::vector, std::vector>, public Mesh { public: virtual bool load(const std::filesystem::__cxx11::path &meshFilePath) override { int mask; vcg::tri::io::Importer::LoadMask(meshFilePath.c_str(), mask); int error = vcg::tri::io::Importer::Open(*this, meshFilePath.c_str(), mask); if (error != 0) { std::cerr << "Could not load polygonal mesh:" << meshFilePath << std::endl; return false; } vcg::tri::UpdateTopology::FaceFace(*this); vcg::tri::UpdateTopology::VertexEdge(*this); vcg::tri::UpdateTopology::VertexFace(*this); vcg::tri::UpdateNormal::PerVertexNormalized(*this); vcg::tri::Clean::RemoveUnreferencedVertex(*this); //finally remove valence 1 vertices on the border // vcg::PolygonalAlgorithm::RemoveValence2Vertices(dual); return true; } // // vcg::tri::io::ImporterOBJ::Open(); // // unsigned int mask = 0; // // mask |= nanoply::NanoPlyWrapper::IO_VERTCOORD; // // mask |= nanoply::NanoPlyWrapper::IO_VERTNORMAL; // // mask |= nanoply::NanoPlyWrapper::IO_VERTCOLOR; // // mask |= nanoply::NanoPlyWrapper::IO_EDGEINDEX; // // mask |= nanoply::NanoPlyWrapper::IO_FACEINDEX; // // if (nanoply::NanoPlyWrapper::LoadModel( // // std::filesystem::absolute(filename).c_str(), *this, mask) != // // 0) { // // std::cout << "Could not load tri mesh" << std::endl; // // } // } Eigen::MatrixX3d getVertices() const { Eigen::MatrixX3d vertices(VN(), 3); for (size_t vi = 0; vi < VN(); vi++) { VCGPolyMesh::CoordType vertexCoordinates = vert[vi].cP(); vertices.row(vi) = vertexCoordinates.ToEigenVector(); } return vertices; } std::vector> getFaces() const { std::vector> faces(FN()); for (const VCGPolyMesh::FaceType &f : this->face) { const int fi = vcg::tri::Index(*this, f); for (size_t vi = 0; vi < f.VN(); vi++) { const size_t viGlobal = vcg::tri::Index(*this, f.cV(vi)); faces[fi].push_back(viGlobal); } } return faces; } // bool load(const std::filesystem::__cxx11::path &meshFilePath) // { // const std::string extension = ".ply"; // std::filesystem::path filePath = meshFilePath; // assert(std::filesystem::path(filePath).extension().string() == extension); // unsigned int mask = 0; // mask |= vcg::tri::io::Mask::IOM_VERTCOORD; // mask |= vcg::tri::io::Mask::IOM_VERTNORMAL; // mask |= vcg::tri::io::Mask::IOM_FACEINDEX; // mask |= vcg::tri::io::Mask::IOM_FACECOLOR; // if (vcg::tri::io::Importer::Open(*this, filePath.c_str()) != 0) { // return false; // } // label = meshFilePath.filename(); // return true; // } bool save(const std::filesystem::__cxx11::path &meshFilePath = std::filesystem::path()) { if (meshFilePath.extension() == ".obj") { return saveOBJ(meshFilePath); } else if (meshFilePath.extension() == ".ply") { return savePLY(meshFilePath); } return false; } bool saveOBJ(const std::filesystem::path &objFilePath = std::filesystem::path()) { const std::string extension = ".obj"; std::filesystem::path filePath = objFilePath; if (filePath.empty()) { filePath = std::filesystem::current_path().append(getLabel() + extension).string(); } else if (std::filesystem::is_directory(std::filesystem::path(objFilePath))) { filePath = std::filesystem::path(objFilePath).append(getLabel() + extension).string(); } assert(std::filesystem::path(filePath).extension().string() == extension); unsigned int mask = 0; mask |= vcg::tri::io::Mask::IOM_VERTCOORD; mask |= vcg::tri::io::Mask::IOM_VERTNORMAL; mask |= vcg::tri::io::Mask::IOM_FACEINDEX; mask |= vcg::tri::io::Mask::IOM_FACECOLOR; if (vcg::tri::io::ExporterOBJ::Save(*this, filePath.string().c_str(), mask) != 0) { return false; } return true; } bool savePLY(const std::filesystem::path &objFilePath = std::filesystem::path()) { const std::string extension = ".ply"; std::filesystem::path filePath = objFilePath; if (filePath.empty()) { filePath = std::filesystem::current_path().append(getLabel() + extension).string(); } else if (std::filesystem::is_directory(std::filesystem::path(objFilePath))) { filePath = std::filesystem::path(objFilePath).append(getLabel() + extension).string(); } assert(std::filesystem::path(filePath).extension().string() == extension); unsigned int mask = 0; mask |= vcg::tri::io::Mask::IOM_VERTCOORD; mask |= vcg::tri::io::Mask::IOM_VERTNORMAL; mask |= vcg::tri::io::Mask::IOM_FACEINDEX; mask |= vcg::tri::io::Mask::IOM_FACECOLOR; if (vcg::tri::io::ExporterPLY::Save(*this, filePath.string().c_str(), mask, false) != 0) { return false; } return true; } #ifdef POLYSCOPE_DEFINED polyscope::SurfaceMesh *registerForDrawing( const std::optional> &desiredColor = std::nullopt, const bool &shouldEnable = true) { auto vertices = getVertices(); auto faces = getFaces(); PolyscopeInterface::init(); polyscope::SurfaceMesh *polyscopeHandle_mesh = polyscope::registerSurfaceMesh(label, vertices, faces); const double drawingRadius = 0.002; polyscopeHandle_mesh->setEnabled(shouldEnable); polyscopeHandle_mesh->setEdgeWidth(drawingRadius); if (desiredColor.has_value()) { const glm::vec3 desiredColor_glm(desiredColor.value()[0], desiredColor.value()[1], desiredColor.value()[2]); polyscopeHandle_mesh->setSurfaceColor(glm::normalize(desiredColor_glm)); } return polyscopeHandle_mesh; } #endif void moveToCenter() { CoordType centerOfMass(0, 0, 0); for (int vi = 0; vi < VN(); vi++) { centerOfMass += vert[vi].cP(); } centerOfMass /= VN(); vcg::tri::UpdatePosition::Translate(*this, -centerOfMass); } /* * Returns the average distance from the center of each edge to the center of its face over the whole mesh * */ double getAverageFaceRadius() const { double averageFaceRadius = 0; for (int fi = 0; fi < FN(); fi++) { const VCGPolyMesh::FaceType &f = face[fi]; CoordType centerOfFace(0, 0, 0); for (int vi = 0; vi < f.VN(); vi++) { centerOfFace = centerOfFace + f.cP(vi); } centerOfFace /= f.VN(); double faceRadius = 0; // for (int face_ei = 0; face_ei < f.EN(); face_ei++) { // std::cout << "fi:" << getIndex(f) << std::endl; // auto vps = f.FVp(0); // auto vpe = vps; for (int i = 0; i < f.VN(); i++) { faceRadius += vcg::Distance(centerOfFace, (f.cP0(i) + f.cP1(i)) / 2); } // } const int faceEdges = f.VN(); //NOTE: When does this not hold? faceRadius /= faceEdges; averageFaceRadius += faceRadius; } averageFaceRadius /= FN(); return averageFaceRadius; } bool copy(VCGPolyMesh ©From) { vcg::tri::Append::MeshCopy(*this, copyFrom); label = copyFrom.getLabel(); // eigenEdges = mesh.getEigenEdges(); // if (eigenEdges.rows() == 0) { // getEdges(eigenEdges); // } // eigenVertices = mesh.getEigenVertices(); // if (eigenVertices.rows() == 0) { // getVertices(); // } vcg::tri::UpdateTopology::VertexEdge(*this); vcg::tri::UpdateTopology::VertexFace(*this); vcg::tri::UpdateTopology::FaceFace(*this); vcg::tri::UpdateTopology::AllocateEdge(*this); vcg::tri::UpdateTopology::EdgeEdge(*this); // vcg::tri::UpdateTopology::VertexFace(*this); return true; } VCGPolyMesh(VCGPolyMesh ©From) { copy(copyFrom); } VCGPolyMesh() {} template size_t getIndex(const MeshElement &meshElement) const { return vcg::tri::Index(*this, meshElement); } }; using ConstVCGPolyMesh = VCGPolyMesh; #endif // POLYMESH_HPP