#include "edgemesh.hpp" #include "vcg/simplex/face/topology.h" Eigen::MatrixX2i VCGEdgeMesh::getEigenEdges() const { return eigenEdges; } Eigen::MatrixX3d VCGEdgeMesh::getEigenVertices() const { // getVertices(eigenVertices); return eigenVertices; } Eigen::MatrixX3d VCGEdgeMesh::getEigenEdgeNormals() const { return eigenEdgeNormals; } bool VCGEdgeMesh::savePly(const std::string plyFilename) {} void VCGEdgeMesh::GeneratedRegularSquaredPattern( const double angleDeg, std::vector> &pattern, const size_t &desiredNumberOfSamples) { static const size_t piSamples = 10; // generate a pattern in a 1x1 quad const vcg::Point2d offset(0, 0); const size_t samplesNo = desiredNumberOfSamples; // std::max(desiredNumberOfSamples, size_t(piSamples * (angleDeg / // 180))); const double angle = vcg::math::ToRad(angleDeg); pattern.clear(); // first arm std::vector arm; { for (int k = 0; k <= samplesNo; k++) { const double t = double(k) / samplesNo; const double a = (1 - t) * angle; // const double r = vcg::math::Sin(t*M_PI_2) /*(1-((1-t)*(1-t)))*/ * 0.5; const double r = t * 0.5; // linear vcg::Point2d p(vcg::math::Cos(a), vcg::math::Sin(a)); arm.push_back((p * r)); } pattern.push_back(arm); } // other arms for (int i = 0; i < 3; i++) { for (vcg::Point2d &p : arm) { p = vcg::Point2d(-p.Y(), p.X()); } pattern.push_back(arm); } assert(pattern.size() == 4); // offset all for (auto &arm : pattern) { for (vcg::Point2d &p : arm) { p += offset; } } } void VCGEdgeMesh::createSpiral(const float °reesOfArm, const size_t &numberOfSamples) { std::vector> spiralPoints; GeneratedRegularSquaredPattern(degreesOfArm, spiralPoints, numberOfSamples); for (size_t armIndex = 0; armIndex < spiralPoints.size(); armIndex++) { for (size_t pointIndex = 0; pointIndex < spiralPoints[armIndex].size() - 1; pointIndex++) { const vcg::Point2d p0 = spiralPoints[armIndex][pointIndex]; const vcg::Point2d p1 = spiralPoints[armIndex][pointIndex + 1]; CoordType n(0, 0, 1); auto ei = vcg::tri::Allocator::AddEdge( *this, VCGEdgeMesh::CoordType(p0.X(), p0.Y(), 0), VCGEdgeMesh::CoordType(p1.X(), p1.Y(), 0)); ei->cV(0)->N() = n; ei->cV(1)->N() = n; } } // setDefaultAttributes(); } bool VCGEdgeMesh::createSpanGrid(const size_t squareGridDimension) { return createSpanGrid(squareGridDimension, squareGridDimension); } bool VCGEdgeMesh::createSpanGrid(const size_t desiredWidth, const size_t desiredHeight) { std::cout << "Grid of dimensions:" << desiredWidth << "," << desiredHeight << std::endl; const VCGEdgeMesh::CoordType n(0, 0, 1); int x = 0; int y = 0; // for (size_t vi = 0; vi < numberOfVertices; vi++) { while (y <= desiredHeight) { // std::cout << x << " " << y << std::endl; auto p = VCGEdgeMesh::CoordType(x, y, 0); vcg::tri::Allocator::AddVertex(*this, p, n); x++; if (x > desiredWidth) { x = 0; y++; } } for (size_t vi = 0; vi < VN(); vi++) { int x = vi % (desiredWidth + 1); int y = vi / (desiredWidth + 1); const bool isCornerNode = (y == 0 && x == 0) || (y == 0 && x == desiredWidth) || (y == desiredHeight && x == 0) || (y == desiredHeight && x == desiredWidth); if (isCornerNode) { continue; } if (y == 0) { // row 0.Connect with node above vcg::tri::Allocator::AddEdge(*this, vi, vi + desiredWidth + 1); continue; } else if (x == 0) { // col 0.Connect with node to the right vcg::tri::Allocator::AddEdge(*this, vi, vi + 1); continue; } else if (y == desiredHeight) { // row 0.Connect with node below // vcg::tri::Allocator::AddEdge(*this, vi, // vi - (desiredWidth + // 1)); continue; } else if (x == desiredWidth) { // row 0.Connect with node to the left // vcg::tri::Allocator::AddEdge(*this, vi, vi - 1); continue; } vcg::tri::Allocator::AddEdge(*this, vi, vi + desiredWidth + 1); vcg::tri::Allocator::AddEdge(*this, vi, vi + 1); // vcg::tri::Allocator::AddEdge(*this, vi, // vi - (desiredWidth + 1)); // vcg::tri::Allocator::AddEdge(*this, vi, vi - 1); } vcg::tri::Allocator::DeleteVertex(*this, vert[0]); vcg::tri::Allocator::DeleteVertex(*this, vert[desiredWidth]); vcg::tri::Allocator::DeleteVertex( *this, vert[desiredHeight * (desiredWidth + 1)]); vcg::tri::Allocator::DeleteVertex( *this, vert[(desiredHeight + 1) * (desiredWidth + 1) - 1]); vcg::tri::Allocator::CompactVertexVector(*this); getEdges(eigenEdges); getVertices(eigenVertices); // vcg::tri::Allocator::CompactEdgeVector(*this); // const size_t numberOfEdges = // desiredHeight * (desiredWidth - 1) + desiredWidth * (desiredHeight - // 1); // handleBeamDimensions._handle->data.resize( // numberOfEdges, CylindricalElementDimensions(0.03, 0.026)); // handleBeamMaterial._handle->data.resize(numberOfEdges, // ElementMaterial(0.3, 200)); return true; } bool VCGEdgeMesh::loadFromPly(const std::string plyFilename) { std::string usedPath = plyFilename; if (std::filesystem::path(plyFilename).is_relative()) { usedPath = std::filesystem::absolute(plyFilename).string(); } assert(std::filesystem::exists(usedPath)); this->Clear(); const bool useDefaultImporter = false; if (useDefaultImporter) { if (!loadUsingDefaultLoader(usedPath)) { return false; } eigenEdgeNormals.resize(EN(), 3); for (int i = 0; i < EN(); i++) { eigenEdgeNormals.row(i) = Eigen::Vector3d(0, 1, 0); } } else { if (!loadUsingNanoply(usedPath)) { std::cerr << "Error: Unable to open " + usedPath << std::endl; return false; } } getEdges(eigenEdges); getVertices(eigenVertices); vcg::tri::UpdateTopology::VertexEdge(*this); std::cout << plyFilename << " was loaded successfuly." << std::endl; std::cout << "Mesh has " << EN() << " edges." << std::endl; return true; } bool VCGEdgeMesh::loadUsingNanoply(const std::string &plyFilename) { this->Clear(); // assert(plyFileHasAllRequiredFields(plyFilename)); // Load the ply file unsigned int mask = 0; mask |= nanoply::NanoPlyWrapper::IO_VERTCOORD; mask |= nanoply::NanoPlyWrapper::IO_VERTNORMAL; mask |= nanoply::NanoPlyWrapper::IO_EDGEINDEX; if (nanoply::NanoPlyWrapper::LoadModel(plyFilename.c_str(), *this, mask) != 0) { return false; } return true; } // bool VCGEdgeMesh::plyFileHasAllRequiredFields(const std::string &plyFilename) // { // const nanoply::Info info(plyFilename); // const std::vector::const_iterator edgeElemIt = // std::find_if(info.elemVec.begin(), info.elemVec.end(), // [&](const nanoply::PlyElement &plyElem) { // return plyElem.plyElem == nanoply::NNP_EDGE_ELEM; // }); // if (edgeElemIt == info.elemVec.end()) { // std::cerr << "Ply file is missing edge elements." << std::endl; // return false; // } // const std::vector &edgePropertyVector = // edgeElemIt->propVec; // return hasPlyEdgeProperty(plyFilename, edgePropertyVector, // plyPropertyBeamDimensionsID) && // hasPlyEdgeProperty(plyFilename, edgePropertyVector, // plyPropertyBeamMaterialID); //} bool VCGEdgeMesh::hasPlyEdgeProperty( const std::string &plyFilename, const std::vector &edgeProperties, const std::string &plyEdgePropertyName) { const bool hasEdgeProperty = hasProperty(edgeProperties, plyEdgePropertyName); if (!hasEdgeProperty) { std::cerr << "Ply file " + plyFilename + " is missing the propertry:" + plyEdgePropertyName << std::endl; return false; } return true; } bool VCGEdgeMesh::hasProperty(const std::vector &v, const std::string &propertyName) { return v.end() != std::find_if(v.begin(), v.end(), [&](const nanoply::PlyProperty &plyProperty) { return plyProperty.name == propertyName; }); } Eigen::MatrixX3d VCGEdgeMesh::getNormals() const { Eigen::MatrixX3d vertexNormals; vertexNormals.resize(VN(), 3); for (int vertexIndex = 0; vertexIndex < VN(); vertexIndex++) { VCGEdgeMesh::CoordType vertexNormal = vert[static_cast(vertexIndex)].cN(); vertexNormals.row(vertexIndex) = vertexNormal.ToEigenVector(); } return vertexNormals; } void VCGEdgeMesh::getEdges(Eigen::MatrixX3d &edgeStartingPoints, Eigen::MatrixX3d &edgeEndingPoints) const { edgeStartingPoints.resize(EN(), 3); edgeEndingPoints.resize(EN(), 3); for (int edgeIndex = 0; edgeIndex < EN(); edgeIndex++) { const VCGEdgeMesh::EdgeType &edge = this->edge[edgeIndex]; edgeStartingPoints.row(edgeIndex) = edge.cP(0).ToEigenVector(); edgeEndingPoints.row(edgeIndex) = edge.cP(1).ToEigenVector(); } } VCGEdgeMesh::VCGEdgeMesh() {} void VCGEdgeMesh::updateEigenEdgeAndVertices() { getEdges(eigenEdges); getVertices(eigenVertices); } void VCGEdgeMesh::copy(VCGEdgeMesh &mesh) { vcg::tri::Append::MeshCopy(*this, mesh); label = mesh.getLabel(); eigenEdges = mesh.getEigenEdges(); if (eigenEdges.rows() == 0) { getEdges(eigenEdges); } eigenVertices = mesh.getEigenVertices(); if (eigenVertices.rows() == 0) { getVertices(eigenVertices); } vcg::tri::UpdateTopology::VertexEdge(*this); } void VCGEdgeMesh::getVertices(Eigen::MatrixX3d &vertices) { vertices = Eigen::MatrixX3d(); vertices.resize(VN(), 3); for (int vi = 0; vi < VN(); vi++) { if (vert[vi].IsD()) { continue; } VCGEdgeMesh::CoordType vertexCoordinates = vert[static_cast(vi)].cP(); vertices.row(vi) = vertexCoordinates.ToEigenVector(); } } std::string VCGEdgeMesh::getLabel() const { return label; } void VCGEdgeMesh::setLabel(const std::string &value) { label = value; } void VCGEdgeMesh::getEdges(Eigen::MatrixX2i &edges) { edges = Eigen::MatrixX2i(); edges.resize(EN(), 2); for (int edgeIndex = 0; edgeIndex < EN(); edgeIndex++) { const VCGEdgeMesh::EdgeType &edge = this->edge[edgeIndex]; const size_t nodeIndex0 = vcg::tri::Index(*this, edge.cV(0)); const size_t nodeIndex1 = vcg::tri::Index(*this, edge.cV(1)); edges.row(edgeIndex) = Eigen::Vector2i(nodeIndex0, nodeIndex1); } } void VCGEdgeMesh::printVertexCoordinates(const size_t &vi) const { std::cout << "vi:" << vi << " " << vert[vi].cP()[0] << " " << vert[vi].cP()[1] << " " << vert[vi].cP()[2] << std::endl; } void VCGEdgeMesh::registerForDrawing() const { initPolyscope(); polyscope::registerCurveNetwork(label, getEigenVertices(), getEigenEdges()); }