Optimize endpoint face generation

master
huxingyi 2020-10-18 22:12:47 +09:30
parent 0ae6426587
commit 3af98c5334
5 changed files with 157 additions and 11 deletions

View File

@ -538,6 +538,9 @@ HEADERS += src/fileforever.h
SOURCES += src/partpreviewimagesgenerator.cpp
HEADERS += src/partpreviewimagesgenerator.h
SOURCES += src/remeshhole.cpp
HEADERS += src/remeshhole.h
SOURCES += src/main.cpp
HEADERS += src/version.h

108
src/remeshhole.cpp Normal file
View File

@ -0,0 +1,108 @@
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/boost/graph/graph_traits_Surface_mesh.h>
#include <CGAL/Polygon_mesh_processing/remesh.h>
#include <CGAL/Polygon_mesh_processing/border.h>
#include <CGAL/Polygon_mesh_processing/repair.h>
#include <CGAL/Polygon_mesh_processing/triangulate_faces.h>
#include <boost/function_output_iterator.hpp>
#include "remeshhole.h"
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
typedef Kernel::Point_3 Point;
typedef CGAL::Surface_mesh<Kernel::Point_3> Mesh;
typedef boost::graph_traits<Mesh>::halfedge_descriptor halfedge_descriptor;
typedef boost::graph_traits<Mesh>::edge_descriptor edge_descriptor;
typedef boost::graph_traits<Mesh>::vertex_iterator vertex_iterator;
typedef boost::graph_traits<Mesh>::vertex_descriptor vertex_descriptor;
struct halfedge2edge
{
halfedge2edge(const Mesh& m, std::vector<edge_descriptor>& edges)
: m_mesh(m), m_edges(edges)
{}
void operator()(const halfedge_descriptor& h) const
{
m_edges.push_back(edge(h, m_mesh));
}
const Mesh& m_mesh;
std::vector<edge_descriptor>& m_edges;
};
void remeshHole(std::vector<QVector3D> &vertices,
const std::vector<size_t> &hole,
std::vector<std::vector<size_t>> &newFaces)
{
if (hole.empty())
return;
Mesh mesh;
double targetEdgeLength = 0;
for (size_t i = 1; i < hole.size(); ++i) {
targetEdgeLength += (vertices[hole[i - 1]] - vertices[hole[i]]).length();
}
targetEdgeLength /= hole.size();
std::vector<typename CGAL::Surface_mesh<typename Kernel::Point_3>::Vertex_index> meshFace;
std::vector<size_t> originalIndices;
originalIndices.reserve(hole.size());
for (const auto &v: hole) {
originalIndices.push_back(v);
const auto &position = vertices[v];
meshFace.push_back(mesh.add_vertex(Point(position.x(), position.y(), position.z())));
}
mesh.add_face(meshFace);
std::vector<edge_descriptor> border;
CGAL::Polygon_mesh_processing::triangulate_faces(mesh);
CGAL::Polygon_mesh_processing::border_halfedges(faces(mesh),
mesh,
boost::make_function_output_iterator(halfedge2edge(mesh, border)));
auto ecm = mesh.add_property_map<edge_descriptor, bool>("ecm").first;
for (edge_descriptor e: border)
ecm[e] = true;
Mesh::Property_map<Mesh::Vertex_index, size_t> meshPropertyMap;
bool created;
boost::tie(meshPropertyMap, created) = mesh.add_property_map<Mesh::Vertex_index, size_t>("v:source", 0);
size_t vertexIndex = 0;
for (auto vertexIt = mesh.vertices_begin(); vertexIt != mesh.vertices_end(); vertexIt++) {
meshPropertyMap[*vertexIt] = originalIndices[vertexIndex++];
}
unsigned int nb_iter = 3;
CGAL::Polygon_mesh_processing::isotropic_remeshing(faces(mesh),
targetEdgeLength,
mesh,
CGAL::Polygon_mesh_processing::parameters::number_of_iterations(nb_iter)
.protect_constraints(true)
.edge_is_constrained_map(ecm));
for (auto vertexIt = mesh.vertices_begin() + vertexIndex; vertexIt != mesh.vertices_end(); vertexIt++) {
auto point = mesh.point(*vertexIt);
originalIndices.push_back(vertices.size());
vertices.push_back(QVector3D(
CGAL::to_double(point.x()),
CGAL::to_double(point.y()),
CGAL::to_double(point.z())
));
meshPropertyMap[*vertexIt] = originalIndices[vertexIndex++];
}
for (const auto &faceIt: mesh.faces()) {
CGAL::Vertex_around_face_iterator<Mesh> vbegin, vend;
std::vector<size_t> faceIndices;
for (boost::tie(vbegin, vend) = CGAL::vertices_around_face(mesh.halfedge(faceIt), mesh);
vbegin != vend;
++vbegin) {
faceIndices.push_back(meshPropertyMap[*vbegin]);
}
newFaces.push_back(faceIndices);
}
}

