Optimize endpoint face generation
parent
0ae6426587
commit
3af98c5334
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue