#ifndef FLATPATTERNGEOMETRY_HPP #define FLATPATTERNGEOMETRY_HPP #include "edgemesh.hpp" #include #include #include #include "vcgtrimesh.hpp" #include "polymesh.hpp" class PatternGeometry : public VCGEdgeMesh { private: size_t computeTiledValence(const size_t &nodeIndex, const std::vector &numberOfNodesPerSlot) const; size_t getNodeValence(const size_t &nodeIndex) const; size_t getNodeSlot(const size_t &nodeIndex) const; void addNormals(); double baseTriangleHeight; double computeBaseTriangleHeight() const; const int interfaceNodeIndex{3}; const size_t fanSize{6}; std::vector vertices; const double triangleEdgeSize{1}; // radius edge std::unordered_map nodeSlot; std::unordered_map correspondingNode; std::unordered_map nodeTiledValence; void constructCorresponginNodeMap(const std::vector &numberOfNodesPerSlot); void constructNodeToTiledValenceMap( const std::vector &numberOfNodesPerSlot); public: PatternGeometry(); /*The following function should be a copy constructor with * a const argument but this is impossible due to the * vcglib interface. * */ PatternGeometry(PatternGeometry &other); bool save(const std::string plyFilename); void add(const std::vector &vertices); void add(const std::vector &edges); void add(const std::vector &vertices, const std::vector &edges); void add(const std::vector &numberOfNodesPerSlot, const std::vector &edges); static std::vector constructVertexVector(const std::vector &numberOfNodesPerSlot, const size_t &fanSize, const double &triangleEdgeSize); bool hasDanglingEdges(const std::vector &numberOfNodesPerSlot); std::vector getVertices() const; static PatternGeometry createFan(PatternGeometry &pattern); static PatternGeometry createTile(PatternGeometry &pattern); double getTriangleEdgeSize() const; bool hasUntiledDanglingEdges(); std::unordered_map> getIntersectingEdges(size_t &numberOfIntersectingEdgePairs) const; static size_t binomialCoefficient(size_t n, size_t m) { assert(n >= m); return tgamma(n + 1) / (tgamma(m + 1) * tgamma(n - m + 1)); } bool isFullyConnectedWhenTiled(); bool hasIntersectingEdges( const std::string &patternBinaryRepresentation, const std::unordered_map> &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 scale(const double &desiredBaseTriangleCentralEdgeSize, const int &interfaceNodeIndex); double getBaseTriangleHeight() const; vcg::Triangle3 getBaseTriangle() const; PatternGeometry(const std::vector &vertices, const std::vector &edges); // static std::shared_ptr tilePattern(PatternGeometry &pattern, // VCGPolyMesh &tileInto, // const int &interfaceNodeIndex, // const bool &shouldDeleteDanglingEdges) // { // PatternGeometry tiledPattern; // double bottomEdgeHalfSize = 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(bottomEdgeHalfSize, 0, 0); // CoordType patternBottomLeft = pattern.vert[interfaceNodeIndex].cP() // - CoordType(bottomEdgeHalfSize, 0, 0); // std::vector patternTrianglePoints{patternCoord0, // patternBottomRight, // patternBottomLeft}; // CoordType pointOnPattern = patternCoord0 + (patternBottomLeft - patternCoord0) // ^ (patternBottomRight - patternCoord0); // // patternTrianglePoints.push_back(pointOnPattern); // VCGTriMesh tileIntoEdgeMesh; // for (VCGPolyMesh::FaceType &f : tileInto.face) { // 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); // for (size_t vi = 0; vi < f.VN(); vi++) { // // 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; // // meshTrianglePoints.push_back(pointOnTriMesh); // // 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); // PatternGeometry transformedPattern; // transformedPattern.copy(pattern); // vcg::tri::UpdatePosition::Matrix(transformedPattern, M); // for (VertexType &v : transformedPattern.vert) { // v.N() = faceNormal; // } // // const double innerHexagonInitialRotationAngle = 30; // // vcg::Matrix44d Rlocal; // // Rlocal.SetRotateDeg( // // (0 // // // optimizationResults.optimalXNameValuePairs["HexAngle"] // // - innerHexagonInitialRotationAngle), // // VectorType(0, 0, 1)); // // vcg::Matrix44d T; // // T.SetTranslate(-transformedPattern.vert[0].cP()); // // vcg::Matrix44d Trev; // // Trev.SetTranslate(transformedPattern.vert[0].cP()); // // auto R = T * Rlocal * Trev; // // transformedPattern.vert[1].P() // // = R * meshTrianglePoints[2] // // * 0.5; //optimizationResults.optimalXNameValuePairs["HexSize"]; // // transformedPattern.vert[5].P() // // = R * meshTrianglePoints[1] // // * 0.5; //optimizationResults.optimalXNameValuePairs["HexSize"]; // vcg::tri::Append::Mesh(tiledPattern, transformedPattern); // tiledPattern.updateEigenEdgeAndVertices(); // tiledPattern.registerForDrawing(); // polyscope::show(); // } // } // tiledPattern.removeDuplicateVertices(); // tiledPattern.deleteDanglingVertices(); // vcg::tri::Allocator::CompactEveryVector(tiledPattern); // tiledPattern.updateEigenEdgeAndVertices(); // return std::make_shared(tiledPattern); // } static std::shared_ptr tilePattern(PatternGeometry &pattern, const vcg::Triangle3 &baseTriangle, const std::vector &connectToNeighborsVi, const VCGPolyMesh &tileInto) { std::shared_ptr pTiledPattern(new PatternGeometry); //Compute the barycentric coords of the verts in the base triangle pattern std::vector barycentricCoordinates(pattern.VN()); for (int vi = 0; vi < pattern.VN(); vi++) { CoordType barycentricCoords_vi; vcg::InterpolationParameters, double>(baseTriangle, pattern.vert[vi].cP(), barycentricCoords_vi); barycentricCoordinates[vi] = barycentricCoords_vi; } VCGTriMesh tileIntoEdgeMesh; for (const VCGPolyMesh::FaceType &f : tileInto.face) { CoordType centerOfFace(0, 0, 0); for (size_t vi = 0; vi < f.VN(); vi++) { centerOfFace = centerOfFace + f.cP(vi); } centerOfFace /= f.VN(); vcg::tri::Allocator::AddVertex(tileIntoEdgeMesh, centerOfFace, vcg::Color4b::Yellow); std::vector firstInFanConnectToNeighbor_vi(connectToNeighborsVi); for (int &vi : firstInFanConnectToNeighbor_vi) { vi += pTiledPattern->VN(); } for (size_t vi = 0; vi < f.VN(); vi++) { std::vector meshTrianglePoints{centerOfFace, f.cP(vi), vi + 1 == f.VN() ? f.cP(0) : f.cP(vi + 1)}; auto fit = vcg::tri::Allocator::AddFace(tileIntoEdgeMesh, meshTrianglePoints[0], meshTrianglePoints[1], meshTrianglePoints[2]); CoordType faceNormal = ((meshTrianglePoints[1] - meshTrianglePoints[0]) ^ (meshTrianglePoints[2] - meshTrianglePoints[0])) .Normalize(); fit->N() = faceNormal; PatternGeometry transformedPattern; transformedPattern.copy(pattern); //Transform the base triangle nodes to the mesh triangle using barycentric coords for (int vi = 0; vi < transformedPattern.VN(); vi++) { transformedPattern.vert[vi].P() = CoordType( meshTrianglePoints[0] * barycentricCoordinates[vi][0] + meshTrianglePoints[1] * barycentricCoordinates[vi][1] + meshTrianglePoints[2] * barycentricCoordinates[vi][2]); } for (VertexType &v : transformedPattern.vert) { v.N() = faceNormal; } vcg::tri::Append::Mesh(*pTiledPattern, transformedPattern); //Add edges for connecting the desired vertices if (!connectToNeighborsVi.empty()) { if (vi + 1 == f.VN()) { for (int connectToNeighborIndex = 0; connectToNeighborIndex < connectToNeighborsVi.size(); connectToNeighborIndex++) { vcg::tri::Allocator::AddEdge( *pTiledPattern, firstInFanConnectToNeighbor_vi[connectToNeighborIndex], pTiledPattern->VN() - pattern.VN() + connectToNeighborsVi[connectToNeighborIndex]); } } if (vi != 0) { for (int connectToNeighborIndex = 0; connectToNeighborIndex < connectToNeighborsVi.size(); connectToNeighborIndex++) { vcg::tri::Allocator::AddEdge( *pTiledPattern, pTiledPattern->VN() - 2 * pattern.VN() + connectToNeighborsVi[connectToNeighborIndex], pTiledPattern->VN() - pattern.VN() + connectToNeighborsVi[connectToNeighborIndex]); } } } // tiledPattern.updateEigenEdgeAndVertices(); // tiledPattern.registerForDrawing(); // polyscope::show(); } } pTiledPattern->removeDuplicateVertices(); pTiledPattern->deleteDanglingVertices(); vcg::tri::Allocator::CompactEveryVector(*pTiledPattern); pTiledPattern->updateEigenEdgeAndVertices(); return pTiledPattern; } void createFan(const std::vector &connectToNeighborsVi=std::vector(), const size_t &fanSize=6); }; #endif // FLATPATTERNGEOMETRY_HPP