9
src/remeshhole.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef DUST3D_REMESH_HOLE_H
#define DUST3D_REMESH_HOLE_H
#include <QVector3D>
void remeshHole(std::vector<QVector3D> &vertices,
const std::vector<size_t> &hole,
std::vector<std::vector<size_t>> &newFaces);
#endif

View File

@ -5,6 +5,7 @@
#include "meshstitcher.h"
#include "util.h"
#include "boxmesh.h"
#include "remeshhole.h"
size_t StrokeMeshBuilder::Node::nextOrNeighborOtherThan(size_t neighborIndex) const
{
@ -230,7 +231,6 @@ void StrokeMeshBuilder::buildMesh()
return;
}
std::vector<std::vector<size_t>> cuts;
for (size_t i = 0; i < m_nodeIndices.size(); ++i) {
auto &node = m_nodes[m_nodeIndices[i]];
if (!qFuzzyIsNull(node.cutRotation)) {
@ -243,16 +243,18 @@ void StrokeMeshBuilder::buildMesh()
node.traverseDirection, node.baseNormal);
std::vector<size_t> cut;
insertCutVertices(cutVertices, &cut, node.index, node.traverseDirection);
cuts.push_back(cut);
m_cuts.push_back(cut);
}
}
// Stich cuts
void StrokeMeshBuilder::stitchCuts()
{
for (size_t i = m_isRing ? 0 : 1; i < m_nodeIndices.size(); ++i) {
size_t h = (i + m_nodeIndices.size() - 1) % m_nodeIndices.size();
const auto &nodeH = m_nodes[m_nodeIndices[h]];
const auto &nodeI = m_nodes[m_nodeIndices[i]];
const auto &cutH = cuts[h];
auto reversedCutI = edgeloopFlipped(cuts[i]);
const auto &cutH = m_cuts[h];
auto reversedCutI = edgeloopFlipped(m_cuts[i]);
std::vector<std::pair<std::vector<size_t>, QVector3D>> edgeLoops = {
{cutH, -nodeH.traverseDirection},
{reversedCutI, nodeI.traverseDirection},
@ -267,7 +269,7 @@ void StrokeMeshBuilder::buildMesh()
// Fill endpoints
if (!m_isRing) {
if (cuts.size() < 2)
if (m_cuts.size() < 2)
return;
if (!qFuzzyIsNull(m_hollowThickness)) {
// Generate mesh for hollow
@ -293,8 +295,8 @@ void StrokeMeshBuilder::buildMesh()
m_generatedFaces.push_back(newFace);
}
std::vector<std::vector<size_t>> revisedCuts = {cuts[0],
edgeloopFlipped(cuts[cuts.size() - 1])};
std::vector<std::vector<size_t>> revisedCuts = {m_cuts[0],
edgeloopFlipped(m_cuts[m_cuts.size() - 1])};
for (const auto &cut: revisedCuts) {
for (size_t i = 0; i < cut.size(); ++i) {
size_t j = (i + 1) % cut.size();
@ -307,8 +309,28 @@ void StrokeMeshBuilder::buildMesh()
}
}
} else {
m_generatedFaces.push_back(cuts[0]);
m_generatedFaces.push_back(edgeloopFlipped(cuts[cuts.size() - 1]));
if (m_cuts[0].size() <= 4) {
m_generatedFaces.push_back(m_cuts[0]);
m_generatedFaces.push_back(edgeloopFlipped(m_cuts[m_cuts.size() - 1]));
} else {
auto remeshAndAddCut = [&](const std::vector<size_t> &inputFace) {
std::vector<std::vector<size_t>> remeshedFaces;
size_t oldVertexCount = m_generatedVertices.size();
remeshHole(m_generatedVertices,
inputFace,
remeshedFaces);
size_t oldIndex = inputFace[0];
for (size_t i = oldVertexCount; i < m_generatedVertices.size(); ++i) {
m_generatedVerticesCutDirects.push_back(m_generatedVerticesCutDirects[oldIndex]);
m_generatedVerticesSourceNodeIndices.push_back(m_generatedVerticesSourceNodeIndices[oldIndex]);
m_generatedVerticesInfos.push_back(m_generatedVerticesInfos[oldIndex]);
}
for (const auto &it: remeshedFaces)
m_generatedFaces.push_back(it);
};
remeshAndAddCut(m_cuts[0]);
remeshAndAddCut(edgeloopFlipped(m_cuts[m_cuts.size() - 1]));
}
}
}
}
@ -722,5 +744,6 @@ bool StrokeMeshBuilder::build()
buildMesh();
applyDeform();
stitchCuts();
return true;
}

View File

@ -96,6 +96,8 @@ private:
std::vector<GeneratedVertexInfo> m_generatedVerticesInfos;
std::vector<std::vector<size_t>> m_generatedFaces;
std::vector<std::vector<size_t>> m_cuts;
bool prepare();
std::vector<QVector3D> makeCut(const QVector3D &cutCenter,
float radius,
@ -116,6 +118,7 @@ private:
std::vector<size_t> edgeloopFlipped(const std::vector<size_t> &edgeLoop);
void reviseNodeBaseNormal(Node &node);
void applyDeform();
void stitchCuts();
};
#endif