333 lines
17 KiB
C++
Executable File
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 ©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<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
|