MySources/topologyenumerator.cpp

804 lines
39 KiB
C++
Executable File

#include "topologyenumerator.hpp"
#include <algorithm>
#include <boost/graph/biconnected_components.hpp>
#include <iostream>
#include <math.h>
#include <numeric>
#include <unordered_set>
const bool debugIsOn{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<vcg::Point3d> vertices,
// const std::filesystem::path &savePath) const {
// const std::string allOnes(patternTopology.getNumberOfPossibleEdges(), '1');
// const std::vector<vcg::Point2i> allEdges =
// TrianglePatternTopology::convertToEdges(allOnes, vertices.size());
// TrianglePatternGeometry labelMesh;
// std::vector<vcg::Point3d> 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<size_t> &reducedNumberOfNodesPerSlot,
const std::string &desiredResultsPath,
const int &numberOfDesiredEdges)
{
assert(reducedNumberOfNodesPerSlot.size() == 5);
assert(reducedNumberOfNodesPerSlot[0] == 0 || reducedNumberOfNodesPerSlot[0] == 1);
assert(reducedNumberOfNodesPerSlot[1] == 0 || reducedNumberOfNodesPerSlot[1] == 1);
std::vector<size_t> 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<vcg::Point2i> 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);
}
PatternGeometry patternGeometryAllEdges;
patternGeometryAllEdges.add(numberOfNodesPerSlot, allPossibleEdges);
// Create Results path
auto resultPath = std::filesystem::path(desiredResultsPath);
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(PatternGeometry().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.save(
std::filesystem::path(resultsPath).append("allPossibleEdges.ply").string());
}
// statistics.numberOfPossibleEdges = numberOfAllPossibleEdges;
std::vector<vcg::Point2i> validEdges = getValidEdges(numberOfNodesPerSlot,
resultsPath,
patternGeometryAllEdges,
allPossibleEdges);
PatternGeometry patternAllValidEdges;
patternAllValidEdges.add(patternGeometryAllEdges.getVertices(), validEdges);
if (debugIsOn) {
// Export all valid edges in a ply
patternAllValidEdges.save(
std::filesystem::path(resultsPath).append("allValidEdges.ply").string());
}
// statistics.numberOfValidEdges = validEdges.size();
// Find pairs of intersecting edges
const std::unordered_map<size_t, std::unordered_set<size_t>> 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++) {
PatternGeometry intersectingEdgePair;
const size_t ei0 = mapIt->first;
const size_t ei1 = *setIt;
vcg::tri::Allocator<PatternGeometry>::AddEdge(
intersectingEdgePair,
patternGeometryAllEdges.getVertices()[validEdges[ei0][0]],
patternGeometryAllEdges.getVertices()[validEdges[ei0][1]]);
vcg::tri::Allocator<PatternGeometry>::AddEdge(
intersectingEdgePair,
patternGeometryAllEdges.getVertices()[validEdges[ei1][0]],
patternGeometryAllEdges.getVertices()[validEdges[ei1][1]]);
intersectingEdgePair.save(std::filesystem::path(intersectingEdgesPath)
.append(std::to_string(mapIt->first) + "_"
+ std::to_string(*setIt) + ".ply")
.string());
}
}
}
const std::unordered_set<VertexIndex> interfaceNodes = patternGeometryAllEdges.getInterfaceNodes(
numberOfNodesPerSlot);
// assert(validEdges.size() == allPossibleEdges.size() -
// coincideEdges.size() -
// duplicateEdges.size());
// PatternSet patternSet;
// const std::vector<vcg::Point3d> 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::Point3d(nodes[nodeIndex][0], nodes[nodeIndex][1],0);
// }
// if (std::filesystem::exists(std::filesystem::path(resultsPath)
// .append("patterns.patt")
// .string())) {
// std::filesystem::remove(
// std::filesystem::path(resultsPath).append("patterns.patt"));
// }
if (numberOfDesiredEdges == -1) {
for (size_t numberOfEdges = 2; numberOfEdges <= validEdges.size(); 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)) {
// if (debugIsOn) {
std::filesystem::remove_all(perEdgeResultPath);
// } else {
// continue;
// }
}
std::filesystem::create_directory(perEdgeResultPath);
computeValidPatterns(numberOfNodesPerSlot,
numberOfEdges,
perEdgeResultPath,
patternGeometryAllEdges.getVertices(),
intersectingEdges,
validEdges,
interfaceNodes);
statistics.print(setupString, perEdgeResultPath);
statistics.reset();
}
} else {
std::cout << "Computing " + setupString << " with " << numberOfDesiredEdges << " edges."
<< std::endl;
auto perEdgeResultPath = std::filesystem::path(resultsPath)
.append(std::to_string(numberOfDesiredEdges));
if (std::filesystem::exists(perEdgeResultPath)) {
// return;
std::filesystem::remove_all(perEdgeResultPath);
}
std::filesystem::create_directory(perEdgeResultPath);
computeValidPatterns(numberOfNodesPerSlot,
numberOfDesiredEdges,
perEdgeResultPath,
patternGeometryAllEdges.getVertices(),
intersectingEdges,
validEdges,
interfaceNodes);
statistics.print(setupString, perEdgeResultPath);
}
}
void TopologyEnumerator::computeEdgeNodes(const std::vector<size_t> &numberOfNodesPerSlot,
std::vector<size_t> &nodesEdge0,
std::vector<size_t> &nodesEdge1,
std::vector<size_t> &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<size_t> TopologyEnumerator::computeCoincideEdges(
const std::vector<size_t> &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<size_t> nodesEdge0; // left edge
std::vector<size_t> nodesEdge1; // bottom edge
std::vector<size_t> nodesEdge2; // right edge
computeEdgeNodes(numberOfNodesPerSlot, nodesEdge0, nodesEdge1, nodesEdge2);
std::vector<size_t> coincideEdges0 = getCoincideEdges(nodesEdge0);
std::vector<size_t> coincideEdges1 = getCoincideEdges(nodesEdge1);
std::vector<size_t> coincideEdges2 = getCoincideEdges(nodesEdge2);
std::unordered_set<size_t> 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<size_t> TopologyEnumerator::computeDuplicateEdges(
const std::vector<size_t> &numberOfNodesPerSlot)
{
/*
* A duplicate edges are all edges the "right" edge since due to rotational
* symmetry "left" edge=="right" edge
* */
std::unordered_set<size_t> duplicateEdges;
std::vector<size_t> nodesEdge0; // left edge
std::vector<size_t> nodesEdge1; // bottom edge
std::vector<size_t> 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<vcg::Point2i> TopologyEnumerator::getValidEdges(
const std::vector<size_t> &numberOfNodesPerSlot,
const std::filesystem::path &resultsPath,
const PatternGeometry &patternGeometryAllEdges,
const std::vector<vcg::Point2i> &allPossibleEdges)
{
std::unordered_set<size_t> 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) {
PatternGeometry::EdgeType e = patternGeometryAllEdges.edge[coincideEdgeIndex];
PatternGeometry singleEdgeMesh;
vcg::Point3d p0 = e.cP(0);
vcg::Point3d p1 = e.cP(1);
std::vector<vcg::Point3d> edgeVertices;
edgeVertices.push_back(p0);
edgeVertices.push_back(p1);
singleEdgeMesh.add(edgeVertices);
singleEdgeMesh.add(std::vector<vcg::Point2i>{vcg::Point2i{0, 1}});
singleEdgeMesh.save(std::filesystem::path(coincideEdgesPath)
.append(std::to_string(coincideEdgeIndex))
.string()
+ ".ply");
}
}
statistics.numberOfCoincideEdges = coincideEdges.size();
// Compute duplicate edges
std::unordered_set<size_t> 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);
PatternGeometry patternDuplicateEdges;
for (auto duplicateEdgeIndex : duplicateEdges) {
PatternGeometry::EdgeType e = patternGeometryAllEdges.edge[duplicateEdgeIndex];
vcg::Point3d p0 = e.cP(0);
vcg::Point3d p1 = e.cP(1);
vcg::tri::Allocator<PatternGeometry>::AddEdge(patternDuplicateEdges, p0, p1);
}
patternDuplicateEdges.save(
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<vcg::Point2i> 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::exportPattern(const std::filesystem::path &saveToPath,
PatternGeometry &patternGeometry,
const bool saveTilledPattern) const
{
const std::string patternName = patternGeometry.getLabel();
std::filesystem::create_directory(saveToPath);
patternGeometry.save(std::filesystem::path(saveToPath).append(patternName).string() + ".ply");
if (saveTilledPattern) {
PatternGeometry tiledPatternGeometry = PatternGeometry::createTile(patternGeometry);
tiledPatternGeometry.save(
std::filesystem::path(saveToPath).append(patternName + "_tiled").string() + ".ply");
}
}
void TopologyEnumerator::computeValidPatterns(
const std::vector<size_t> &numberOfNodesPerSlot,
const size_t &numberOfDesiredEdges,
const std::filesystem::path &resultsPath,
const std::vector<vcg::Point3d> &allVertices,
const std::unordered_map<size_t, std::unordered_set<size_t>> &intersectingEdges,
const std::vector<vcg::Point2i> &validEdges,
const std::unordered_set<VertexIndex> &interfaceNodes)
{
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
const auto validPatternsPath = std::filesystem::path(resultsPath).append("Valid");
const bool validPathCreatedSuccesfully = std::filesystem::create_directories(validPatternsPath);
assert(validPathCreatedSuccesfully && std::filesystem::exists(validPatternsPath));
// std::ofstream validPatternsFileStream;
// validPatternsFileStream.open(
// validPatternsPath.append("patterns.patt").string());
const std::string compressedPatternsFilePath
= std::filesystem::path(validPatternsPath).append("patterns.patt").string();
PatternIO::PatternSet patternSet;
patternSet.nodes = allVertices;
const int patternSetBufferSize = 10000;
const size_t numberOfPatterns = PatternGeometry::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());
/*TODO: Performance could be improved by changing the patternGeometry with
* respect to the previous one. Maybe I could xor the binaryRepresentation
* to the previous one.*/
// std::string previousPatternBinaryRepresentation(validEdges.size(),'0');
size_t patternIndex = 0;
bool validPatternsExist = false;
const bool exportTilledPattern = true;
const bool saveCompressedFormat = false;
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<vcg::Point2i> 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];
}
}
PatternGeometry patternGeometry;
patternGeometry.add(allVertices, patternEdges);
patternGeometry.setLabel(patternName);
// Check if pattern contains intersecting edges
const bool isInterfaceConnected = patternGeometry.isInterfaceConnected(interfaceNodes);
// Export the tiled ply file if it contains intersecting edges
if (!isInterfaceConnected) {
// create the tiled geometry of the pattern
statistics.numberOfPatternViolatingInterfaceEnforcement++;
if (debugIsOn) {
if (savePlyFiles) {
exportPattern(std::filesystem::path(resultsPath).append("InterfaceEnforcement"),
patternGeometry,
exportTilledPattern);
}
} else {
continue; // should be uncommented in order to improve performance
}
}
// 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) {
exportPattern(std::filesystem::path(resultsPath).append("Intersecting"),
patternGeometry,
exportTilledPattern);
}
} else {
continue; // should be uncommented in order to improve performance
}
}
// const bool shouldBreak = numberOfDesiredEdges == 4 && patternIndex == 53;
const bool tiledPatternHasEdgesWithAngleSmallerThanThreshold
= patternGeometry.hasAngleSmallerThanThreshold(numberOfNodesPerSlot, 15);
if (tiledPatternHasEdgesWithAngleSmallerThanThreshold) {
statistics.numberOfPatternsViolatingAngleThreshold++;
if (debugIsOn /*|| savePlyFiles*/) {
if (savePlyFiles) {
exportPattern(std::filesystem::path(resultsPath)
.append("ExceedingAngleThreshold"),
patternGeometry,
exportTilledPattern);
}
} else {
continue;
}
}
const bool tiledPatternHasNodeWithValenceGreaterThanDesired
= patternGeometry.hasValenceGreaterThan(numberOfNodesPerSlot, 6);
if (tiledPatternHasNodeWithValenceGreaterThanDesired) {
statistics.numberOfPatternsViolatingValenceThreshold++;
if (debugIsOn) {
if (savePlyFiles) {
auto highValencePath = std::filesystem::path(resultsPath)
.append("HighValencePatterns");
exportPattern(highValencePath, patternGeometry, exportTilledPattern);
}
} else {
continue;
}
}
// 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.isFullyConnectedWhenFanned();
PatternGeometry fanPatternGeometry = PatternGeometry::createFan(patternGeometry);
const int interfaceNodeVi = 3;
std::vector<PatternGeometry::EdgeType *> connectedEdges;
vcg::edge::VEStarVE(&fanPatternGeometry.vert[interfaceNodeVi], connectedEdges);
if (!connectedEdges.empty()) {
for (int i = 1; i < 6; i++) {
vcg::tri::Allocator<PatternGeometry>::AddEdge(fanPatternGeometry,
interfaceNodeVi
+ (i - 1) * patternGeometry.VN(),
interfaceNodeVi
+ i * patternGeometry.VN());
}
}
vcg::tri::Clean<PatternGeometry>::MergeCloseVertex(fanPatternGeometry, 0.0000005);
vcg::tri::Allocator<PatternGeometry>::CompactEveryVector(fanPatternGeometry);
vcg::tri::UpdateTopology<PatternGeometry>::VertexEdge(fanPatternGeometry);
vcg::tri::UpdateTopology<PatternGeometry>::EdgeEdge(fanPatternGeometry);
// for (PatternGeometry::VertexType &v : tilledPatternGeometry.vert) {
// std::vector<PatternGeometry::EdgeType *> connectedEdges;
// vcg::edge::VEStarVE(&v, connectedEdges);
// if (connectedEdges.size() == 1) {
// vcg::tri::Allocator<PatternGeometry>::DeleteVertex(tilledPatternGeometry, v);
// vcg::tri::Allocator<PatternGeometry>::DeleteEdge(tilledPatternGeometry,
// *connectedEdges[0]);
// }
// }
// // vcg::tri::Allocator<PatternGeometry>::CompactEveryVector(tilledPatternGeometry);
// fanPatternGeometry.updateEigenEdgeAndVertices();
BoostGraph fanPatternGraph(fanPatternGeometry.VN());
// std::cout << "Edges:";
for (const PatternGeometry::EdgeType &e : fanPatternGeometry.edge) {
if (e.IsD() || e.cV(0)->IsD() || e.cV(1)->IsD()) {
continue;
}
const int vi0 = fanPatternGeometry.getIndex(e.cV(0));
const int vi1 = fanPatternGeometry.getIndex(e.cV(1));
boost::add_edge(vi0, vi1, fanPatternGraph);
// std::cout << vi0 << "," << vi1 << " ";
}
// std::cout << std::endl;
std::vector<vertex_t> articulationPoints;
boost::articulation_points(fanPatternGraph, std::back_inserter(articulationPoints));
const bool hasArticulationPoints = !articulationPoints.empty();
// if (!hasArticulationPoints && tiledPatternHasDanglingEdges) {
// PatternGeometry tilledPatternGeometry = PatternGeometry::createTile(patternGeometry);
// tilledPatternGeometry.updateEigenEdgeAndVertices();
// tilledPatternGeometry.registerForDrawing();
// // ->addNodeColorQuantity("de_noAp_tilled", fanVertexColors)
// // ->setEnabled(true);
// polyscope::show();
// tilledPatternGeometry.unregister();
// }
// if (hasArticulationPoints && !tiledPatternHasDanglingEdges/*&& !patternContainsIntersectingEdges
// && !hasFloatingComponents
// && !tiledPatternHasNodeWithValenceGreaterThanDesired
// && !tiledPatternHasEdgesWithAngleSmallerThanThreshold*/) {
// for (PatternGeometry::VertexType &v : patternGeometry.vert) {
// v.C() = vcg::Color4b::Yellow;
// }
// // std::cout << "AP:";
// for (const int articulationPointVi : articulationPoints) {
// if (articulationPointVi >= patternGeometry.VN()) {
// continue;
// }
// // std::cout << articulationPointVi << " ";
// patternGeometry.vert[articulationPointVi].C() = vcg::Color4b::Red;
// }
// PatternGeometry tilledPatternGeometry = PatternGeometry::createTile(patternGeometry);
// // std::cout << std::endl;
// std::vector<glm::vec3> fanVertexColors(tilledPatternGeometry.VN(), glm::vec3(0, 0, 1));
// for (const PatternGeometry::VertexType &v : tilledPatternGeometry.vert) {
// const auto vColor = glm::vec3(v.cC()[0] / 255, v.cC()[1] / 255, v.cC()[2] / 255);
// const auto vi = tilledPatternGeometry.getIndex(v);
// fanVertexColors[vi] = vColor;
// }
// tilledPatternGeometry.updateEigenEdgeAndVertices();
// tilledPatternGeometry.registerForDrawing()
// ->addNodeColorQuantity("ap_tilled", fanVertexColors)
// ->setEnabled(true);
// polyscope::show();
// tilledPatternGeometry.unregister();
// }
// 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");
exportPattern(danglingEdgesPath, patternGeometry, exportTilledPattern);
}
} 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.save(
std::filesystem::path(moreThanOneCCPath).append(patternName).string()
+ ".ply");
PatternGeometry tiledPatternGeometry = PatternGeometry::createTile(
patternGeometry); // the marked nodes of hasDanglingEdges are
std::vector<std::pair<int, PatternGeometry::EdgePointer>> eCC;
vcg::tri::Clean<PatternGeometry>::edgeMeshConnectedComponents(tiledPatternGeometry,
eCC);
vcg::tri::UpdateFlags<PatternGeometry>::EdgeClear(tiledPatternGeometry);
const size_t numberOfCC_edgeBased = eCC.size();
std::sort(eCC.begin(),
eCC.end(),
[](const std::pair<int, PatternGeometry::EdgePointer> &a,
const std::pair<int, PatternGeometry::EdgePointer> &b) {
return a.first > b.first;
});
PatternGeometry::EdgePointer &ep = eCC[0].second;
size_t colorsRegistered = 0;
std::stack<EdgePointer> stack;
stack.push(ep);
while (!stack.empty()) {
EdgePointer ep = stack.top();
stack.pop();
for (int i = 0; i < 2; ++i) {
vcg::edge::VEIterator<PatternGeometry::EdgeType> vei(ep->V(i));
while (!vei.End()) {
if (!vei.E()->IsV()) {
vei.E()->SetV();
stack.push(vei.E());
tiledPatternGeometry
.vert[tiledPatternGeometry.getIndex(vei.V1())]
.C()
= vcg::Color4b::Blue;
tiledPatternGeometry
.vert[tiledPatternGeometry.getIndex(vei.V0())]
.C()
= vcg::Color4b::Blue;
colorsRegistered++;
}
++vei;
}
}
}
assert(colorsRegistered == eCC[0].first);
if (exportTilledPattern) {
tiledPatternGeometry.save(std::filesystem::path(moreThanOneCCPath)
.append(patternName + "_tiled")
.string()
+ ".ply");
}
}
} else {
continue;
}
}
if (hasArticulationPoints /*&& !hasFloatingComponents && !tiledPatternHasDanglingEdges */) {
statistics.numberOfPatternsWithArticulationPoints++;
if (debugIsOn) {
if (savePlyFiles) {
auto articulationPointsPath = std::filesystem::path(resultsPath)
.append("ArticulationPoints");
exportPattern(articulationPointsPath, patternGeometry, exportTilledPattern);
}
} else {
continue;
}
}
const bool isValidPattern = !patternContainsIntersectingEdges
&& isInterfaceConnected
/*&& !tiledPatternHasDanglingEdges*/
&& !hasFloatingComponents && !hasArticulationPoints
&& !tiledPatternHasNodeWithValenceGreaterThanDesired
&& !tiledPatternHasEdgesWithAngleSmallerThanThreshold;
// if (!hasArticulationPoints && !patternContainsIntersectingEdges
// && !tiledPatternHasDanglingEdges && !hasFloatingComponents
// && !tiledPatternHasNodeWithValenceGreaterThanDesired
// && tiledPatternHasEdgesWithAngleSmallerThanThreshold && numberOfDesiredEdges > 4) {
// std::cout << "Pattern found:" << patternName << std::endl;
// patternGeometry.registerForDrawing();
// polyscope::show();
// patternGeometry.unregister();
// }
if (isValidPattern) {
// if(patternName=='2055'){
// PatternGeometry tiledPatternGeometry = PatternGeometry::createTile(
// patternGeometry); // the marked nodes of hasDanglingEdges are
// tiledPatternGeometry.registerForDrawing(std::array<double, 3>{0, 0, 1});
// polyscope::show();
// tiledPatternGeometry.unregister();
// }
statistics.numberOfValidPatterns++;
validPatternsExist = true;
if (savePlyFiles) {
exportPattern(validPatternsPath, patternGeometry, exportTilledPattern);
}
if (saveCompressedFormat) {
PatternIO::Pattern pattern;
pattern.edges = patternEdges;
pattern.name = patternIndex;
patternSet.patterns.emplace_back(pattern);
// Save valid patterns
// if (patternIndex% patternSetBufferSize == 0) {
if (statistics.numberOfValidPatterns % patternSetBufferSize == 0) {
PatternIO::save(compressedPatternsFilePath, patternSet);
patternSet.patterns.clear();
patternSet.patterns.reserve(patternSetBufferSize);
}
}
}
// assert(vcg_tiledPatternHasDangling == tiledPatternHasDanglingEdges);
} while (std::next_permutation(patternBinaryRepresentation.begin(),
patternBinaryRepresentation.end()));
if (!patternSet.patterns.empty() && saveCompressedFormat) {
PatternIO::save(compressedPatternsFilePath, patternSet);
}
if (!validPatternsExist) {
std::filesystem::remove_all(validPatternsPath);
if (!debugIsOn) {
std::filesystem::remove_all(resultsPath);
}
}
}
std::vector<size_t> TopologyEnumerator::getCoincideEdges(
const std::vector<size_t> &edgeNodeIndices) const
{
std::vector<size_t> 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<vcg::Point2i> &validEdges,
const size_t &numberOfDesiredEdges) const
{
return true;
}