From 5aaf4f5242b25e4fc2996729747a3a85d88a726c Mon Sep 17 00:00:00 2001 From: iasonmanolas Date: Mon, 15 Mar 2021 19:04:29 +0200 Subject: [PATCH] Refactoring --- beam.hpp | 0 beamformfinder.cpp | 95 +++--- beamformfinder.hpp | 2 - csvfile.hpp | 0 edgemesh.cpp | 57 ++-- edgemesh.hpp | 23 +- elementalmesh.cpp | 16 +- elementalmesh.hpp | 20 +- flatpattern.cpp | 424 ------------------------ flatpattern.hpp | 35 -- mesh.hpp | 20 ++ optimizationstructs.hpp | 0 patternIO.cpp | 183 ++++++----- patternIO.hpp | 60 ++-- polymesh.hpp | 25 +- simulationhistoryplotter.hpp | 0 simulationresult.hpp | 32 +- simulationresult.hpp.orig | 0 topologyenumerator.cpp | 609 ----------------------------------- topologyenumerator.hpp | 7 +- trianglepatterngeometry.cpp | 577 ++++++++++++++++++++++++++++----- trianglepatterngeometry.hpp | 44 ++- trianglepattterntopology.cpp | 0 trianglepattterntopology.hpp | 0 utilities.hpp | 5 + vcgtrimesh.cpp | 1 + vcgtrimesh.hpp | 1 - 27 files changed, 862 insertions(+), 1374 deletions(-) mode change 100644 => 100755 beam.hpp mode change 100644 => 100755 beamformfinder.cpp mode change 100644 => 100755 beamformfinder.hpp mode change 100644 => 100755 csvfile.hpp mode change 100644 => 100755 edgemesh.cpp mode change 100644 => 100755 edgemesh.hpp mode change 100644 => 100755 elementalmesh.cpp mode change 100644 => 100755 elementalmesh.hpp delete mode 100644 flatpattern.cpp delete mode 100644 flatpattern.hpp create mode 100755 mesh.hpp mode change 100644 => 100755 optimizationstructs.hpp mode change 100644 => 100755 patternIO.cpp mode change 100644 => 100755 patternIO.hpp mode change 100644 => 100755 polymesh.hpp mode change 100644 => 100755 simulationhistoryplotter.hpp mode change 100644 => 100755 simulationresult.hpp mode change 100644 => 100755 simulationresult.hpp.orig mode change 100644 => 100755 topologyenumerator.hpp mode change 100644 => 100755 trianglepatterngeometry.cpp mode change 100644 => 100755 trianglepatterngeometry.hpp mode change 100644 => 100755 trianglepattterntopology.cpp mode change 100644 => 100755 trianglepattterntopology.hpp mode change 100644 => 100755 utilities.hpp mode change 100644 => 100755 vcgtrimesh.cpp mode change 100644 => 100755 vcgtrimesh.hpp diff --git a/beam.hpp b/beam.hpp old mode 100644 new mode 100755 diff --git a/beamformfinder.cpp b/beamformfinder.cpp old mode 100644 new mode 100755 index 018d6f7..4000ffc --- a/beamformfinder.cpp +++ b/beamformfinder.cpp @@ -15,9 +15,9 @@ void FormFinder::runUnitTests() { VCGEdgeMesh beam; // const size_t spanGridSize = 11; // mesh.createSpanGrid(spanGridSize); - beam.loadPly(std::filesystem::path(groundOfTruthFolder) - .append("simpleBeam.ply") - .string()); + beam.load(std::filesystem::path(groundOfTruthFolder) + .append("simpleBeam.ply") + .string()); std::unordered_map> fixedVertices; fixedVertices[0] = std::unordered_set{0, 1, 2, 3}; fixedVertices[beam.VN() - 1] = std::unordered_set{1, 2}; @@ -65,9 +65,9 @@ void FormFinder::runUnitTests() { VCGEdgeMesh shortSpanGrid; // const size_t spanGridSize = 11; // mesh.createSpanGrid(spanGridSize); - shortSpanGrid.loadPly(std::filesystem::path(groundOfTruthFolder) - .append("shortSpanGridshell.ply") - .string()); + shortSpanGrid.load(std::filesystem::path(groundOfTruthFolder) + .append("shortSpanGridshell.ply") + .string()); fixedVertices.clear(); //// Corner nodes @@ -123,9 +123,9 @@ void FormFinder::runUnitTests() { // Third example of the paper VCGEdgeMesh longSpanGrid; - longSpanGrid.loadPly(std::filesystem::path(groundOfTruthFolder) - .append("longSpanGridshell.ply") - .string()); + longSpanGrid.load(std::filesystem::path(groundOfTruthFolder) + .append("longSpanGridshell.ply") + .string()); const size_t spanGridSize = 11; fixedVertices.clear(); @@ -793,7 +793,7 @@ void FormFinder::updateResidualForcesOnTheFly( std::vector>(4, {-1, Vector6d()})); // omp_lock_t writelock; // omp_init_lock(&writelock); - //#pragma omp parallel for //schedule(static) num_threads(8) + //#pragma omp parallel for schedule(static) num_threads(8) for (int ei = 0; ei < pMesh->EN(); ei++) { const EdgeType &e = pMesh->edge[ei]; const SimulationMesh::VertexType &ev_j = *e.cV(0); @@ -1019,10 +1019,23 @@ void FormFinder::updateNodalExternalForces( } externalMomentsNorm += std::sqrt(pow(nodalExternalForce[3], 2) + pow(nodalExternalForce[4], 2)); - // CoordType v = (mesh->vert[nodeIndex].cP() - - // mesh->vert[0].cP()).Normalize(); const double forceMagnitude = 0.1; - // nodalExternalForce[3] = v[0] * forceMagnitude; - // nodalExternalForce[4] = v[1] * forceMagnitude; + + /* + * The external moments are given as a rotation around an axis. + * In this implementation we model moments as rotation of the normal vector + * and because of that we need to transform the moments. + */ + + if (externalMomentsNorm != 0) { + VectorType momentVector( + nodalExternalForce[3], nodalExternalForce[4], + nodalExternalForce[5]); // rotation around this vector + VectorType transformedVector = momentVector ^ VectorType(0, 0, 1); + nodalExternalForce[3] = transformedVector[0]; + nodalExternalForce[4] = transformedVector[1]; + nodalExternalForce[5] = transformedVector[5]; + } + node.force.external = nodalExternalForce; } } @@ -1162,26 +1175,26 @@ void FormFinder::updateNodalMasses() { assert(rotationalSumSk_I3 != 0); assert(rotationalSumSk_J != 0); } - pMesh->nodes[v].translationalMass = + pMesh->nodes[v].mass.translational = gamma * pow(mSettings.Dtini, 2) * 2 * translationalSumSk; - pMesh->nodes[v].rotationalMass_I2 = + pMesh->nodes[v].mass.rotationalI2 = gamma * pow(mSettings.Dtini, 2) * 8 * rotationalSumSk_I2; - pMesh->nodes[v].rotationalMass_I3 = + pMesh->nodes[v].mass.rotationalI3 = gamma * pow(mSettings.Dtini, 2) * 8 * rotationalSumSk_I3; - pMesh->nodes[v].rotationalMass_J = + pMesh->nodes[v].mass.rotationalJ = gamma * pow(mSettings.Dtini, 2) * 8 * rotationalSumSk_J; assert(std::pow(mSettings.Dtini, 2.0) * translationalSumSk / - pMesh->nodes[v].translationalMass < + pMesh->nodes[v].mass.translational < 2); assert(std::pow(mSettings.Dtini, 2.0) * rotationalSumSk_I2 / - pMesh->nodes[v].rotationalMass_I2 < + pMesh->nodes[v].mass.rotationalI2 < 2); assert(std::pow(mSettings.Dtini, 2.0) * rotationalSumSk_I3 / - pMesh->nodes[v].rotationalMass_I3 < + pMesh->nodes[v].mass.rotationalI3 < 2); assert(std::pow(mSettings.Dtini, 2.0) * rotationalSumSk_J / - pMesh->nodes[v].rotationalMass_J < + pMesh->nodes[v].mass.rotationalJ < 2); } } @@ -1193,16 +1206,16 @@ void FormFinder::updateNodalAccelerations() { for (DoFType dofi = DoF::Ux; dofi < DoF::NumDoF; dofi++) { if (dofi == DoF::Ux || dofi == DoF::Uy || dofi == DoF::Uz) { node.acceleration[dofi] = - node.force.residual[dofi] / node.translationalMass; + node.force.residual[dofi] / node.mass.translational; } else if (dofi == DoF::Nx) { node.acceleration[dofi] = - node.force.residual[dofi] / node.rotationalMass_J; + node.force.residual[dofi] / node.mass.rotationalJ; } else if (dofi == DoF::Ny) { node.acceleration[dofi] = - node.force.residual[dofi] / node.rotationalMass_I3; + node.force.residual[dofi] / node.mass.rotationalI3; } else if (dofi == DoF::Nr) { node.acceleration[dofi] = - node.force.residual[dofi] / node.rotationalMass_I2; + node.force.residual[dofi] / node.mass.rotationalI2; } } } @@ -1239,7 +1252,6 @@ void FormFinder::updateNodePosition( const std::unordered_map> &fixedVertices) { Node &node = pMesh->nodes[v]; - CoordType previousLocation = v.cP(); const VertexIndex &vi = pMesh->nodes[v].vi; VectorType displacementVector(0, 0, 0); @@ -1252,7 +1264,6 @@ void FormFinder::updateNodePosition( if (!fixedVertices.contains(vi) || !fixedVertices.at(vi).contains(2)) { displacementVector += VectorType(0, 0, node.displacements[2]); } - node.previousLocation = previousLocation; v.P() = node.initialLocation + displacementVector; if (shouldApplyInitialDistortion && mCurrentSimulationStep < 40) { VectorType desiredInitialDisplacement(0, 0, 0.01); @@ -1411,16 +1422,16 @@ void FormFinder::updateKineticEnergy() { std::pow(node.velocity[0], 2) + std::pow(node.velocity[1], 2) + std::pow(node.velocity[2], 2)); const double nodeTranslationalKineticEnergy = - 0.5 * node.translationalMass * pow(translationalVelocityNorm, 2); + 0.5 * node.mass.translational * pow(translationalVelocityNorm, 2); const double nodeRotationalKineticEnergy = - 0.5 * (node.rotationalMass_J * pow(node.velocity[3], 2) + - +node.rotationalMass_I3 * pow(node.velocity[4], 2) + - +node.rotationalMass_I2 * pow(node.velocity[5], 2)); + 0.5 * (node.mass.rotationalJ * pow(node.velocity[3], 2) + + +node.mass.rotationalI3 * pow(node.velocity[4], 2) + + +node.mass.rotationalI2 * pow(node.velocity[5], 2)); node.kineticEnergy += nodeTranslationalKineticEnergy /*+ nodeRotationalKineticEnergy*/; - assert(node.kineticEnergy < 10000000000000000000); + assert(node.kineticEnergy < 1e15); pMesh->currentTotalKineticEnergy += node.kineticEnergy; pMesh->currentTotalTranslationalKineticEnergy += @@ -1472,13 +1483,13 @@ void FormFinder::updatePositionsOnTheFly( // assert(rotationalSumSk_I3 != 0); // assert(rotationalSumSk_J != 0); } - pMesh->nodes[v].translationalMass = + pMesh->nodes[v].mass.translational = gamma * pow(mSettings.Dtini, 2) * 2 * translationalSumSk; - pMesh->nodes[v].rotationalMass_I2 = + pMesh->nodes[v].mass.rotationalI2 = gamma * pow(mSettings.Dtini, 2) * 8 * rotationalSumSk_I2; - pMesh->nodes[v].rotationalMass_I3 = + pMesh->nodes[v].mass.rotationalI3 = gamma * pow(mSettings.Dtini, 2) * 8 * rotationalSumSk_I3; - pMesh->nodes[v].rotationalMass_J = + pMesh->nodes[v].mass.rotationalJ = gamma * pow(mSettings.Dtini, 2) * 8 * rotationalSumSk_J; // assert(std::pow(mSettings.Dtini, 2.0) * translationalSumSk / @@ -1500,16 +1511,16 @@ void FormFinder::updatePositionsOnTheFly( for (DoFType dofi = DoF::Ux; dofi < DoF::NumDoF; dofi++) { if (dofi == DoF::Ux || dofi == DoF::Uy || dofi == DoF::Uz) { node.acceleration[dofi] = - node.force.residual[dofi] / node.translationalMass; + node.force.residual[dofi] / node.mass.translational; } else if (dofi == DoF::Nx) { node.acceleration[dofi] = - node.force.residual[dofi] / node.rotationalMass_J; + node.force.residual[dofi] / node.mass.rotationalJ; } else if (dofi == DoF::Ny) { node.acceleration[dofi] = - node.force.residual[dofi] / node.rotationalMass_I3; + node.force.residual[dofi] / node.mass.rotationalI3; } else if (dofi == DoF::Nr) { node.acceleration[dofi] = - node.force.residual[dofi] / node.rotationalMass_I2; + node.force.residual[dofi] / node.mass.rotationalI2; } } } @@ -1789,4 +1800,4 @@ mesh->currentTotalPotentialEnergykN*/ } } return results; -} +} \ No newline at end of file diff --git a/beamformfinder.hpp b/beamformfinder.hpp old mode 100644 new mode 100755 index 79797fc..825a9a4 --- a/beamformfinder.hpp +++ b/beamformfinder.hpp @@ -3,8 +3,6 @@ #include "elementalmesh.hpp" #include "matplot/matplot.h" -//#include "polyscope/curve_network.h" -//#include "polyscope/polyscope.h" #include "simulationresult.hpp" #include #include diff --git a/csvfile.hpp b/csvfile.hpp old mode 100644 new mode 100755 diff --git a/edgemesh.cpp b/edgemesh.cpp old mode 100644 new mode 100755 index 976c2b3..1cb56e0 --- a/edgemesh.cpp +++ b/edgemesh.cpp @@ -1,5 +1,6 @@ #include "edgemesh.hpp" #include "vcg/simplex/face/topology.h" +#include Eigen::MatrixX2i VCGEdgeMesh::getEigenEdges() const { return eigenEdges; } @@ -45,7 +46,8 @@ void VCGEdgeMesh::GeneratedRegularSquaredPattern( 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 = 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)); @@ -174,7 +176,7 @@ bool VCGEdgeMesh::createSpanGrid(const size_t desiredWidth, return true; } -bool VCGEdgeMesh::loadPly(const std::string plyFilename) { +bool VCGEdgeMesh::load(const string &plyFilename) { std::string usedPath = plyFilename; if (std::filesystem::path(plyFilename).is_relative()) { @@ -182,7 +184,6 @@ bool VCGEdgeMesh::loadPly(const std::string plyFilename) { } assert(std::filesystem::exists(usedPath)); this->Clear(); - const bool useDefaultImporter = false; if (!loadUsingNanoply(usedPath)) { std::cerr << "Error: Unable to open " + usedPath << std::endl; return false; @@ -217,7 +218,8 @@ bool VCGEdgeMesh::loadUsingNanoply(const std::string &plyFilename) { return true; } -// bool VCGEdgeMesh::plyFileHasAllRequiredFields(const std::string &plyFilename) +// bool VCGEdgeMesh::plyFileHasAllRequiredFields(const std::string +// &plyFilename) // { // const nanoply::Info info(plyFilename); // const std::vector::const_iterator edgeElemIt = @@ -238,28 +240,6 @@ bool VCGEdgeMesh::loadUsingNanoply(const std::string &plyFilename) { // 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); @@ -289,8 +269,10 @@ void VCGEdgeMesh::getEdges(Eigen::MatrixX3d &edgeStartingPoints, VCGEdgeMesh::VCGEdgeMesh() {} void VCGEdgeMesh::updateEigenEdgeAndVertices() { +#ifdef POLYSCOPE_DEFINED getEdges(eigenEdges); getVertices(eigenVertices); +#endif } void VCGEdgeMesh::copy(VCGEdgeMesh &mesh) { @@ -329,9 +311,15 @@ void VCGEdgeMesh::getEdges(Eigen::MatrixX2i &edges) { 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); + assert(!edge.IsD()); + auto vp0 = edge.cV(0); + auto vp1 = edge.cV(1); + assert(vcg::tri::IsValidPointer(*this, vp0) && + vcg::tri::IsValidPointer(*this, vp1)); + const size_t vi0 = vcg::tri::Index(*this, vp0); + const size_t vi1 = vcg::tri::Index(*this, vp1); + assert(vi0 != -1 && vi1 != -1); + edges.row(edgeIndex) = Eigen::Vector2i(vi0, vi1); } } @@ -342,13 +330,14 @@ void VCGEdgeMesh::printVertexCoordinates(const size_t &vi) const { #ifdef POLYSCOPE_DEFINED void VCGEdgeMesh::registerForDrawing( - const std::optional &desiredColor) const { + const std::optional &desiredColor, + const bool &shouldEnable) const { initPolyscope(); const double drawingRadius = 0.002; - auto polyscopeHandle_edgeMesh = - polyscope::registerCurveNetwork(label, getEigenVertices(), - getEigenEdges()) - ->setRadius(drawingRadius, true); + auto polyscopeHandle_edgeMesh = polyscope::registerCurveNetwork( + label, getEigenVertices(), getEigenEdges()); + polyscopeHandle_edgeMesh->setEnabled(shouldEnable); + polyscopeHandle_edgeMesh->setRadius(drawingRadius, true); if (desiredColor.has_value()) { polyscopeHandle_edgeMesh->setColor(desiredColor.value()); } diff --git a/edgemesh.hpp b/edgemesh.hpp old mode 100644 new mode 100755 index 7995507..cfb6796 --- a/edgemesh.hpp +++ b/edgemesh.hpp @@ -1,14 +1,13 @@ #ifndef EDGEMESH_HPP #define EDGEMESH_HPP #include "beam.hpp" -#include "externvariables.hpp" -#include "polymesh.hpp" +#include "mesh.hpp" +//#include "polymesh.hpp" #include "utilities.hpp" -#include "vcgtrimesh.hpp" +//#include "vcgtrimesh.hpp" #include #include #include -#include using EdgeIndex = size_t; @@ -29,7 +28,8 @@ class VCGEdgeMeshEdgeType vcg::edge::VEAdj> {}; class VCGEdgeMesh : public vcg::tri::TriMesh, - std::vector> { + std::vector>, + Mesh { protected: Eigen::MatrixX2i eigenEdges; @@ -54,19 +54,11 @@ public: Eigen::MatrixX3d getNormals() const; - bool hasProperty(const std::vector &v, - const std::string &propertyName); - - bool - hasPlyEdgeProperty(const std::string &plyFilename, - const std::vector &edgeProperties, - const std::string &plyEdgePropertyName); - bool plyFileHasAllRequiredFields(const std::string &plyFilename); bool loadUsingNanoply(const std::string &plyFilename); - virtual bool loadPly(const std::string plyFilename); + bool load(const std::string &plyFilename) override; bool savePly(const std::string plyFilename); @@ -80,7 +72,8 @@ public: void printVertexCoordinates(const size_t &vi) const; #ifdef POLYSCOPE_DEFINED void registerForDrawing( - const std::optional &desiredColor = std::nullopt) const; + const std::optional &desiredColor = std::nullopt, + const bool &shouldEnable = true) const; void unregister() const; #endif std::string getLabel() const; diff --git a/elementalmesh.cpp b/elementalmesh.cpp old mode 100644 new mode 100755 index 0cc48b2..264f38a --- a/elementalmesh.cpp +++ b/elementalmesh.cpp @@ -1,4 +1,5 @@ #include "elementalmesh.hpp" +#include SimulationMesh::SimulationMesh() { elements = vcg::tri::Allocator::GetPerEdgeAttribute( @@ -45,8 +46,8 @@ SimulationMesh::~SimulationMesh() { nodes); } -SimulationMesh::SimulationMesh(FlatPattern &pattern) { - vcg::tri::MeshAssert::VertexNormalNormalized(pattern); +SimulationMesh::SimulationMesh(PatternGeometry &pattern) { + vcg::tri::MeshAssert::VertexNormalNormalized(pattern); vcg::tri::Append::MeshCopy(*this, pattern); elements = vcg::tri::Allocator::GetPerEdgeAttribute( @@ -218,6 +219,7 @@ void SimulationMesh::initializeElements() { element.derivativeR_j.resize(6); element.derivativeR_jplus1.resize(6); } + updateElementalFrames(); } void SimulationMesh::updateElementalLengths() { @@ -235,6 +237,14 @@ void SimulationMesh::updateElementalLengths() { } } +void SimulationMesh::updateElementalFrames() { + for (const EdgeType &e : edge) { + const VectorType elementNormal = + (e.cV(0)->cN() + e.cV(1)->cN()).Normalize(); + elements[e].frame = computeElementFrame(e.cP(0), e.cP(1), elementNormal); + } +} + void SimulationMesh::setBeamCrossSection( const CrossSectionType &beamDimensions) { for (size_t ei = 0; ei < EN(); ei++) { @@ -267,7 +277,7 @@ std::vector SimulationMesh::getBeamMaterial() { return beamMaterial; } -bool SimulationMesh::loadPly(const string &plyFilename) { +bool SimulationMesh::load(const string &plyFilename) { this->Clear(); // assert(plyFileHasAllRequiredFields(plyFilename)); // Load the ply file diff --git a/elementalmesh.hpp b/elementalmesh.hpp old mode 100644 new mode 100755 index e04c495..1e46590 --- a/elementalmesh.hpp +++ b/elementalmesh.hpp @@ -3,7 +3,7 @@ #include "Eigen/Dense" #include "edgemesh.hpp" -#include "flatpattern.hpp" +#include "trianglepatterngeometry.hpp" struct Element; struct Node; @@ -24,14 +24,14 @@ public: PerEdgeAttributeHandle elements; PerVertexAttributeHandle nodes; ~SimulationMesh(); - SimulationMesh(FlatPattern &pattern); + SimulationMesh(PatternGeometry &pattern); SimulationMesh(ConstVCGEdgeMesh &edgeMesh); SimulationMesh(SimulationMesh &elementalMesh); void updateElementalLengths(); std::vector getIncidentElements(const VCGEdgeMesh::VertexType &v); - virtual bool loadPly(const string &plyFilename); + virtual bool load(const string &plyFilename); std::vector getBeamDimensions(); std::vector getBeamMaterial(); @@ -47,6 +47,7 @@ public: void setBeamMaterial(const double &pr, const double &ym); void reset(); SimulationMesh(); + void updateElementalFrames(); }; struct Element { @@ -131,14 +132,17 @@ struct Node { bool hasExternalForce() const { return external.isZero(); } }; + struct Mass { + double translational; + double rotationalI2; + double rotationalI3; + double rotationalJ; + }; + + Mass mass; VertexIndex vi; CoordType initialLocation; - CoordType previousLocation; CoordType initialNormal; - double translationalMass; - double rotationalMass_I2; - double rotationalMass_I3; - double rotationalMass_J; Vector6d acceleration{0}; Forces force; Vector6d velocity{0}; diff --git a/flatpattern.cpp b/flatpattern.cpp deleted file mode 100644 index 309e4e6..0000000 --- a/flatpattern.cpp +++ /dev/null @@ -1,424 +0,0 @@ -#include "flatpattern.hpp" -#include "trianglepatterngeometry.hpp" -#include - -FlatPattern::FlatPattern() {} - -FlatPattern::FlatPattern(const std::string &filename, bool addNormalsIfAbsent) { - if (!std::filesystem::exists(std::filesystem::path(filename))) { - assert(false); - std::cerr << "No flat pattern with name " << filename << std::endl; - return; - } - if (!loadPly(filename)) { - assert(false); - std::cerr << "File could not be loaded " << filename << std::endl; - return; - } - if (addNormalsIfAbsent) { - bool normalsAreAbsent = vert[0].cN().Norm() < 0.000001; - if (normalsAreAbsent) { - for (auto &v : vert) { - v.N() = CoordType(0, 0, 1); - } - } - } - - vcg::tri::UpdateTopology::VertexEdge(*this); - const double baseTriangleCentralEdgeSize = - (vert[0].cP() - vert[3].cP()).Norm(); - - updateEigenEdgeAndVertices(); -} - -FlatPattern::FlatPattern(const std::vector &numberOfNodesPerSlot, - const std::vector &edges) { - add(numberOfNodesPerSlot, edges); - // add normals - bool normalsAreAbsent = vert[0].cN().Norm() < 0.000001; - if (normalsAreAbsent) { - for (auto &v : vert) { - v.N() = CoordType(0, 0, 1); - } - } - baseTriangleHeight = (vert[0].cP() - vert[3].cP()).Norm(); - updateEigenEdgeAndVertices(); -} - -bool FlatPattern::createHoneycombAtom() { - VCGEdgeMesh honeycombQuarter; - const VCGEdgeMesh::CoordType n(0, 0, 1); - const double H = 0.2; - const double height = 1.5 * H; - const double width = 0.2; - const double theta = 70; - const double dy = tan(vcg::math::ToRad(90 - theta)) * width / 2; - vcg::tri::Allocator::AddVertex( - honeycombQuarter, VCGEdgeMesh::CoordType(0, height / 2, 0), n); - vcg::tri::Allocator::AddVertex( - honeycombQuarter, VCGEdgeMesh::CoordType(0, H / 2 - dy, 0), n); - vcg::tri::Allocator::AddVertex( - honeycombQuarter, VCGEdgeMesh::CoordType(width / 2, H / 2, 0), n); - vcg::tri::Allocator::AddVertex( - honeycombQuarter, VCGEdgeMesh::CoordType(width / 2, 0, 0), n); - vcg::tri::Allocator::AddEdge(honeycombQuarter, 0, 1); - vcg::tri::Allocator::AddEdge(honeycombQuarter, 1, 2); - vcg::tri::Allocator::AddEdge(honeycombQuarter, 2, 3); - - VCGEdgeMesh honeycombAtom; - // Top right - vcg::tri::Append::MeshCopy(honeycombAtom, - honeycombQuarter); - // Bottom right - vcg::Matrix44d rotM; - rotM.SetRotateDeg(180, vcg::Point3d(1, 0, 0)); - vcg::tri::UpdatePosition::Matrix(honeycombQuarter, rotM); - vcg::tri::Append::Mesh(honeycombAtom, - honeycombQuarter); - // Bottom left - rotM.SetRotateDeg(180, vcg::Point3d(0, 1, 0)); - vcg::tri::UpdatePosition::Matrix(honeycombQuarter, rotM); - vcg::tri::Append::Mesh(honeycombAtom, - honeycombQuarter); - // Top left - rotM.SetRotateDeg(180, vcg::Point3d(1, 0, 0)); - vcg::tri::UpdatePosition::Matrix(honeycombQuarter, rotM); - vcg::tri::Append::Mesh(honeycombAtom, - honeycombQuarter); - - for (VertexType &v : honeycombAtom.vert) { - v.P()[2] = 0; - } - - return true; -} - -void FlatPattern::copy(FlatPattern ©From) { - VCGEdgeMesh::copy(copyFrom); - baseTriangleHeight = copyFrom.getBaseTriangleHeight(); -} - -void FlatPattern::deleteDanglingEdges() { - for (VertexType &v : vert) { - std::vector incidentElements; - vcg::edge::VEStarVE(&v, incidentElements); - if (incidentElements.size() == 1) { - vcg::tri::Allocator::DeleteEdge(*this, *incidentElements[0]); - } - if (incidentElements.size() == 1) { - vcg::tri::Allocator::DeleteVertex(*this, v); - } - } - - vcg::tri::Clean::RemoveDegenerateVertex(*this); - vcg::tri::Clean::RemoveDegenerateEdge(*this); - vcg::tri::Allocator::CompactEveryVector(*this); -} - -void FlatPattern::scale(const double &desiredBaseTriangleCentralEdgeSize) { - this->baseTriangleHeight = desiredBaseTriangleCentralEdgeSize; - const double baseTriangleCentralEdgeSize = - (vert[0].cP() - vert[3].cP()).Norm(); - const double scaleRatio = - desiredBaseTriangleCentralEdgeSize / baseTriangleCentralEdgeSize; - - vcg::tri::UpdatePosition::Scale(*this, scaleRatio); -} - -void FlatPattern::deleteDanglingVertices() { - vcg::tri::Allocator::PointerUpdater pu; - deleteDanglingVertices(pu); -} - -void FlatPattern::deleteDanglingVertices( - vcg::tri::Allocator::PointerUpdater &pu) { - for (VertexType &v : vert) { - std::vector incidentElements; - vcg::edge::VEStarVE(&v, incidentElements); - if (incidentElements.size() == 0) { - vcg::tri::Allocator::DeleteVertex(*this, v); - } - } - - vcg::tri::Allocator::CompactVertexVector(*this, pu); - vcg::tri::Allocator::CompactEdgeVector(*this); - - updateEigenEdgeAndVertices(); -} - -void FlatPattern::tilePattern(VCGEdgeMesh &pattern, VCGPolyMesh &tileInto, - const bool &shouldDeleteDanglingEdges) { - const size_t middleIndex = 3; - double xOffset = - vcg::Distance(pattern.vert[0].cP(), pattern.vert[middleIndex].cP()) / - std::tan(M_PI / 3); - CoordType patternCoord0 = pattern.vert[0].cP(); - CoordType patternBottomRight = - pattern.vert[middleIndex].cP() + CoordType(xOffset, 0, 0); - CoordType patternBottomLeft = - pattern.vert[middleIndex].cP() - CoordType(xOffset, 0, 0); - std::vector patternTrianglePoints{ - patternCoord0, patternBottomRight, patternBottomLeft}; - CoordType pointOnPattern = - patternCoord0 + (patternBottomLeft - patternCoord0) ^ - (patternBottomRight - patternCoord0); - - std::vector faceCenters(FN()); - VCGTriMesh tileIntoEdgeMesh; - - for (VCGPolyMesh::FaceType &f : tileInto.face) { - std::vector incidentVertices; - vcg::face::VFIterator vfi( - &f, 0); // initialize the iterator to the first face - // vcg::face::Pos p(vfi.F(), f.cV(0)); - // vcg::face::VVOrderedStarFF(p, incidentVertices); - size_t numberOfNodes = 0; - CoordType centerOfFace(0, 0, 0); - for (size_t vi = 0; vi < f.VN(); vi++) { - numberOfNodes++; - centerOfFace = centerOfFace + f.cP(vi); - } - centerOfFace /= f.VN(); - vcg::tri::Allocator::AddVertex(tileIntoEdgeMesh, centerOfFace, - vcg::Color4b::Yellow); - - // const size_t vi = vcg::tri::Index(tileInto, v); - // std::cout << "vertex " << vi << " has incident vertices:" << - // std::endl; - for (size_t vi = 0; vi < f.VN(); vi++) { - // size_t f = 0; - // std::cout << vcg::tri::Index(tileInto, - // / incidentVertices[f]) / << std::endl; - - // Compute transformation matrix M - // vcg::Matrix44d M; - std::vector meshTrianglePoints{ - centerOfFace, f.cP(vi), vi + 1 == f.VN() ? f.cP(0) : f.cP(vi + 1)}; - CoordType faceNormal = ((meshTrianglePoints[1] - meshTrianglePoints[0]) ^ - (meshTrianglePoints[2] - meshTrianglePoints[0])) - .Normalize(); - auto fit = vcg::tri::Allocator::AddFace( - tileIntoEdgeMesh, meshTrianglePoints[0], meshTrianglePoints[1], - meshTrianglePoints[2]); - fit->N() = faceNormal; - CoordType pointOnTriMesh = - meshTrianglePoints[0] + - (meshTrianglePoints[1] - meshTrianglePoints[0]) ^ - (meshTrianglePoints[2] - meshTrianglePoints[0]); - vcg::Matrix44d M; - // vcg::ComputeRigidMatchMatrix(meshTrianglePoints, - // patternTrianglePoints, - // M); - vcg::Matrix44d A_prime; - A_prime[0][0] = meshTrianglePoints[0][0]; - A_prime[1][0] = meshTrianglePoints[0][1]; - A_prime[2][0] = meshTrianglePoints[0][2]; - A_prime[3][0] = 1; - A_prime[0][1] = meshTrianglePoints[1][0]; - A_prime[1][1] = meshTrianglePoints[1][1]; - A_prime[2][1] = meshTrianglePoints[1][2]; - A_prime[3][1] = 1; - A_prime[0][2] = meshTrianglePoints[2][0]; - A_prime[1][2] = meshTrianglePoints[2][1]; - A_prime[2][2] = meshTrianglePoints[2][2]; - A_prime[3][2] = 1; - A_prime[0][3] = pointOnTriMesh[0]; - A_prime[1][3] = pointOnTriMesh[1]; - A_prime[2][3] = pointOnTriMesh[2]; - A_prime[3][3] = 1; - vcg::Matrix44d A; - A[0][0] = patternTrianglePoints[0][0]; - A[1][0] = patternTrianglePoints[0][1]; - A[2][0] = patternTrianglePoints[0][2]; - A[3][0] = 1; - A[0][1] = patternTrianglePoints[1][0]; - A[1][1] = patternTrianglePoints[1][1]; - A[2][1] = patternTrianglePoints[1][2]; - A[3][1] = 1; - A[0][2] = patternTrianglePoints[2][0]; - A[1][2] = patternTrianglePoints[2][1]; - A[2][2] = patternTrianglePoints[2][2]; - A[3][2] = 1; - A[0][3] = pointOnPattern[0]; - A[1][3] = pointOnPattern[1]; - A[2][3] = pointOnPattern[2]; - A[3][3] = 1; - M = A_prime * vcg::Inverse(A); - - VCGEdgeMesh transformedPattern; - vcg::tri::Append::MeshCopy(transformedPattern, - pattern); - vcg::tri::UpdatePosition::Matrix(transformedPattern, M); - for (VertexType &v : transformedPattern.vert) { - v.N() = faceNormal; - } - - vcg::tri::Append::Mesh(*this, - transformedPattern); - } - } - - // vcg::tri::Clean::MergeCloseVertex(*this, 0.0000000001); - // vcg::tri::Clean::RemoveDegenerateVertex(*this); - // vcg::tri::Clean::RemoveDegenerateEdge(*this); - // vcg::tri::Allocator::CompactEveryVector(*this); - - vcg::tri::UpdateTopology::VertexEdge(*this); - - vcg::tri::Clean::MergeCloseVertex(*this, 0.0000000001); - deleteDanglingVertices(); - deleteDanglingEdges(); - vcg::tri::Clean::RemoveDegenerateVertex(*this); - vcg::tri::Clean::RemoveDegenerateEdge(*this); - vcg::tri::Allocator::CompactEveryVector(*this); - updateEigenEdgeAndVertices(); - savePly("tiledPattern.ply"); - - vcg::tri::Clean::MergeCloseVertex(tileIntoEdgeMesh, 0.0000000001); - vcg::tri::Clean::RemoveDegenerateVertex(tileIntoEdgeMesh); - vcg::tri::Clean::RemoveDegenerateEdge(tileIntoEdgeMesh); - tileIntoEdgeMesh.savePly("tileIntoTriMesh.ply"); -} - -void FlatPattern::createFan(const size_t &fanSize) { - FlatPattern rotatedPattern; - vcg::tri::Append::MeshCopy(rotatedPattern, *this); - for (int rotationCounter = 1; rotationCounter < fanSize; rotationCounter++) { - vcg::Matrix44d R; - auto rotationAxis = vcg::Point3d(0, 0, 1); - R.SetRotateDeg(360 / fanSize, rotationAxis); - vcg::tri::UpdatePosition::Matrix(rotatedPattern, R); - vcg::tri::Append::Mesh(*this, rotatedPattern); - } - - removeDuplicateVertices(); - // const double precision = 1e-4; - // for (size_t vi = 0; vi < VN(); vi++) { - // vert[vi].P()[0] = std::round(vert[vi].P()[0] * (1 / precision)) * - // precision; vert[vi].P()[1] = std::round(vert[vi].P()[1] * (1 / - // precision)) * precision; vert[vi].P()[2] = std::round(vert[vi].P()[2] - // * (1 / precision)) * precision; - // } - - updateEigenEdgeAndVertices(); -} - -void FlatPattern::removeDuplicateVertices() { - vcg::tri::Clean::MergeCloseVertex(*this, 0.0000000001); - vcg::tri::Clean::RemoveDegenerateVertex(*this); - vcg::tri::Clean::RemoveDegenerateEdge(*this); - vcg::tri::Allocator::CompactEveryVector(*this); - vcg::tri::UpdateTopology::VertexEdge(*this); -} - -double FlatPattern::getBaseTriangleHeight() const { return baseTriangleHeight; } - -void FlatPattern::tilePattern(VCGEdgeMesh &pattern, VCGTriMesh &tileInto) { - - const size_t middleIndex = 3; - double xOffset = - vcg::Distance(pattern.vert[0].cP(), pattern.vert[middleIndex].cP()) / - std::tan(M_PI / 3); - CoordType patternCoord0 = pattern.vert[0].cP(); - CoordType patternBottomRight = - pattern.vert[middleIndex].cP() + CoordType(xOffset, 0, 0); - CoordType patternBottomLeft = - pattern.vert[middleIndex].cP() - CoordType(xOffset, 0, 0); - std::vector patternTrianglePoints{ - patternCoord0, patternBottomRight, patternBottomLeft}; - CoordType pointOnPattern = - patternCoord0 + (patternBottomLeft - patternCoord0) ^ - (patternBottomRight - patternCoord0); - - for (VCGTriMesh::VertexType &v : tileInto.vert) { - const auto centralNodeColor = vcg::Color4(64, 64, 64, 255); - const bool isCentralNode = v.cC() == centralNodeColor; - if (isCentralNode) { - std::vector incidentVertices; - vcg::face::VFIterator vfi( - &v); // initialize the iterator tohe first face - vcg::face::Pos p(vfi.F(), &v); - vcg::face::VVOrderedStarFF(p, incidentVertices); - - const size_t vi = vcg::tri::Index(tileInto, v); - std::cout << "vertex " << vi << " has incident vertices:" << std::endl; - for (size_t f = 0; f < incidentVertices.size(); f++) { - // size_t f = 0; - std::cout << vcg::tri::Index(tileInto, incidentVertices[f]) - << std::endl; - - // Compute transformation matrix M - // vcg::Matrix44d M; - std::vector meshTrianglePoints{ - v.cP(), incidentVertices[f]->cP(), - f + 1 == incidentVertices.size() ? incidentVertices[0]->cP() - : incidentVertices[f + 1]->cP()}; - CoordType faceNormal = - ((meshTrianglePoints[1] - meshTrianglePoints[0]) ^ - (meshTrianglePoints[2] - meshTrianglePoints[0])) - .Normalize(); - CoordType pointOnTriMesh = - meshTrianglePoints[0] + - (meshTrianglePoints[1] - meshTrianglePoints[0]) ^ - (meshTrianglePoints[2] - meshTrianglePoints[0]); - vcg::Matrix44d M; - // vcg::ComputeRigidMatchMatrix(meshTrianglePoints, - // patternTrianglePoints, - // M); - vcg::Matrix44d A_prime; - A_prime[0][0] = meshTrianglePoints[0][0]; - A_prime[1][0] = meshTrianglePoints[0][1]; - A_prime[2][0] = meshTrianglePoints[0][2]; - A_prime[3][0] = 1; - A_prime[0][1] = meshTrianglePoints[1][0]; - A_prime[1][1] = meshTrianglePoints[1][1]; - A_prime[2][1] = meshTrianglePoints[1][2]; - A_prime[3][1] = 1; - A_prime[0][2] = meshTrianglePoints[2][0]; - A_prime[1][2] = meshTrianglePoints[2][1]; - A_prime[2][2] = meshTrianglePoints[2][2]; - A_prime[3][2] = 1; - A_prime[0][3] = pointOnTriMesh[0]; - A_prime[1][3] = pointOnTriMesh[1]; - A_prime[2][3] = pointOnTriMesh[2]; - A_prime[3][3] = 1; - vcg::Matrix44d A; - A[0][0] = patternTrianglePoints[0][0]; - A[1][0] = patternTrianglePoints[0][1]; - A[2][0] = patternTrianglePoints[0][2]; - A[3][0] = 1; - A[0][1] = patternTrianglePoints[1][0]; - A[1][1] = patternTrianglePoints[1][1]; - A[2][1] = patternTrianglePoints[1][2]; - A[3][1] = 1; - A[0][2] = patternTrianglePoints[2][0]; - A[1][2] = patternTrianglePoints[2][1]; - A[2][2] = patternTrianglePoints[2][2]; - A[3][2] = 1; - A[0][3] = pointOnPattern[0]; - A[1][3] = pointOnPattern[1]; - A[2][3] = pointOnPattern[2]; - A[3][3] = 1; - M = A_prime * vcg::Inverse(A); - - VCGEdgeMesh transformedPattern; - vcg::tri::Append::MeshCopy(transformedPattern, - pattern); - vcg::tri::UpdatePosition::Matrix(transformedPattern, M); - for (VertexType &v : transformedPattern.vert) { - v.N() = faceNormal; - } - - vcg::tri::Append::Mesh(*this, - transformedPattern); - } - } - } - - vcg::tri::UpdateTopology::VertexEdge(*this); - deleteDanglingVertices(); - deleteDanglingEdges(); - vcg::tri::Allocator::CompactEveryVector(*this); - - updateEigenEdgeAndVertices(); -} diff --git a/flatpattern.hpp b/flatpattern.hpp deleted file mode 100644 index 4b6a360..0000000 --- a/flatpattern.hpp +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef FLATPATTERN_HPP -#define FLATPATTERN_HPP - -#include "trianglepatterngeometry.hpp" - -class FlatPattern : public FlatPatternGeometry { -public: - FlatPattern(); - FlatPattern(const std::string &filename, bool addNormalsIfAbsent = true); - FlatPattern(const std::vector &numberOfNodesPerSlot, - const std::vector &edges); - - bool createHoneycombAtom(); - void copy(FlatPattern ©From); - - void tilePattern(VCGEdgeMesh &pattern, VCGTriMesh &tileInto); - void tilePattern(VCGEdgeMesh &pattern, VCGPolyMesh &tileInto, - const bool &shouldDeleteDanglingEdges); - - void createFan(const size_t &fanSize = 6); - - void deleteDanglingVertices( - vcg::tri::Allocator::PointerUpdater &pu); - void deleteDanglingVertices(); - void scale(const double &desiredBaseTriangleCentralEdgeSize); - - double getBaseTriangleHeight() const; - -private: - void deleteDanglingEdges(); - void removeDuplicateVertices(); - double baseTriangleHeight; -}; - -#endif // FLATPATTERN_HPP diff --git a/mesh.hpp b/mesh.hpp new file mode 100755 index 0000000..4e708cc --- /dev/null +++ b/mesh.hpp @@ -0,0 +1,20 @@ +#ifndef MESH_HPP +#define MESH_HPP + +#include + +class Mesh { + std::string label; + +public: + virtual ~Mesh() = default; + virtual bool load(const std::string &filePath) { return false; } + std::string getLabel() const; + void setLabel(const std::string &newLabel); +}; + +inline std::string Mesh::getLabel() const { return label; } + +inline void Mesh::setLabel(const std::string &newLabel) { label = newLabel; } + +#endif // MESH_HPP diff --git a/optimizationstructs.hpp b/optimizationstructs.hpp old mode 100644 new mode 100755 diff --git a/patternIO.cpp b/patternIO.cpp old mode 100644 new mode 100755 index 10bb10e..738d8a5 --- a/patternIO.cpp +++ b/patternIO.cpp @@ -1,116 +1,141 @@ #include "patternIO.hpp" +#include "trianglepatterngeometry.hpp" #include #include #include #include -PatternIO::PatternIO() {} +void PatternIO::write(std::ofstream &fileStream, const Pattern &pattern) { + fileStream << "p " << pattern.name << " " << pattern.edges.size(); + for (const vcg::Point2i &edge : pattern.edges) { + fileStream << " " << edge[0] << " " << edge[1]; + } +} +void PatternIO::write(std::ofstream &fileStream, + const std::vector &vertices) { + fileStream << "#Nodes" << '\n'; + for (vcg::Point3d node : vertices) { + fileStream << "n " << node.X() << " " << node.Y() << " " << node.Z() + << '\n'; + } + fileStream << "#Patterns" << '\n'; +} -void PatternIO::save(const std::string &filepath, +void PatternIO::exportPLY(const std::string &inputFilePath, + const int &startIndex, const int &endIndex) { + assert(std::filesystem::path(inputFilePath).extension() == ".patt"); + const std::string outputDir = + std::filesystem::path(inputFilePath) + .parent_path() + .append("PLYFiles") + .append(std::to_string(startIndex) + "_" + std::to_string(endIndex)) + .string(); + exportPLY(inputFilePath, outputDir, startIndex, endIndex); +} + +void PatternIO::exportPLY(const std::string &patternSetFilePath, + const std::string &outputDirectoryPath, + const int &startIndex, const int &endIndex) { + assert(std::filesystem::path(patternSetFilePath).extension() == ".patt"); + std::vector vertices; + std::vector patterns; + load(patternSetFilePath, vertices, patterns, startIndex, endIndex); + std::filesystem::create_directories(outputDirectoryPath); + + for (int patternIndex = 0; patternIndex < patterns.size(); patternIndex++) { + PatternGeometry p; + p.add(vertices, patterns[patternIndex].edges); + auto tiled = p.createTile(p); + p.savePly( + std::filesystem::path(outputDirectoryPath) + .append(std::to_string(patterns[patternIndex].name) + ".ply")); + tiled.savePly(std::filesystem::path(outputDirectoryPath) + .append("tiled_" + + std::to_string(patterns[patternIndex].name) + + ".ply")); + } +} + +void PatternIO::save(const std::string &filePath, const PatternSet &patternSet) { std::ofstream fileStream; - if (std::filesystem::exists(filepath)) { - fileStream.open(filepath, std::ios_base::app); + if (!std::filesystem::exists(filePath)) { + fileStream.open(filePath); + write(fileStream, patternSet.nodes); } else { - fileStream.open(filepath); - fileStream << "#Nodes" << std::endl; - for (vcg::Point2d node : patternSet.nodes) { - fileStream << "n " << node.X() << " " << node.Y() << std::endl; - } - fileStream << "#Patterns" << std::endl; + fileStream.open(filePath, std::ios_base::app); } for (const Pattern &pattern : patternSet.patterns) { - fileStream << "p " << pattern.labels.size() << " " << pattern.edges.size() - << " "; - for (size_t labelIndex = 0; labelIndex < pattern.labels.size() - 1; - labelIndex++) { - fileStream << pattern.labels[labelIndex] << " "; - } - fileStream << pattern.labels[pattern.labels.size() - 1] << " "; - - for (const vcg::Point2i &edge : pattern.edges) { - fileStream << " " << edge[0] << " " << edge[1] << " "; - } - fileStream << std::endl; + write(fileStream, pattern); + fileStream << '\n'; } + + fileStream.close(); } -void PatternIO::save(const std::string &filepath, const Pattern &pattern) { +void PatternIO::save(std::ofstream &fileStream, const Pattern &pattern) { + assert(fileStream.is_open()); + write(fileStream, pattern); + fileStream << '\n'; +} + +void PatternIO::save(const std::string &filePath, const Pattern &pattern) { + if (!std::filesystem::exists(filePath)) { + std::cerr << "File must already exist. The node information must already " + "be in the file." + << '\n'; + std::terminate(); + } std::ofstream fileStream; - if (std::filesystem::exists(filepath)) { - fileStream.open(filepath, std::ios_base::app); - } else { - fileStream.open(filepath); - fileStream << "#Nodes" << std::endl; - fileStream << "#Patterns" << std::endl; - } + fileStream.open(filePath, std::ios_base::app); - fileStream << "p " << pattern.labels.size() << " " << pattern.edges.size() - << " "; - for (size_t labelIndex = 0; labelIndex < pattern.labels.size() - 1; - labelIndex++) { - fileStream << pattern.labels[labelIndex] << " "; - } - fileStream << pattern.labels[pattern.labels.size() - 1] << " "; - - for (const vcg::Point2i &edge : pattern.edges) { - fileStream << " " << edge[0] << " " << edge[1] << " "; - } - fileStream << std::endl; + write(fileStream, pattern); + fileStream << '\n'; } -void PatternIO::load(const std::string &filepath, PatternSet &patternSet, - const std::vector &targetLabels) { +void PatternIO::load(const std::string &filepath, + std::vector &vertices, + std::vector &patterns, const int &startIndex, + const int &endIndex) { std::ifstream fileStream(filepath); std::string line; - std::vector sortedTargetPatternLabels(targetLabels); - std::sort(sortedTargetPatternLabels.begin(), sortedTargetPatternLabels.end()); - while (std::getline(fileStream, line)) { - std::cout << line << std::endl; + int patternIndex = 0; + while (std::getline(fileStream, line) && patternIndex <= endIndex) { + // std::cout << line << '\n'; std::istringstream iss(line); char lineID; iss >> lineID; if (lineID == 'n') { - double x, y; + double x, y, z = 0; iss >> x >> y; - std::cout << x << " " << y << std::endl; + // std::cout << x << " " << y << z << '\n'; + vertices.push_back(vcg::Point3d(x, y, z)); } else if (lineID == 'p') { + patternIndex++; + if (startIndex > patternIndex) { + continue; + } Pattern pattern; - size_t numberOfLabels, numberOfEdges; - iss >> numberOfLabels >> numberOfEdges; - std::cout << "NumberOfLabels:" << numberOfLabels << std::endl; - std::cout << "NumberOfEdges:" << numberOfEdges << std::endl; - std::vector patternLabels; - for (size_t labelIndex = 0; labelIndex < numberOfLabels; labelIndex++) { - size_t patternLabel; - iss >> patternLabel; - PatternLabel pl = static_cast(patternLabel); - std::cout << "Pattern label read:" << patternLabel << std::endl; - patternLabels.push_back(pl); - } - if (!targetLabels.empty()) { - std::sort(patternLabels.begin(), patternLabels.end()); - std::vector labelIntersection; - std::set_intersection(patternLabels.begin(), patternLabels.end(), - sortedTargetPatternLabels.begin(), - sortedTargetPatternLabels.end(), - labelIntersection.begin()); - if (!labelIntersection.empty()) { - pattern.labels = patternLabels; - } else { - continue; - } - } else { - pattern.labels = patternLabels; - } - for (size_t edgeIndex = 0; edgeIndex < numberOfEdges; edgeIndex++) { + iss >> pattern.name; + int numberOfEdges; + iss >> numberOfEdges; + for (int edgeIndex = 0; edgeIndex < numberOfEdges; edgeIndex++) { size_t ni0, ni1; iss >> ni0 >> ni1; vcg::Point2i edge(ni0, ni1); pattern.edges.push_back(edge); - std::cout << "Node indices read:" << ni0 << "," << ni1 << std::endl; } + patterns.push_back(pattern); + + // PatternGeometry fpg; + // fpg.add(vertices, pattern.edges); + // fpg.registerForDrawing(glm::vec3(1, 0, 0)); + // PatternGeometry tiledPattern = fpg.createTile(fpg); + // tiledPattern.deleteDanglingVertices(); + // tiledPattern.registerForDrawing(); + // polyscope::show(); + // polyscope::removeAllStructures(); } } } diff --git a/patternIO.hpp b/patternIO.hpp old mode 100644 new mode 100755 index daef17a..46a5b1b --- a/patternIO.hpp +++ b/patternIO.hpp @@ -3,38 +3,62 @@ #include #include +#include #include +#include #include -enum PatternLabel { - Valid = 0, - MultipleCC, - DanglingEdge, - IntersectingEdges, - ArticulationPoints -}; - +// enum PatternLabel { +// Valid = 0, +// MultipleCC, +// DanglingEdge, +// IntersectingEdges, +// ArticulationPoints +//}; +namespace PatternIO { +using PatternName = int; struct Pattern { std::vector edges; - std::vector labels; + PatternName name{-1}; + + bool operator==(const Pattern &p) const { return name == p.name; } +}; +struct PatternHashFunction { + std::size_t operator()(const Pattern &p) const { + return std::hash()(p.name); + } }; /* * A set of planar patterns using the same nodes * */ struct PatternSet { - std::vector nodes; + std::vector nodes; + std::vector patterns; }; -class PatternIO { +void save(const std::string &filePath, const Pattern &pattern); +void save(const std::string &filePath, const PatternSet &patterns); +void load(const std::string &filePath, PatternSet &patternSet); +void save(const std::string &filePath, + const std::vector &vertices); +void write(std::ofstream &fileStream, const Pattern &pattern); +void write(std::ofstream &fileStream, + const std::vector &vertices); +void exportPLY(const std::string &patternSetFilePath, + const std::string &outputDirectoryPath, const int &startIndex, + const int &endIndex); +void exportPLY(const std::string &outputDirectoryPath, + const std::string &patternSetFilePath, + const PatternName &patternToExport); +void save(std::ofstream &fileStream, const Pattern &pattern); +void load(const std::string &filepath, std::vector &vertices, + std::vector &patterns, const int &startIndex, + const int &endIndex); +void exportPLY(const std::string &inputFilePath, const int &startIndex, + const int &indexStep); -public: - PatternIO(); - static void save(const std::string &filepath, const Pattern &pattern); - static void save(const std::string &filepath, const PatternSet &patterns); - static void load(const std::string &filepath, PatternSet &patternSet, - const std::vector &targetLabels = {}); -}; +} // namespace PatternIO #endif // PATTERNEXPORTER_HPP diff --git a/polymesh.hpp b/polymesh.hpp old mode 100644 new mode 100755 index 91256d8..f5cda8d --- a/polymesh.hpp +++ b/polymesh.hpp @@ -1,9 +1,9 @@ #ifndef POLYMESH_HPP #define POLYMESH_HPP +#include "mesh.hpp" #include "vcg/complex/complex.h" #include #include -//#include class PFace; class PVertex; @@ -37,13 +37,18 @@ class PFace > {}; class VCGPolyMesh - : public vcg::tri::TriMesh, // the vector of vertices - std::vector // the vector of faces - > { + : public vcg::tri::TriMesh, std::vector>, + public Mesh { public: - void loadFromPlyFile(const std::string &filename) { - vcg::tri::io::ImporterOBJ::Info info; - vcg::tri::io::ImporterOBJ::Open(*this, filename.c_str(), info); + virtual bool load(const std::string &filename) override { + int mask; + vcg::tri::io::Importer::LoadMask(filename.c_str(), mask); + int error = vcg::tri::io::Importer::Open( + *this, filename.c_str(), mask); + if (error != 0) { + return false; + } + // vcg::tri::io::ImporterOBJ::Open(); // unsigned int mask = 0; // mask |= nanoply::NanoPlyWrapper::IO_VERTCOORD; // mask |= nanoply::NanoPlyWrapper::IO_VERTNORMAL; @@ -58,7 +63,13 @@ public: vcg::tri::UpdateTopology::FaceFace(*this); // vcg::tri::UpdateTopology::VertexFace(*this); vcg::tri::UpdateNormal::PerVertexNormalized(*this); + return true; } +#ifdef POLYSCOPE_DEFINED + void registerForDrawing(){ + + } +#endif }; #endif // POLYMESH_HPP diff --git a/simulationhistoryplotter.hpp b/simulationhistoryplotter.hpp old mode 100644 new mode 100755 diff --git a/simulationresult.hpp b/simulationresult.hpp old mode 100644 new mode 100755 index f1a7533..85968a1 --- a/simulationresult.hpp +++ b/simulationresult.hpp @@ -109,6 +109,7 @@ public: return json.dump(); } bool load(const std::string &jsonFilename) { + const bool beVerbose = false; if (std::filesystem::path(jsonFilename).extension() != ".json") { std::cerr << "A json file is expected as input. The given file has the " "following extension:" @@ -124,7 +125,9 @@ public: return false; } - std::cout << "Loading json file:" << jsonFilename << std::endl; + if (beVerbose) { + std::cout << "Loading json file:" << jsonFilename << std::endl; + } nlohmann::json json; std::ifstream ifs(jsonFilename); ifs >> json; @@ -136,7 +139,7 @@ public: std::filesystem::path( std::filesystem::path(jsonFilename).parent_path()) .append(relativeFilepath); - pMesh->loadPly(meshFilepath.string()); + pMesh->load(meshFilepath.string()); pMesh->setLabel( json[jsonLabels.meshLabel]); // FIXME: This should be exported using // nanoply but nanoply might not be able @@ -148,9 +151,11 @@ public: // auto conV = json[jsonLabels.constrainedVertices] .get>>(); - std::cout << "Loaded constrained vertices. Number of constrained " - "vertices found:" - << constrainedVertices.size() << std::endl; + if (beVerbose) { + std::cout << "Loaded constrained vertices. Number of constrained " + "vertices found:" + << constrainedVertices.size() << std::endl; + } } if (json.contains(jsonLabels.nodalForces)) { @@ -159,8 +164,10 @@ public: for (const auto &forces : f) { nodalExternalForces[forces.first] = Vector6d(forces.second); } - std::cout << "Loaded forces. Number of forces found:" - << nodalExternalForces.size() << std::endl; + if (beVerbose) { + std::cout << "Loaded forces. Number of forces found:" + << nodalExternalForces.size() << std::endl; + } } if (json.contains(jsonLabels.label)) { @@ -389,7 +396,8 @@ struct SimulationResults { polyscope::removeCurveNetwork(getLabel()); } void registerForDrawing( - const std::optional &desiredColor = std::nullopt) const { + const std::optional &desiredColor = std::nullopt, + const bool &shouldEnable = true) const { polyscope::options::groundPlaneEnabled = false; polyscope::view::upDir = polyscope::view::UpDir::ZUp; const std::string branchName = "Branch:Polyscope"; @@ -405,10 +413,10 @@ struct SimulationResults { // mesh->getEigenEdges()); const std::shared_ptr &mesh = job->pMesh; - auto polyscopeHandle_deformedEdmeMesh = - polyscope::registerCurveNetwork(getLabel(), mesh->getEigenVertices(), - mesh->getEigenEdges()) - ->setRadius(0.002, true); + auto polyscopeHandle_deformedEdmeMesh = polyscope::registerCurveNetwork( + getLabel(), mesh->getEigenVertices(), mesh->getEigenEdges()); + polyscopeHandle_deformedEdmeMesh->setEnabled(shouldEnable); + polyscopeHandle_deformedEdmeMesh->setRadius(0.002, true); if (desiredColor.has_value()) { polyscopeHandle_deformedEdmeMesh->setColor(desiredColor.value()); } diff --git a/simulationresult.hpp.orig b/simulationresult.hpp.orig old mode 100644 new mode 100755 diff --git a/topologyenumerator.cpp b/topologyenumerator.cpp index 01a2d29..e69de29 100644 --- a/topologyenumerator.cpp +++ b/topologyenumerator.cpp @@ -1,609 +0,0 @@ -#include "topologyenumerator.hpp" -#include -#include -#include -#include -#include - -const bool debugIsOn{false}; -const bool exportArticulationPointsPatterns{false}; -const bool savePlyFiles{true}; - -// size_t binomialCoefficient(size_t n, size_t m) { -// assert(n > m); -// return tgamma(n + 1) / (tgamma(m + 1) * tgamma(n - m + 1)); -//} - -// void TopologyEnumerator::createLabelMesh( -// const std::vector vertices, -// const std::filesystem::path &savePath) const { -// const std::string allOnes(patternTopology.getNumberOfPossibleEdges(), '1'); -// const std::vector allEdges = -// TrianglePatternTopology::convertToEdges(allOnes, vertices.size()); -// TrianglePatternGeometry labelMesh; -// std::vector labelVertices(allEdges.size()); -// for (size_t edgeIndex = 0; edgeIndex < allEdges.size(); edgeIndex++) { -// const vcg::Point3d edgeMidpoint = -// (vertices[allEdges[edgeIndex][0]] + vertices[allEdges[edgeIndex][1]]) -// / 2; -// labelVertices[edgeIndex] = edgeMidpoint; -// } -// labelMesh.set(labelVertices); -// labelMesh.savePly(std::filesystem::path(savePath) -// .append(std::string("labelMesh.ply")) -// .string()); -//} - -size_t TopologyEnumerator::getEdgeIndex(size_t ni0, size_t ni1) const { - if (ni1 <= ni0) { - std::swap(ni0, ni1); - } - assert(ni1 > ni0); - const size_t &n = numberOfNodes; - return (n * (n - 1) / 2) - (n - ni0) * ((n - ni0) - 1) / 2 + ni1 - ni0 - 1; -} - -TopologyEnumerator::TopologyEnumerator() {} - -void TopologyEnumerator::computeValidPatterns( - const std::vector &reducedNumberOfNodesPerSlot) { - assert(reducedNumberOfNodesPerSlot.size() == 5); - assert(reducedNumberOfNodesPerSlot[0] == 0 || - reducedNumberOfNodesPerSlot[0] == 1); - assert(reducedNumberOfNodesPerSlot[1] == 0 || - reducedNumberOfNodesPerSlot[1] == 1); - std::vector numberOfNodesPerSlot{ - reducedNumberOfNodesPerSlot[0], reducedNumberOfNodesPerSlot[1], - reducedNumberOfNodesPerSlot[1], reducedNumberOfNodesPerSlot[2], - reducedNumberOfNodesPerSlot[3], reducedNumberOfNodesPerSlot[2], - reducedNumberOfNodesPerSlot[4]}; - // Generate an edge mesh wih all possible edges - numberOfNodes = std::accumulate(numberOfNodesPerSlot.begin(), - numberOfNodesPerSlot.end(), 0); - const size_t numberOfAllPossibleEdges = - numberOfNodes * (numberOfNodes - 1) / 2; - - std::vector allPossibleEdges(numberOfAllPossibleEdges); - const int &n = numberOfNodes; - for (size_t edgeIndex = 0; edgeIndex < numberOfAllPossibleEdges; - edgeIndex++) { - const int ni0 = - n - 2 - - std::floor(std::sqrt(-8 * edgeIndex + 4 * n * (n - 1) - 7) / 2.0 - 0.5); - const int ni1 = - edgeIndex + ni0 + 1 - n * (n - 1) / 2 + (n - ni0) * ((n - ni0) - 1) / 2; - allPossibleEdges[edgeIndex] = vcg::Point2i(ni0, ni1); - } - FlatPatternGeometry patternGeometryAllEdges; - patternGeometryAllEdges.add(numberOfNodesPerSlot, allPossibleEdges); - // Create Results path - auto resultPath = - // std::filesystem::path("/home/iason/Documents/PhD/Research/Enumerating\\ - // " - // "2d\\ connections\\ of\\ nodes"); - std::filesystem::current_path() - .parent_path() - .parent_path() - .parent_path() - .parent_path(); - assert(std::filesystem::exists(resultPath)); - - auto allResultsPath = resultPath.append("Results"); - std::filesystem::create_directory(allResultsPath); - std::string setupString; - // for (size_t numberOfNodes : reducedNumberOfNodesPerSlot) { - for (size_t numberOfNodesPerSlotIndex = 0; - numberOfNodesPerSlotIndex < reducedNumberOfNodesPerSlot.size(); - numberOfNodesPerSlotIndex++) { - std::string elemID; - if (numberOfNodesPerSlotIndex == 0 || numberOfNodesPerSlotIndex == 1) { - elemID = "v"; - } else if (numberOfNodesPerSlotIndex == 2 || - numberOfNodesPerSlotIndex == 3) { - elemID = "e"; - } else { - elemID = "c"; - } - setupString += - std::to_string(reducedNumberOfNodesPerSlot[numberOfNodesPerSlotIndex]) + - elemID + "_"; - } - setupString += std::to_string(FlatPatternGeometry().getFanSize()) + "fan"; - if (debugIsOn) { - setupString += "_debug"; - } - auto resultsPath = std::filesystem::path(allResultsPath).append(setupString); - // std::filesystem::remove_all(resultsPath); // delete previous results - std::filesystem::create_directory(resultsPath); - if (debugIsOn) { - patternGeometryAllEdges.savePly(std::filesystem::path(resultsPath) - .append("allPossibleEdges.ply") - .string()); - } - // statistics.numberOfPossibleEdges = numberOfAllPossibleEdges; - - std::vector validEdges = - getValidEdges(numberOfNodesPerSlot, resultsPath, patternGeometryAllEdges, - allPossibleEdges); - FlatPatternGeometry patternAllValidEdges; - patternAllValidEdges.add(patternGeometryAllEdges.getVertices(), validEdges); - if (debugIsOn) { - // Export all valid edges in a ply - patternAllValidEdges.savePly( - std::filesystem::path(resultsPath).append("allValidEdges.ply").string()); - } - // statistics.numberOfValidEdges = validEdges.size(); - - // Find pairs of intersecting edges - std::unordered_map> intersectingEdges = - patternAllValidEdges.getIntersectingEdges( - statistics.numberOfIntersectingEdgePairs); - if (debugIsOn) { - auto intersectingEdgesPath = std::filesystem::path(resultsPath) - .append("All_intersecting_edge_pairs"); - std::filesystem::create_directory(intersectingEdgesPath); - // Export intersecting pairs in ply files - for (auto mapIt = intersectingEdges.begin(); - mapIt != intersectingEdges.end(); mapIt++) { - for (auto setIt = mapIt->second.begin(); setIt != mapIt->second.end(); - setIt++) { - FlatPatternGeometry intersectingEdgePair; - const size_t ei0 = mapIt->first; - const size_t ei1 = *setIt; - vcg::tri::Allocator::AddEdge( - intersectingEdgePair, - patternGeometryAllEdges.getVertices()[validEdges[ei0][0]], - patternGeometryAllEdges.getVertices()[validEdges[ei0][1]]); - vcg::tri::Allocator::AddEdge( - intersectingEdgePair, - patternGeometryAllEdges.getVertices()[validEdges[ei1][0]], - patternGeometryAllEdges.getVertices()[validEdges[ei1][1]]); - intersectingEdgePair.savePly( - std::filesystem::path(intersectingEdgesPath) - .append(std::to_string(mapIt->first) + "_" + - std::to_string(*setIt) + ".ply") - .string()); - } - } - } - - // assert(validEdges.size() == allPossibleEdges.size() - - // coincideEdges.size() - - // duplicateEdges.size()); - - PatternSet patternSet; - const std::vector nodes = patternGeometryAllEdges.getVertices(); - const size_t numberOfNodes = nodes.size(); - patternSet.nodes.resize(numberOfNodes); - for (size_t nodeIndex = 0; nodeIndex < numberOfNodes; nodeIndex++) { - patternSet.nodes[nodeIndex] = - vcg::Point2d(nodes[nodeIndex][0], nodes[nodeIndex][1]); - } - if (std::filesystem::exists(std::filesystem::path(resultsPath) - .append("patterns.patt") - .string())) { - std::filesystem::remove( - std::filesystem::path(resultsPath).append("patterns.patt")); - } - for (size_t numberOfEdges = 2; numberOfEdges < validEdges.size(); - numberOfEdges++) { - // for (size_t numberOfEdges = 1; numberOfEdges < 3; numberOfEdges++) { - std::cout << "Computing " + setupString << " with " << numberOfEdges - << " edges." << std::endl; - auto perEdgeResultPath = std::filesystem::path(resultsPath) - .append(std::to_string(numberOfEdges)); - // if (std::filesystem::exists(perEdgeResultPath)) { - // continue; - // } - std::filesystem::create_directory(perEdgeResultPath); - computeValidPatterns(numberOfNodesPerSlot, numberOfEdges, perEdgeResultPath, - patternGeometryAllEdges.getVertices(), - intersectingEdges, validEdges, patternSet); - // statistics.print(setupString, perEdgeResultPath); - PatternIO::save( - std::filesystem::path(resultsPath).append("patterns.patt").string(), - patternSet); - } -} - -void TopologyEnumerator::computeEdgeNodes( - const std::vector &numberOfNodesPerSlot, - std::vector &nodesEdge0, std::vector &nodesEdge1, - std::vector &nodesEdge2) { - // Create vectors holding the node indices of each pattern node of each - // triangle edge - size_t nodeIndex = 0; - if (numberOfNodesPerSlot[0] != 0) { - nodesEdge0.push_back(nodeIndex++); - } - if (numberOfNodesPerSlot[1] != 0) - nodesEdge1.push_back(nodeIndex++); - if (numberOfNodesPerSlot[2] != 0) - nodesEdge2.push_back(nodeIndex++); - - if (numberOfNodesPerSlot[3] != 0) { - for (size_t edgeNodeIndex = 0; edgeNodeIndex < numberOfNodesPerSlot[3]; - edgeNodeIndex++) { - nodesEdge0.push_back(nodeIndex++); - } - } - if (numberOfNodesPerSlot[4] != 0) { - for (size_t edgeNodeIndex = 0; edgeNodeIndex < numberOfNodesPerSlot[4]; - edgeNodeIndex++) { - nodesEdge1.push_back(nodeIndex++); - } - } - - if (numberOfNodesPerSlot[5] != 0) { - for (size_t edgeNodeIndex = 0; edgeNodeIndex < numberOfNodesPerSlot[5]; - edgeNodeIndex++) { - nodesEdge2.push_back(nodeIndex++); - } - } - if (numberOfNodesPerSlot[1] != 0) { - assert(numberOfNodesPerSlot[2]); - nodesEdge0.push_back(1); - nodesEdge1.push_back(2); - } - - if (numberOfNodesPerSlot[0] != 0) { - nodesEdge2.push_back(0); - } -} - -std::unordered_set TopologyEnumerator::computeCoincideEdges( - const std::vector &numberOfNodesPerSlot) { - /* - * A coincide edge is defined as an edge connection between two nodes that lay - * on a triangle edge and which have another node in between - * */ - std::vector nodesEdge0; // left edge - std::vector nodesEdge1; // bottom edge - std::vector nodesEdge2; // right edge - computeEdgeNodes(numberOfNodesPerSlot, nodesEdge0, nodesEdge1, nodesEdge2); - - std::vector coincideEdges0 = getCoincideEdges(nodesEdge0); - std::vector coincideEdges1 = getCoincideEdges(nodesEdge1); - std::vector coincideEdges2 = getCoincideEdges(nodesEdge2); - std::unordered_set coincideEdges{coincideEdges0.begin(), - coincideEdges0.end()}; - std::copy(coincideEdges1.begin(), coincideEdges1.end(), - std::inserter(coincideEdges, coincideEdges.end())); - std::copy(coincideEdges2.begin(), coincideEdges2.end(), - std::inserter(coincideEdges, coincideEdges.end())); - - if (numberOfNodesPerSlot[0] && numberOfNodesPerSlot[1]) { - coincideEdges.insert(getEdgeIndex(0, 2)); - } - - if (numberOfNodesPerSlot[0] && numberOfNodesPerSlot[2]) { - assert(numberOfNodesPerSlot[1]); - coincideEdges.insert(getEdgeIndex(0, 3)); - } - - return coincideEdges; -} - -std::unordered_set TopologyEnumerator::computeDuplicateEdges( - const std::vector &numberOfNodesPerSlot) { - /* - * A duplicate edges are all edges the "right" edge since due to rotational - * symmetry "left" edge=="right" edge - * */ - std::unordered_set duplicateEdges; - std::vector nodesEdge0; // left edge - std::vector nodesEdge1; // bottom edge - std::vector nodesEdge2; // right edge - computeEdgeNodes(numberOfNodesPerSlot, nodesEdge0, nodesEdge1, nodesEdge2); - if (numberOfNodesPerSlot[5]) { - for (size_t edge2NodeIndex = 0; edge2NodeIndex < nodesEdge2.size() - 1; - edge2NodeIndex++) { - const size_t nodeIndex = nodesEdge2[edge2NodeIndex]; - const size_t nextNodeIndex = nodesEdge2[edge2NodeIndex + 1]; - duplicateEdges.insert(getEdgeIndex(nodeIndex, nextNodeIndex)); - } - } - - return duplicateEdges; -} - -std::vector TopologyEnumerator::getValidEdges( - const std::vector &numberOfNodesPerSlot, - const std::filesystem::path &resultsPath, - const FlatPatternGeometry &patternGeometryAllEdges, - const std::vector &allPossibleEdges) { - - std::unordered_set coincideEdges = - computeCoincideEdges(numberOfNodesPerSlot); - // Export each coincide edge into a ply file - if (!coincideEdges.empty() && debugIsOn) { - auto coincideEdgesPath = - std::filesystem::path(resultsPath).append("Coincide_edges"); - std::filesystem::create_directories(coincideEdgesPath); - for (auto coincideEdgeIndex : coincideEdges) { - FlatPatternGeometry::EdgeType e = - patternGeometryAllEdges.edge[coincideEdgeIndex]; - FlatPatternGeometry singleEdgeMesh; - vcg::Point3d p0 = e.cP(0); - vcg::Point3d p1 = e.cP(1); - std::vector edgeVertices; - edgeVertices.push_back(p0); - edgeVertices.push_back(p1); - singleEdgeMesh.add(edgeVertices); - singleEdgeMesh.add(std::vector{vcg::Point2i{0, 1}}); - singleEdgeMesh.savePly(std::filesystem::path(coincideEdgesPath) - .append(std::to_string(coincideEdgeIndex)) - .string() + - ".ply"); - } - } - statistics.numberOfCoincideEdges = coincideEdges.size(); - - // Compute duplicate edges - std::unordered_set duplicateEdges = - computeDuplicateEdges(numberOfNodesPerSlot); - if (!duplicateEdges.empty() && debugIsOn) { - // Export duplicate edges in a single ply file - auto duplicateEdgesPath = - std::filesystem::path(resultsPath).append("duplicate"); - std::filesystem::create_directory(duplicateEdgesPath); - FlatPatternGeometry patternDuplicateEdges; - for (auto duplicateEdgeIndex : duplicateEdges) { - FlatPatternGeometry::EdgeType e = - patternGeometryAllEdges.edge[duplicateEdgeIndex]; - vcg::Point3d p0 = e.cP(0); - vcg::Point3d p1 = e.cP(1); - vcg::tri::Allocator::AddEdge( - patternDuplicateEdges, p0, p1); - } - patternDuplicateEdges.savePly( - std::filesystem::path(duplicateEdgesPath).append("duplicateEdges.ply").string()); - } - statistics.numberOfDuplicateEdges = duplicateEdges.size(); - - // Create the set of all possible edges without coincide and duplicate edges - std::vector validEdges; - for (size_t edgeIndex = 0; edgeIndex < allPossibleEdges.size(); edgeIndex++) { - if (coincideEdges.count(edgeIndex) == 0 && - duplicateEdges.count(edgeIndex) == 0) { - validEdges.push_back(allPossibleEdges[edgeIndex]); - } - } - - return validEdges; -} - -void TopologyEnumerator::computeValidPatterns( - const std::vector &numberOfNodesPerSlot, - const size_t &numberOfDesiredEdges, - const std::filesystem::path &resultsPath, - const std::vector &allVertices, - const std::unordered_map> - &intersectingEdges, - const std::vector &validEdges, PatternSet &patternsSet) { - assert(numberOfNodesPerSlot.size() == 7); - - // Iterate over all patterns which have numberOfDesiredEdges edges from - // from the validEdges Identify patterns that contain dangling edges - const bool enoughValidEdgesExist = validEdges.size() >= numberOfDesiredEdges; - if (!enoughValidEdgesExist) { - std::filesystem::remove_all(resultsPath); // delete previous results folder - return; - } - assert(enoughValidEdgesExist); - - // Create pattern result paths - auto validPatternsPath = std::filesystem::path(resultsPath).append("Valid"); - std::filesystem::create_directory(validPatternsPath); - - const size_t numberOfPatterns = FlatPatternGeometry::binomialCoefficient( - validEdges.size(), numberOfDesiredEdges); - statistics.numberOfPatterns = numberOfPatterns; - - // Initialize pattern binary representation - std::string patternBinaryRepresentation; - patternBinaryRepresentation = std::string(numberOfDesiredEdges, '1'); - patternBinaryRepresentation += - std::string(validEdges.size() - numberOfDesiredEdges, '0'); - std::sort(patternBinaryRepresentation.begin(), - patternBinaryRepresentation.end()); - size_t patternIndex = 0; - do { - patternIndex++; - const std::string patternName = std::to_string(patternIndex); - // std::cout << "Pattern name:" + patternBinaryRepresentation << - // std::endl; isValidPattern(patternBinaryRepresentation, validEdges, - // numberOfDesiredEdges); - // Create the geometry of the pattern - // Compute the pattern edges from the binary representation - std::vector patternEdges(numberOfDesiredEdges); - size_t patternEdgeIndex = 0; - for (size_t validEdgeIndex = 0; - validEdgeIndex < patternBinaryRepresentation.size(); - validEdgeIndex++) { - if (patternBinaryRepresentation[validEdgeIndex] == '1') { - assert(patternEdgeIndex < numberOfDesiredEdges); - patternEdges[patternEdgeIndex++] = validEdges[validEdgeIndex]; - } - } - Pattern pattern; - pattern.edges = patternEdges; - - FlatPatternGeometry patternGeometry; - patternGeometry.add(allVertices, patternEdges); - - // Check if pattern contains intersecting edges - const bool patternContainsIntersectingEdges = - patternGeometry.hasIntersectingEdges(patternBinaryRepresentation, - intersectingEdges); - // Export the tiled ply file if it contains intersecting edges - if (patternContainsIntersectingEdges) { - // create the tiled geometry of the pattern - statistics.numberOfPatternsWithIntersectingEdges++; - if (debugIsOn) { - if (savePlyFiles) { - FlatPatternGeometry tiledPatternGeometry = - FlatPatternGeometry::createTile(patternGeometry); - auto intersectingPatternsPath = - std::filesystem::path(resultsPath).append("Intersecting"); - std::filesystem::create_directory(intersectingPatternsPath); - patternGeometry.savePly( - std::filesystem::path(intersectingPatternsPath) - .append(patternName) - .string() + - ".ply"); - tiledPatternGeometry.savePly( - std::filesystem::path(intersectingPatternsPath) - .append(patternName + "_tiled") - .string() + - ".ply"); - } - pattern.labels.push_back(PatternLabel::IntersectingEdges); - } else { - continue; // should be uncommented in order to improve performance - } - } - - // Compute the tiled valence - const bool tiledPatternHasDanglingEdges = patternGeometry.hasDanglingEdges( - numberOfNodesPerSlot); // marks the nodes with valence>=1 - // Create the tiled geometry of the pattern - const bool hasFloatingComponents = - !patternGeometry.isFullyConnectedWhenTiled(); - FlatPatternTopology topology(numberOfNodesPerSlot, patternEdges); - const bool hasArticulationPoints = topology.containsArticulationPoints(); - FlatPatternGeometry tiledPatternGeometry = - FlatPatternGeometry::createTile( - patternGeometry); // the marked nodes of hasDanglingEdges are - // duplicated here - // Check dangling edges with vcg method - // const bool vcg_tiledPatternHasDangling = - // tiledPatternGeometry.hasUntiledDanglingEdges(); - if (tiledPatternHasDanglingEdges /*&& !hasFloatingComponents && - !hasArticulationPoints*/) { - statistics.numberOfPatternsWithADanglingEdgeOrNode++; - if (debugIsOn) { - if (savePlyFiles) { - auto danglingEdgesPath = - std::filesystem::path(resultsPath).append("Dangling"); - std::filesystem::create_directory(danglingEdgesPath); - patternGeometry.savePly(std::filesystem::path(danglingEdgesPath) - .append(patternName) - .string() + - ".ply"); - tiledPatternGeometry.savePly(std::filesystem::path(danglingEdgesPath) - .append(patternName + "_tiled") - .string() + - ".ply"); - } - pattern.labels.push_back(PatternLabel::DanglingEdge); - } else { - continue; - } - } - - if (hasFloatingComponents /*&& !hasArticulationPoints && - !tiledPatternHasDanglingEdges*/) { - statistics.numberOfPatternsWithMoreThanASingleCC++; - if (debugIsOn) { - if (savePlyFiles) { - auto moreThanOneCCPath = - std::filesystem::path(resultsPath).append("MoreThanOneCC"); - std::filesystem::create_directory(moreThanOneCCPath); - patternGeometry.savePly(std::filesystem::path(moreThanOneCCPath) - .append(patternName) - .string() + - ".ply"); - tiledPatternGeometry.savePly(std::filesystem::path(moreThanOneCCPath) - .append(patternName + "_tiled") - .string() + - ".ply"); - } - pattern.labels.push_back(PatternLabel::MultipleCC); - } else { - continue; - } - } - - if (hasArticulationPoints /*&& !hasFloatingComponents && - !tiledPatternHasDanglingEdges*/) { - statistics.numberOfPatternsWithArticulationPoints++; - if (exportArticulationPointsPatterns || debugIsOn) { - if (savePlyFiles) { - auto articulationPointsPath = - std::filesystem::path(resultsPath).append("ArticulationPoints"); - std::filesystem::create_directory(articulationPointsPath); - patternGeometry.savePly(std::filesystem::path(articulationPointsPath) - .append(patternName) - .string() + - ".ply"); - tiledPatternGeometry.savePly( - std::filesystem::path(articulationPointsPath) - .append(patternName + "_tiled") - .string() + - ".ply"); - - // std::cout << "Pattern:" << patternName << std::endl; - } - pattern.labels.push_back(PatternLabel::ArticulationPoints); - } else { - continue; - } - } - - const bool isValidPattern = - !patternContainsIntersectingEdges && !tiledPatternHasDanglingEdges && - !hasFloatingComponents && !hasArticulationPoints; - if (isValidPattern) { - statistics.numberOfValidPatterns++; - if (savePlyFiles) { - // if (numberOfDesiredEdges == 4) { - // std::cout << "Saving:" - // << std::filesystem::path(validPatternsPath) - // .append(patternName) - // .string() + - // ".ply" - // << std::endl; - // } - patternGeometry.savePly(std::filesystem::path(validPatternsPath) - .append(patternName) - .string() + - ".ply"); - tiledPatternGeometry.savePly(std::filesystem::path(validPatternsPath) - .append(patternName + "_tiled") - .string() + - ".ply"); - } - pattern.labels.push_back(PatternLabel::Valid); - } - - assert(!pattern.labels.empty()); - patternsSet.patterns.push_back(pattern); - // assert(vcg_tiledPatternHasDangling == tiledPatternHasDanglingEdges); - } while (std::next_permutation(patternBinaryRepresentation.begin(), - patternBinaryRepresentation.end())); -} - -std::vector TopologyEnumerator::getCoincideEdges( - const std::vector &edgeNodeIndices) const { - std::vector coincideEdges; - if (edgeNodeIndices.size() < 3) - return coincideEdges; - for (size_t edgeNodeIndex = 0; edgeNodeIndex < edgeNodeIndices.size() - 2; - edgeNodeIndex++) { - const size_t &firstNodeIndex = edgeNodeIndices[edgeNodeIndex]; - for (size_t secondEdgeNodeIndex = edgeNodeIndex + 2; - secondEdgeNodeIndex < edgeNodeIndices.size(); secondEdgeNodeIndex++) { - const size_t &secondNodeIndex = edgeNodeIndices[secondEdgeNodeIndex]; - coincideEdges.push_back(getEdgeIndex(firstNodeIndex, secondNodeIndex)); - } - } - return coincideEdges; -} - -bool TopologyEnumerator::isValidPattern( - const std::string &patternBinaryRepresentation, - const std::vector &validEdges, - const size_t &numberOfDesiredEdges) const { - return true; -} diff --git a/topologyenumerator.hpp b/topologyenumerator.hpp old mode 100644 new mode 100755 index 1b3202b..058d70d --- a/topologyenumerator.hpp +++ b/topologyenumerator.hpp @@ -157,7 +157,7 @@ private: std::vector getValidEdges(const std::vector &numberOfNodesPerSlot, const std::filesystem::path &resultsPath, - const FlatPatternGeometry &patternGeometryAllEdges, + const PatternGeometry &patternGeometryAllEdges, const std::vector &allPossibleEdges); std::unordered_set computeDuplicateEdges(); std::unordered_set @@ -175,6 +175,7 @@ private: const std::vector &vertices, const std::unordered_map> &intersectingEdges, - const std::vector &validEdges, PatternSet &patternsSet); + const std::vector &validEdges); +}ges, PatternSet &patternsSet); }; -#endif // TOPOLOGYENUMERATOR_HPP +# \ No newline at end of file diff --git a/trianglepatterngeometry.cpp b/trianglepatterngeometry.cpp old mode 100644 new mode 100755 index e629c0f..7058c66 --- a/trianglepatterngeometry.cpp +++ b/trianglepatterngeometry.cpp @@ -8,10 +8,10 @@ #include #include -size_t FlatPatternGeometry::computeTiledValence( +size_t PatternGeometry::computeTiledValence( const size_t &nodeIndex, const std::vector &numberOfNodesPerSlot) const { - std::vector connectedEdges; + std::vector connectedEdges; vcg::edge::VEStarVE(&vert[nodeIndex], connectedEdges); const size_t nodeValence = connectedEdges.size(); assert(nodeSlot.count(nodeIndex) != 0); @@ -25,8 +25,7 @@ size_t FlatPatternGeometry::computeTiledValence( } else { correspondingNodeIndex = nodeIndex - 1; } - std::vector - connectedEdgesCorrespondingNode; + std::vector connectedEdgesCorrespondingNode; vcg::edge::VEStarVE(&vert[correspondingNodeIndex], connectedEdgesCorrespondingNode); size_t correspondingNodeValence = connectedEdgesCorrespondingNode.size(); @@ -55,8 +54,7 @@ size_t FlatPatternGeometry::computeTiledValence( 0); } assert(correspondingNodeIndex < vn); - std::vector - connectedEdgesCorrespondingNode; + std::vector connectedEdgesCorrespondingNode; vcg::edge::VEStarVE(&vert[correspondingNodeIndex], connectedEdgesCorrespondingNode); size_t correspondingNodeValence = connectedEdgesCorrespondingNode.size(); @@ -72,15 +70,13 @@ size_t FlatPatternGeometry::computeTiledValence( return 0; } -size_t FlatPatternGeometry::getFanSize() const { return fanSize; } +size_t PatternGeometry::getFanSize() const { return fanSize; } -double FlatPatternGeometry::getTriangleEdgeSize() const { - return triangleEdgeSize; -} +double PatternGeometry::getTriangleEdgeSize() const { return triangleEdgeSize; } -FlatPatternGeometry::FlatPatternGeometry() {} +PatternGeometry::PatternGeometry() {} -std::vector FlatPatternGeometry::getVertices() const { +std::vector PatternGeometry::getVertices() const { std::vector verts(VN()); for (size_t vi = 0; vi < VN(); vi++) { verts[vi] = vert[vi].cP(); @@ -88,73 +84,70 @@ std::vector FlatPatternGeometry::getVertices() const { return verts; } -FlatPatternGeometry -FlatPatternGeometry::createTile(FlatPatternGeometry &pattern) { +PatternGeometry PatternGeometry::createTile(PatternGeometry &pattern) { - const size_t fanSize = FlatPatternGeometry().getFanSize(); - FlatPatternGeometry fan(createFan(pattern)); - FlatPatternGeometry tile(fan); + const size_t fanSize = PatternGeometry().getFanSize(); + PatternGeometry fan(createFan(pattern)); + PatternGeometry tile(fan); if (fanSize % 2 == 1) { vcg::Matrix44d R; auto rotationAxis = vcg::Point3d(0, 0, 1); R.SetRotateDeg(180, rotationAxis); - vcg::tri::UpdatePosition::Matrix(fan, R); + vcg::tri::UpdatePosition::Matrix(fan, R); } vcg::Matrix44d T; const double centerAngle = 2 * M_PI / fanSize; - const double triangleHeight = std::sin((M_PI - centerAngle) / 2) * - FlatPatternGeometry().triangleEdgeSize; + const double triangleHeight = + std::sin((M_PI - centerAngle) / 2) * PatternGeometry().triangleEdgeSize; T.SetTranslate(0, -2 * triangleHeight, 0); - vcg::tri::UpdatePosition::Matrix(fan, T); + vcg::tri::UpdatePosition::Matrix(fan, T); - FlatPatternGeometry fanOfFan = createFan(fan); - vcg::tri::Append::Mesh(tile, - fanOfFan); - vcg::tri::Clean::MergeCloseVertex(tile, 0.0000005); - vcg::tri::Allocator::CompactEveryVector(tile); - vcg::tri::UpdateTopology::VertexEdge(tile); - vcg::tri::UpdateTopology::EdgeEdge(tile); + PatternGeometry fanOfFan = createFan(fan); + vcg::tri::Append::Mesh(tile, fanOfFan); + vcg::tri::Clean::MergeCloseVertex(tile, 0.0000005); + vcg::tri::Allocator::CompactEveryVector(tile); + vcg::tri::UpdateTopology::VertexEdge(tile); + vcg::tri::UpdateTopology::EdgeEdge(tile); for (size_t vi = 0; vi < pattern.vn; vi++) { tile.vert[vi].C() = vcg::Color4b::Blue; } + tile.updateEigenEdgeAndVertices(); return tile; } -FlatPatternGeometry -FlatPatternGeometry::createFan(FlatPatternGeometry &pattern) { - const size_t fanSize = FlatPatternGeometry().getFanSize(); - FlatPatternGeometry fan(pattern); - FlatPatternGeometry rotatedPattern(pattern); +PatternGeometry PatternGeometry::createFan(PatternGeometry &pattern) { + const size_t fanSize = PatternGeometry().getFanSize(); + PatternGeometry fan(pattern); + PatternGeometry rotatedPattern(pattern); for (int rotationCounter = 1; rotationCounter < fanSize; rotationCounter++) { vcg::Matrix44d R; auto rotationAxis = vcg::Point3d(0, 0, 1); R.SetRotateDeg(360 / fanSize, rotationAxis); - vcg::tri::UpdatePosition::Matrix(rotatedPattern, R); - vcg::tri::Append::Mesh( - fan, rotatedPattern); + vcg::tri::UpdatePosition::Matrix(rotatedPattern, R); + vcg::tri::Append::Mesh(fan, + rotatedPattern); } return fan; } -FlatPatternGeometry::FlatPatternGeometry(FlatPatternGeometry &other) { - vcg::tri::Append::MeshCopy(*this, - other); +PatternGeometry::PatternGeometry(PatternGeometry &other) { + vcg::tri::Append::MeshCopy(*this, other); this->vertices = other.getVertices(); - vcg::tri::UpdateTopology::VertexEdge(*this); - vcg::tri::UpdateTopology::EdgeEdge(*this); + vcg::tri::UpdateTopology::VertexEdge(*this); + vcg::tri::UpdateTopology::EdgeEdge(*this); } -bool FlatPatternGeometry::savePly(const std::string plyFilename) { +bool PatternGeometry::savePly(const std::string plyFilename) { - int returnValue = vcg::tri::io::ExporterPLY::Save( + int returnValue = vcg::tri::io::ExporterPLY::Save( *this, plyFilename.c_str(), vcg::tri::io::Mask::IOM_EDGEINDEX | vcg::tri::io::Mask::IOM_VERTCOLOR, false); if (returnValue != 0) { - std::cerr << vcg::tri::io::ExporterPLY::ErrorMsg( + std::cerr << vcg::tri::io::ExporterPLY::ErrorMsg( returnValue) << std::endl; } @@ -162,44 +155,44 @@ bool FlatPatternGeometry::savePly(const std::string plyFilename) { return static_cast(returnValue); } -void FlatPatternGeometry::add(const std::vector &vertices) { +void PatternGeometry::add(const std::vector &vertices) { this->vertices = vertices; std::for_each(vertices.begin(), vertices.end(), [&](const vcg::Point3d &p) { - vcg::tri::Allocator::AddVertex(*this, p); + vcg::tri::Allocator::AddVertex(*this, p); }); - vcg::tri::UpdateTopology::VertexEdge(*this); - vcg::tri::UpdateTopology::EdgeEdge(*this); + vcg::tri::UpdateTopology::VertexEdge(*this); + vcg::tri::UpdateTopology::EdgeEdge(*this); updateEigenEdgeAndVertices(); } -void FlatPatternGeometry::add(const std::vector &edges) { +void PatternGeometry::add(const std::vector &edges) { std::for_each(edges.begin(), edges.end(), [&](const vcg::Point2i &e) { - vcg::tri::Allocator::AddEdge(*this, e[0], e[1]); + vcg::tri::Allocator::AddEdge(*this, e[0], e[1]); }); - vcg::tri::UpdateTopology::VertexEdge(*this); - vcg::tri::UpdateTopology::EdgeEdge(*this); + vcg::tri::UpdateTopology::VertexEdge(*this); + vcg::tri::UpdateTopology::EdgeEdge(*this); updateEigenEdgeAndVertices(); } -void FlatPatternGeometry::add(const std::vector &vertices, - const std::vector &edges) { +void PatternGeometry::add(const std::vector &vertices, + const std::vector &edges) { add(vertices); add(edges); updateEigenEdgeAndVertices(); } -void FlatPatternGeometry::add(const std::vector &numberOfNodesPerSlot, - const std::vector &edges) { +void PatternGeometry::add(const std::vector &numberOfNodesPerSlot, + const std::vector &edges) { assert(numberOfNodesPerSlot.size() == 7); auto vertices = constructVertexVector(numberOfNodesPerSlot, fanSize, triangleEdgeSize); add(vertices, edges); - vcg::tri::UpdateTopology::VertexEdge(*this); - vcg::tri::UpdateTopology::EdgeEdge(*this); + vcg::tri::UpdateTopology::VertexEdge(*this); + vcg::tri::UpdateTopology::EdgeEdge(*this); updateEigenEdgeAndVertices(); } -std::vector FlatPatternGeometry::constructVertexVector( +std::vector PatternGeometry::constructVertexVector( const std::vector &numberOfNodesPerSlot, const size_t &fanSize, const double &triangleEdgeSize) { @@ -294,7 +287,7 @@ std::vector FlatPatternGeometry::constructVertexVector( return vertices; } -void FlatPatternGeometry::constructNodeToTiledValenceMap( +void PatternGeometry::constructNodeToTiledValenceMap( const std::vector &numberOfNodesPerSlot) { for (size_t nodeIndex = 0; nodeIndex < vn; nodeIndex++) { const size_t tiledValence = @@ -303,7 +296,7 @@ void FlatPatternGeometry::constructNodeToTiledValenceMap( } } -bool FlatPatternGeometry::hasDanglingEdges( +bool PatternGeometry::hasDanglingEdges( const std::vector &numberOfNodesPerSlot) { if (nodeSlot.empty()) { FlatPatternTopology::constructNodeToSlotMap(numberOfNodesPerSlot, nodeSlot); @@ -325,7 +318,7 @@ bool FlatPatternGeometry::hasDanglingEdges( return hasDanglingEdges; } -bool FlatPatternGeometry::hasUntiledDanglingEdges() { +bool PatternGeometry::hasUntiledDanglingEdges() { // vcg::tri::Clean::MergeCloseVertex(*this, // 0.0000005); // vcg::tri::Allocator::CompactEveryVector(*this); @@ -333,7 +326,7 @@ bool FlatPatternGeometry::hasUntiledDanglingEdges() { // vcg::tri::UpdateTopology::EdgeEdge(*this); bool hasDanglingEdges = false; for (size_t vi = 0; vi < vn; vi++) { - std::vector connectedEdges; + std::vector connectedEdges; vcg::edge::VEStarVE(&vert[vi], connectedEdges); const size_t nodeValence = connectedEdges.size(); if (nodeValence == 1) { @@ -350,7 +343,7 @@ bool FlatPatternGeometry::hasUntiledDanglingEdges() { // TODO: The function expects that the numberOfNodesPerSlot follows a specific // format and that the vertex container was populated in a particular order. -void FlatPatternGeometry::constructCorresponginNodeMap( +void PatternGeometry::constructCorresponginNodeMap( const std::vector &numberOfNodesPerSlot) { assert(vn != 0 && !nodeSlot.empty() && correspondingNode.empty() && numberOfNodesPerSlot.size() == 7); @@ -382,7 +375,7 @@ void FlatPatternGeometry::constructCorresponginNodeMap( } } -bool FlatPatternGeometry::isFullyConnectedWhenTiled() { +bool PatternGeometry::isFullyConnectedWhenTiled() { assert(vn != 0 /* && !correspondingNode.empty()*/); // TrianglePatternGeometry copyOfPattern(*this); @@ -392,7 +385,7 @@ bool FlatPatternGeometry::isFullyConnectedWhenTiled() { for (size_t nodeIndex = 0; nodeIndex < vn; nodeIndex++) { if (nodeSlot[nodeIndex] == 1 || nodeSlot[nodeIndex] == 4 || nodeSlot[nodeIndex] == 2) { - std::vector connectedEdges; + std::vector connectedEdges; vcg::edge::VEStarVE(&vert[nodeIndex], connectedEdges); const size_t nodeValence = connectedEdges.size(); if (nodeValence != 0) { @@ -405,15 +398,14 @@ bool FlatPatternGeometry::isFullyConnectedWhenTiled() { return false; } - FlatPatternGeometry fanedPattern = createFan(*this); - vcg::tri::Clean::MergeCloseVertex(fanedPattern, - 0.000000005); - vcg::tri::Allocator::CompactEveryVector(fanedPattern); - vcg::tri::UpdateTopology::VertexEdge(fanedPattern); - vcg::tri::UpdateTopology::EdgeEdge(fanedPattern); - std::vector> eCC; - vcg::tri::Clean::edgeMeshConnectedComponents( - fanedPattern, eCC); + PatternGeometry fanedPattern = createFan(*this); + vcg::tri::Clean::MergeCloseVertex(fanedPattern, 0.000000005); + vcg::tri::Allocator::CompactEveryVector(fanedPattern); + vcg::tri::UpdateTopology::VertexEdge(fanedPattern); + vcg::tri::UpdateTopology::EdgeEdge(fanedPattern); + std::vector> eCC; + vcg::tri::Clean::edgeMeshConnectedComponents(fanedPattern, + eCC); const bool sideInterfaceIsConnected = 1 == eCC.size(); if (!sideInterfaceIsConnected) { @@ -490,7 +482,7 @@ bool FlatPatternGeometry::isFullyConnectedWhenTiled() { return true; } -bool FlatPatternGeometry::hasIntersectingEdges( +bool PatternGeometry::hasIntersectingEdges( const std::string &patternBinaryRepresentation, const std::unordered_map> &intersectingEdges) { @@ -520,7 +512,7 @@ bool FlatPatternGeometry::hasIntersectingEdges( } std::unordered_map> -FlatPatternGeometry::getIntersectingEdges( +PatternGeometry::getIntersectingEdges( size_t &numberOfIntersectingEdgePairs) const { std::unordered_map> intersectingEdges; numberOfIntersectingEdgePairs = 0; @@ -569,3 +561,434 @@ FlatPatternGeometry::getIntersectingEdges( } return intersectingEdges; } + +PatternGeometry::PatternGeometry(const std::string &filename, + bool addNormalsIfAbsent) { + if (!std::filesystem::exists(std::filesystem::path(filename))) { + assert(false); + std::cerr << "No flat pattern with name " << filename << std::endl; + return; + } + if (!load(filename)) { + assert(false); + std::cerr << "File could not be loaded " << filename << std::endl; + return; + } + if (addNormalsIfAbsent) { + addNormals(); + } + + vcg::tri::UpdateTopology::VertexEdge(*this); + baseTriangleHeight = computeBaseTriangleHeight(); + + updateEigenEdgeAndVertices(); +} + +double PatternGeometry::computeBaseTriangleHeight() const { + return (vert[0].cP() - vert[3].cP()).Norm(); +} + +void PatternGeometry::addNormals() { + bool normalsAreAbsent = vert[0].cN().Norm() < 0.000001; + if (normalsAreAbsent) { + for (auto &v : vert) { + v.N() = CoordType(0, 0, 1); + } + } +} + +PatternGeometry::PatternGeometry( + const std::vector &numberOfNodesPerSlot, + const std::vector &edges) { + add(numberOfNodesPerSlot, edges); + addNormals(); + baseTriangleHeight = computeBaseTriangleHeight(); + updateEigenEdgeAndVertices(); +} + +bool PatternGeometry::createHoneycombAtom() { + VCGEdgeMesh honeycombQuarter; + const VCGEdgeMesh::CoordType n(0, 0, 1); + const double H = 0.2; + const double height = 1.5 * H; + const double width = 0.2; + const double theta = 70; + const double dy = tan(vcg::math::ToRad(90 - theta)) * width / 2; + vcg::tri::Allocator::AddVertex( + honeycombQuarter, VCGEdgeMesh::CoordType(0, height / 2, 0), n); + vcg::tri::Allocator::AddVertex( + honeycombQuarter, VCGEdgeMesh::CoordType(0, H / 2 - dy, 0), n); + vcg::tri::Allocator::AddVertex( + honeycombQuarter, VCGEdgeMesh::CoordType(width / 2, H / 2, 0), n); + vcg::tri::Allocator::AddVertex( + honeycombQuarter, VCGEdgeMesh::CoordType(width / 2, 0, 0), n); + vcg::tri::Allocator::AddEdge(honeycombQuarter, 0, 1); + vcg::tri::Allocator::AddEdge(honeycombQuarter, 1, 2); + vcg::tri::Allocator::AddEdge(honeycombQuarter, 2, 3); + + VCGEdgeMesh honeycombAtom; + // Top right + vcg::tri::Append::MeshCopy(honeycombAtom, + honeycombQuarter); + // Bottom right + vcg::Matrix44d rotM; + rotM.SetRotateDeg(180, vcg::Point3d(1, 0, 0)); + vcg::tri::UpdatePosition::Matrix(honeycombQuarter, rotM); + vcg::tri::Append::Mesh(honeycombAtom, + honeycombQuarter); + // Bottom left + rotM.SetRotateDeg(180, vcg::Point3d(0, 1, 0)); + vcg::tri::UpdatePosition::Matrix(honeycombQuarter, rotM); + vcg::tri::Append::Mesh(honeycombAtom, + honeycombQuarter); + // Top left + rotM.SetRotateDeg(180, vcg::Point3d(1, 0, 0)); + vcg::tri::UpdatePosition::Matrix(honeycombQuarter, rotM); + vcg::tri::Append::Mesh(honeycombAtom, + honeycombQuarter); + + for (VertexType &v : honeycombAtom.vert) { + v.P()[2] = 0; + } + + return true; +} + +void PatternGeometry::copy(PatternGeometry ©From) { + VCGEdgeMesh::copy(copyFrom); + baseTriangleHeight = copyFrom.getBaseTriangleHeight(); +} + +void PatternGeometry::deleteDanglingEdges() { + for (VertexType &v : vert) { + std::vector incidentElements; + vcg::edge::VEStarVE(&v, incidentElements); + if (incidentElements.size() == 1) { + vcg::tri::Allocator::DeleteEdge(*this, *incidentElements[0]); + } + if (incidentElements.size() == 1) { + vcg::tri::Allocator::DeleteVertex(*this, v); + } + } + + vcg::tri::Clean::RemoveDegenerateVertex(*this); + vcg::tri::Clean::RemoveDegenerateEdge(*this); + vcg::tri::Allocator::CompactEveryVector(*this); +} + +void PatternGeometry::scale(const double &desiredBaseTriangleCentralEdgeSize) { + this->baseTriangleHeight = desiredBaseTriangleCentralEdgeSize; + const double baseTriangleCentralEdgeSize = + (vert[0].cP() - vert[3].cP()).Norm(); + const double scaleRatio = + desiredBaseTriangleCentralEdgeSize / baseTriangleCentralEdgeSize; + + vcg::tri::UpdatePosition::Scale(*this, scaleRatio); +} + +void PatternGeometry::deleteDanglingVertices() { + vcg::tri::Allocator::PointerUpdater pu; + deleteDanglingVertices(pu); +} + +void PatternGeometry::deleteDanglingVertices( + vcg::tri::Allocator::PointerUpdater &pu) { + for (VertexType &v : vert) { + std::vector incidentElements; + vcg::edge::VEStarVE(&v, incidentElements); + if (incidentElements.size() == 0 && !v.IsD()) { + vcg::tri::Allocator::DeleteVertex(*this, v); + } + } + + vcg::tri::Allocator::CompactVertexVector(*this, pu); + vcg::tri::Allocator::CompactEdgeVector(*this); + + updateEigenEdgeAndVertices(); +} + +void PatternGeometry::tilePattern(VCGEdgeMesh& pattern, VCGPolyMesh &tileInto,const int& interfaceNodeIndex, + const bool &shouldDeleteDanglingEdges) { + double xOffset = + vcg::Distance(pattern.vert[0].cP(), pattern.vert[interfaceNodeIndex].cP()) / + std::tan(M_PI / 3); + CoordType patternCoord0 = pattern.vert[0].cP(); + CoordType patternBottomRight = + pattern.vert[interfaceNodeIndex].cP() + CoordType(xOffset, 0, 0); + CoordType patternBottomLeft = + pattern.vert[interfaceNodeIndex].cP() - CoordType(xOffset, 0, 0); + std::vector patternTrianglePoints{ + patternCoord0, patternBottomRight, patternBottomLeft}; + CoordType pointOnPattern = + patternCoord0 + (patternBottomLeft - patternCoord0) ^ + (patternBottomRight - patternCoord0); + + std::vector faceCenters(FN()); + VCGTriMesh tileIntoEdgeMesh; + + for (VCGPolyMesh::FaceType &f : tileInto.face) { + std::vector incidentVertices; + vcg::face::VFIterator vfi( + &f, 0); // initialize the iterator to the first face + // vcg::face::Pos p(vfi.F(), f.cV(0)); + // vcg::face::VVOrderedStarFF(p, incidentVertices); + size_t numberOfNodes = 0; + CoordType centerOfFace(0, 0, 0); + for (size_t vi = 0; vi < f.VN(); vi++) { + numberOfNodes++; + centerOfFace = centerOfFace + f.cP(vi); + } + centerOfFace /= f.VN(); + vcg::tri::Allocator::AddVertex(tileIntoEdgeMesh, centerOfFace, + vcg::Color4b::Yellow); + + // const size_t vi = vcg::tri::Index(tileInto, v); + // std::cout << "vertex " << vi << " has incident vertices:" << + // std::endl; + for (size_t vi = 0; vi < f.VN(); vi++) { + // size_t f = 0; + // std::cout << vcg::tri::Index(tileInto, + // / incidentVertices[f]) / << std::endl; + + // Compute transformation matrix M + // vcg::Matrix44d M; + std::vector meshTrianglePoints{ + centerOfFace, f.cP(vi), vi + 1 == f.VN() ? f.cP(0) : f.cP(vi + 1)}; + CoordType faceNormal = ((meshTrianglePoints[1] - meshTrianglePoints[0]) ^ + (meshTrianglePoints[2] - meshTrianglePoints[0])) + .Normalize(); + auto fit = vcg::tri::Allocator::AddFace( + tileIntoEdgeMesh, meshTrianglePoints[0], meshTrianglePoints[1], + meshTrianglePoints[2]); + fit->N() = faceNormal; + CoordType pointOnTriMesh = + meshTrianglePoints[0] + + (meshTrianglePoints[1] - meshTrianglePoints[0]) ^ + (meshTrianglePoints[2] - meshTrianglePoints[0]); + vcg::Matrix44d M; + // vcg::ComputeRigidMatchMatrix(meshTrianglePoints, + // patternTrianglePoints, + // M); + vcg::Matrix44d A_prime; + A_prime[0][0] = meshTrianglePoints[0][0]; + A_prime[1][0] = meshTrianglePoints[0][1]; + A_prime[2][0] = meshTrianglePoints[0][2]; + A_prime[3][0] = 1; + A_prime[0][1] = meshTrianglePoints[1][0]; + A_prime[1][1] = meshTrianglePoints[1][1]; + A_prime[2][1] = meshTrianglePoints[1][2]; + A_prime[3][1] = 1; + A_prime[0][2] = meshTrianglePoints[2][0]; + A_prime[1][2] = meshTrianglePoints[2][1]; + A_prime[2][2] = meshTrianglePoints[2][2]; + A_prime[3][2] = 1; + A_prime[0][3] = pointOnTriMesh[0]; + A_prime[1][3] = pointOnTriMesh[1]; + A_prime[2][3] = pointOnTriMesh[2]; + A_prime[3][3] = 1; + vcg::Matrix44d A; + A[0][0] = patternTrianglePoints[0][0]; + A[1][0] = patternTrianglePoints[0][1]; + A[2][0] = patternTrianglePoints[0][2]; + A[3][0] = 1; + A[0][1] = patternTrianglePoints[1][0]; + A[1][1] = patternTrianglePoints[1][1]; + A[2][1] = patternTrianglePoints[1][2]; + A[3][1] = 1; + A[0][2] = patternTrianglePoints[2][0]; + A[1][2] = patternTrianglePoints[2][1]; + A[2][2] = patternTrianglePoints[2][2]; + A[3][2] = 1; + A[0][3] = pointOnPattern[0]; + A[1][3] = pointOnPattern[1]; + A[2][3] = pointOnPattern[2]; + A[3][3] = 1; + M = A_prime * vcg::Inverse(A); + + VCGEdgeMesh transformedPattern; + vcg::tri::Append::MeshCopy(transformedPattern, + pattern); + vcg::tri::UpdatePosition::Matrix(transformedPattern, M); + for (VertexType &v : transformedPattern.vert) { + v.N() = faceNormal; + } + + vcg::tri::Append::Mesh(*this, + transformedPattern); + } + } + + // vcg::tri::Clean::MergeCloseVertex(*this, 0.0000000001); + // vcg::tri::Clean::RemoveDegenerateVertex(*this); + // vcg::tri::Clean::RemoveDegenerateEdge(*this); + // vcg::tri::Allocator::CompactEveryVector(*this); + + // vcg::tri::Clean::RemoveDuplicateVertex(*this); + vcg::tri::Clean::MergeCloseVertex(*this, 0.000061524); + vcg::tri::UpdateTopology::VertexEdge(*this); + + // vcg::tri::Clean::RemoveUnreferencedVertex(*this); + // vcg::tri::UpdateTopology::VertexEdge(*this); + // vcg::tri::Clean::RemoveDegenerateVertex(*this); + // vcg::tri::Clean::RemoveDegenerateEdge(*this); + // vcg::tri::Allocator::CompactEveryVector(*this); + deleteDanglingVertices(); + vcg::tri::Allocator::CompactEveryVector(*this); + // vcg::tri::Clean::RemoveDegenerateVertex(*this); + // vcg::tri::Clean::RemoveUnreferencedVertex(*this); + // vcg::tri::UpdateTopology::VertexEdge(*this); + // deleteDanglingEdges(); + // vcg::tri::Clean::RemoveUnreferencedVertex(*this); + // vcg::tri::Clean::RemoveDegenerateVertex(*this); + // vcg::tri::Clean::RemoveDegenerateEdge(*this); + // vcg::tri::Allocator::CompactEveryVector(*this); + updateEigenEdgeAndVertices(); + savePly("tiledPattern.ply"); +} + +void PatternGeometry::createFan(const size_t &fanSize) { + PatternGeometry rotatedPattern; + vcg::tri::Append::MeshCopy(rotatedPattern, + *this); + for (int rotationCounter = 1; rotationCounter < fanSize; rotationCounter++) { + vcg::Matrix44d R; + auto rotationAxis = vcg::Point3d(0, 0, 1); + R.SetRotateDeg(360 / fanSize, rotationAxis); + vcg::tri::UpdatePosition::Matrix(rotatedPattern, R); + vcg::tri::Append::Mesh(*this, + rotatedPattern); + } + + removeDuplicateVertices(); + // const double precision = 1e-4; + // for (size_t vi = 0; vi < VN(); vi++) { + // vert[vi].P()[0] = std::round(vert[vi].P()[0] * (1 / precision)) * + // precision; vert[vi].P()[1] = std::round(vert[vi].P()[1] * (1 / + // precision)) * precision; vert[vi].P()[2] = std::round(vert[vi].P()[2] + // * (1 / precision)) * precision; + // } + + updateEigenEdgeAndVertices(); +} + +void PatternGeometry::removeDuplicateVertices() { + vcg::tri::Clean::MergeCloseVertex(*this, 0.0000000001); + vcg::tri::Clean::RemoveDegenerateVertex(*this); + vcg::tri::Clean::RemoveDegenerateEdge(*this); + vcg::tri::Allocator::CompactEveryVector(*this); + vcg::tri::UpdateTopology::VertexEdge(*this); +} + +double PatternGeometry::getBaseTriangleHeight() const { + return baseTriangleHeight; +} + +void PatternGeometry::tilePattern(PatternGeometry &pattern, VCGTriMesh &tileInto) { + + const size_t middleIndex = 3; + double xOffset = + vcg::Distance(pattern.vert[0].cP(), pattern.vert[middleIndex].cP()) / + std::tan(M_PI / 3); + CoordType patternCoord0 = pattern.vert[0].cP(); + CoordType patternBottomRight = + pattern.vert[middleIndex].cP() + CoordType(xOffset, 0, 0); + CoordType patternBottomLeft = + pattern.vert[middleIndex].cP() - CoordType(xOffset, 0, 0); + std::vector patternTrianglePoints{ + patternCoord0, patternBottomRight, patternBottomLeft}; + CoordType pointOnPattern = + patternCoord0 + (patternBottomLeft - patternCoord0) ^ + (patternBottomRight - patternCoord0); + + for (VCGTriMesh::VertexType &v : tileInto.vert) { + const auto centralNodeColor = vcg::Color4(64, 64, 64, 255); + const bool isCentralNode = v.cC() == centralNodeColor; + if (isCentralNode) { + std::vector incidentVertices; + vcg::face::VFIterator vfi( + &v); // initialize the iterator tohe first face + vcg::face::Pos p(vfi.F(), &v); + vcg::face::VVOrderedStarFF(p, incidentVertices); + + const size_t vi = vcg::tri::Index(tileInto, v); + std::cout << "vertex " << vi << " has incident vertices:" << std::endl; + for (size_t f = 0; f < incidentVertices.size(); f++) { + // size_t f = 0; + std::cout << vcg::tri::Index(tileInto, incidentVertices[f]) + << std::endl; + + // Compute transformation matrix M + // vcg::Matrix44d M; + std::vector meshTrianglePoints{ + v.cP(), incidentVertices[f]->cP(), + f + 1 == incidentVertices.size() ? incidentVertices[0]->cP() + : incidentVertices[f + 1]->cP()}; + CoordType faceNormal = + ((meshTrianglePoints[1] - meshTrianglePoints[0]) ^ + (meshTrianglePoints[2] - meshTrianglePoints[0])) + .Normalize(); + CoordType pointOnTriMesh = + meshTrianglePoints[0] + + (meshTrianglePoints[1] - meshTrianglePoints[0]) ^ + (meshTrianglePoints[2] - meshTrianglePoints[0]); + vcg::Matrix44d M; + // vcg::ComputeRigidMatchMatrix(meshTrianglePoints, + // patternTrianglePoints, + // M); + vcg::Matrix44d A_prime; + A_prime[0][0] = meshTrianglePoints[0][0]; + A_prime[1][0] = meshTrianglePoints[0][1]; + A_prime[2][0] = meshTrianglePoints[0][2]; + A_prime[3][0] = 1; + A_prime[0][1] = meshTrianglePoints[1][0]; + A_prime[1][1] = meshTrianglePoints[1][1]; + A_prime[2][1] = meshTrianglePoints[1][2]; + A_prime[3][1] = 1; + A_prime[0][2] = meshTrianglePoints[2][0]; + A_prime[1][2] = meshTrianglePoints[2][1]; + A_prime[2][2] = meshTrianglePoints[2][2]; + A_prime[3][2] = 1; + A_prime[0][3] = pointOnTriMesh[0]; + A_prime[1][3] = pointOnTriMesh[1]; + A_prime[2][3] = pointOnTriMesh[2]; + A_prime[3][3] = 1; + vcg::Matrix44d A; + A[0][0] = patternTrianglePoints[0][0]; + A[1][0] = patternTrianglePoints[0][1]; + A[2][0] = patternTrianglePoints[0][2]; + A[3][0] = 1; + A[0][1] = patternTrianglePoints[1][0]; + A[1][1] = patternTrianglePoints[1][1]; + A[2][1] = patternTrianglePoints[1][2]; + A[3][1] = 1; + A[0][2] = patternTrianglePoints[2][0]; + A[1][2] = patternTrianglePoints[2][1]; + A[2][2] = patternTrianglePoints[2][2]; + A[3][2] = 1; + A[0][3] = pointOnPattern[0]; + A[1][3] = pointOnPattern[1]; + A[2][3] = pointOnPattern[2]; + A[3][3] = 1; + M = A_prime * vcg::Inverse(A); + + VCGEdgeMesh transformedPattern; + vcg::tri::Append::MeshCopy(transformedPattern, + pattern); + vcg::tri::UpdatePosition::Matrix(transformedPattern, M); + for (VertexType &v : transformedPattern.vert) { + v.N() = faceNormal; + } + + vcg::tri::Append::Mesh(*this, + transformedPattern); + } + } + } + + vcg::tri::UpdateTopology::VertexEdge(*this); + deleteDanglingVertices(); + deleteDanglingEdges(); + vcg::tri::Allocator::CompactEveryVector(*this); + + updateEigenEdgeAndVertices(); +} diff --git a/trianglepatterngeometry.hpp b/trianglepatterngeometry.hpp old mode 100644 new mode 100755 index 73da326..7efb9b8 --- a/trianglepatterngeometry.hpp +++ b/trianglepatterngeometry.hpp @@ -4,8 +4,10 @@ #include #include #include +#include "vcgtrimesh.hpp" +#include "polymesh.hpp" -class FlatPatternGeometry : public VCGEdgeMesh { +class PatternGeometry : public VCGEdgeMesh { private: size_t computeTiledValence(const size_t &nodeIndex, @@ -13,6 +15,12 @@ private: size_t getNodeValence(const size_t &nodeIndex) const; size_t getNodeSlot(const size_t &nodeIndex) const; + void addNormals(); + void deleteDanglingEdges(); + void removeDuplicateVertices(); + double baseTriangleHeight; + double computeBaseTriangleHeight() const; + const size_t fanSize{6}; std::vector vertices; const double triangleEdgeSize{1}; // radius edge @@ -27,12 +35,12 @@ private: const std::vector &numberOfNodesPerSlot); public: - FlatPatternGeometry(); + PatternGeometry(); /*The following function should be a copy constructor with * a const argument but this is impossible due to the * vcglib interface. * */ - FlatPatternGeometry(FlatPatternGeometry &other); + PatternGeometry(PatternGeometry &other); bool savePly(const std::string plyFilename); void add(const std::vector &vertices); void add(const std::vector &edges); @@ -45,8 +53,8 @@ public: const size_t &fanSize, const double &triangleEdgeSize); bool hasDanglingEdges(const std::vector &numberOfNodesPerSlot); std::vector getVertices() const; - static FlatPatternGeometry createFan(FlatPatternGeometry &pattern); - static FlatPatternGeometry createTile(FlatPatternGeometry &pattern); + static PatternGeometry createFan(PatternGeometry &pattern); + static PatternGeometry createTile(PatternGeometry &pattern); double getTriangleEdgeSize() const; bool hasUntiledDanglingEdges(); std::unordered_map> @@ -64,5 +72,31 @@ public: &intersectingEdges); bool isPatternValid(); size_t getFanSize() const; + void add(const std::vector &vertices, + const std::vector &edges); + + PatternGeometry(const std::vector &numberOfNodesPerSlot, + const std::vector &edges); + PatternGeometry(const std::string &filename, bool addNormalsIfAbsent = true); + + bool createHoneycombAtom(); + void copy(PatternGeometry ©From); + + void tilePattern(PatternGeometry &pattern, VCGTriMesh &tileInto); + void tilePattern(VCGEdgeMesh &pattern, VCGPolyMesh &tileInto, const int &interfaceNodeIndex, + const bool &shouldDeleteDanglingEdges); + + void createFan(const size_t &fanSize = 6); + + void deleteDanglingVertices( + vcg::tri::Allocator::PointerUpdater &pu); + void deleteDanglingVertices(); + void scale(const double &desiredBaseTriangleCentralEdgeSize); + + double getBaseTriangleHeight() const; + + PatternGeometry(const std::vector &vertices, + const std::vector &edges); + }; #endif // FLATPATTERNGEOMETRY_HPP diff --git a/trianglepattterntopology.cpp b/trianglepattterntopology.cpp old mode 100644 new mode 100755 diff --git a/trianglepattterntopology.hpp b/trianglepattterntopology.hpp old mode 100644 new mode 100755 diff --git a/utilities.hpp b/utilities.hpp old mode 100644 new mode 100755 index b1e5088..41b4ec1 --- a/utilities.hpp +++ b/utilities.hpp @@ -13,6 +13,11 @@ struct Vector6d : public std::array { } } + Vector6d(const std::vector &v) { + assert(v.size() == 6); + std::copy(v.begin(), v.end(), this->begin()); + } + Vector6d(const double &d) { for (size_t i = 0; i < 6; i++) { this->operator[](i) = d; diff --git a/vcgtrimesh.cpp b/vcgtrimesh.cpp old mode 100644 new mode 100755 index 6acbc35..23f1eb0 --- a/vcgtrimesh.cpp +++ b/vcgtrimesh.cpp @@ -1,4 +1,5 @@ #include "vcgtrimesh.hpp" +#include #include "wrap/io_trimesh/import_obj.h" #include "wrap/io_trimesh/import_off.h" #include diff --git a/vcgtrimesh.hpp b/vcgtrimesh.hpp old mode 100644 new mode 100755 index 245031c..7be0d69 --- a/vcgtrimesh.hpp +++ b/vcgtrimesh.hpp @@ -1,7 +1,6 @@ #ifndef VCGTRIMESH_HPP #define VCGTRIMESH_HPP #include -#include using VertexIndex = size_t; class VCGTriMeshVertex;