MySources/trianglepatterngeometry.hpp

333 lines
17 KiB
C++
Executable File

#ifndef FLATPATTERNGEOMETRY_HPP
#define FLATPATTERNGEOMETRY_HPP
#include "edgemesh.hpp"
#include <string>
#include <unordered_map>
#include <unordered_set>
#include "vcgtrimesh.hpp"
#include "polymesh.hpp"
class PatternGeometry : public VCGEdgeMesh {
private:
size_t
computeTiledValence(const size_t &nodeIndex,
const std::vector<size_t> &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<VCGEdgeMesh::CoordType> vertices;
const double triangleEdgeSize{1}; // radius edge
std::unordered_map<size_t, size_t> nodeSlot;
std::unordered_map<size_t, size_t> correspondingNode;
std::unordered_map<size_t, size_t> nodeTiledValence;
void
constructCorresponginNodeMap(const std::vector<size_t> &numberOfNodesPerSlot);
void constructNodeToTiledValenceMap(
const std::vector<size_t> &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<vcg::Point3d> &vertices);
void add(const std::vector<vcg::Point2i> &edges);
void add(const std::vector<vcg::Point3d> &vertices,
const std::vector<vcg::Point2i> &edges);
void add(const std::vector<size_t> &numberOfNodesPerSlot,
const std::vector<vcg::Point2i> &edges);
static std::vector<vcg::Point3d>
constructVertexVector(const std::vector<size_t> &numberOfNodesPerSlot,
const size_t &fanSize, const double &triangleEdgeSize);
bool hasDanglingEdges(const std::vector<size_t> &numberOfNodesPerSlot);
std::vector<vcg::Point3d> getVertices() const;
static PatternGeometry createFan(PatternGeometry &pattern);
static PatternGeometry createTile(PatternGeometry &pattern);
double getTriangleEdgeSize() const;
bool hasUntiledDanglingEdges();
std::unordered_map<size_t, std::unordered_set<size_t>>
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<size_t, std::unordered_set<size_t>>
&intersectingEdges);
bool isPatternValid();
size_t getFanSize() const;
void add(const std::vector<vcg::Point2d> &vertices,
const std::vector<vcg::Point2i> &edges);
PatternGeometry(const std::vector<size_t> &numberOfNodesPerSlot,
const std::vector<vcg::Point2i> &edges);
PatternGeometry(const std::string &filename, bool addNormalsIfAbsent = true);
bool createHoneycombAtom();
void copy(PatternGeometry &copyFrom);
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<double> getBaseTriangle() const;
PatternGeometry(const std::vector<vcg::Point2d> &vertices, const std::vector<vcg::Point2i> &edges);
// static std::shared_ptr<PatternGeometry> 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<vcg::Point3d> 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<VCGTriMesh>::AddVertex(tileIntoEdgeMesh,
// centerOfFace,
// vcg::Color4b::Yellow);
// for (size_t vi = 0; vi < f.VN(); vi++) {
// // Compute transformation matrix M
// // vcg::Matrix44d M;
// std::vector<vcg::Point3d> 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<VCGTriMesh>::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<PatternGeometry>::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<MeshType, MeshType>::Mesh(tiledPattern, transformedPattern);
// tiledPattern.updateEigenEdgeAndVertices();
// tiledPattern.registerForDrawing();
// polyscope::show();
// }
// }
// tiledPattern.removeDuplicateVertices();
// tiledPattern.deleteDanglingVertices();
// vcg::tri::Allocator<PatternGeometry>::CompactEveryVector(tiledPattern);
// tiledPattern.updateEigenEdgeAndVertices();
// return std::make_shared<PatternGeometry>(tiledPattern);
// }
static std::shared_ptr<PatternGeometry> tilePattern(PatternGeometry &pattern,
const vcg::Triangle3<double> &baseTriangle,
const std::vector<int> &connectToNeighborsVi,
const VCGPolyMesh &tileInto)
{
std::shared_ptr<PatternGeometry> pTiledPattern(new PatternGeometry);
//Compute the barycentric coords of the verts in the base triangle pattern
std::vector<CoordType> barycentricCoordinates(pattern.VN());
for (int vi = 0; vi < pattern.VN(); vi++) {
CoordType barycentricCoords_vi;
vcg::InterpolationParameters<vcg::Triangle3<double>, 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<VCGTriMesh>::AddVertex(tileIntoEdgeMesh,
centerOfFace,
vcg::Color4b::Yellow);
std::vector<int> firstInFanConnectToNeighbor_vi(connectToNeighborsVi);
for (int &vi : firstInFanConnectToNeighbor_vi) {
vi += pTiledPattern->VN();
}
for (size_t vi = 0; vi < f.VN(); vi++) {
std::vector<vcg::Point3d> meshTrianglePoints{centerOfFace,
f.cP(vi),
vi + 1 == f.VN() ? f.cP(0)
: f.cP(vi + 1)};
auto fit = vcg::tri::Allocator<VCGTriMesh>::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<PatternGeometry, PatternGeometry>::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<PatternGeometry>::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<PatternGeometry>::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<PatternGeometry>::CompactEveryVector(*pTiledPattern);
pTiledPattern->updateEigenEdgeAndVertices();
return pTiledPattern;
}
void createFan(const std::vector<int> &connectToNeighborsVi=std::vector<int>(), const size_t &fanSize=6);
};
#endif // FLATPATTERNGEOMETRY_HPP