Skip to content

Commit

Permalink
add new program to fix self-intersect mesh
Browse files Browse the repository at this point in the history
  • Loading branch information
nodtem66 committed Mar 13, 2020
1 parent bd093a5 commit 31610ab
Show file tree
Hide file tree
Showing 9 changed files with 462 additions and 175 deletions.
4 changes: 4 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,7 @@ target_link_libraries(${PROJECT_NAME} PRIVATE igl::core DIP tbb_static)
add_executable(SliceTest ${MAIN_SOURCES} ${PROJECT_SOURCE_DIR}/src/SliceTest.cpp)
target_include_directories(SliceTest PRIVATE "${PROJECT_SOURCE_DIR}/include" ${TBB_INCLUDE_DIR} ${VCG_INCLUDE_DIR})
target_link_libraries(SliceTest PRIVATE igl::core tbb_static)

add_executable(Fixer ${MAIN_SOURCES} ${PROJECT_SOURCE_DIR}/src/FixSelfIntersect.cpp ${VCG_INCLUDE_DIR}/wrap/ply/plylib.cpp)
target_include_directories(Fixer PRIVATE "${PROJECT_SOURCE_DIR}/include" ${TBB_INCLUDE_DIR} ${VCG_INCLUDE_DIR})
target_link_libraries(Fixer PRIVATE)
271 changes: 249 additions & 22 deletions include/Mesh.h

Large diffs are not rendered by default.

30 changes: 29 additions & 1 deletion include/OptimalSlice.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,7 @@ namespace slice {
L.resize(grid_size + 2);
for (size_t i = 0; i <= grid_size + 1; i++) L[i].clear();
// foreach triangle in mesh
// TODO: implement parallel version with tbb
#ifndef USE_PARALLEL
for (TMesh::FaceIterator it = mesh.face.begin(); it != mesh.face.end(); it++) {
if (!it->IsD())
{
Expand All @@ -397,6 +397,34 @@ namespace slice {
L[i].push_back(triangle);
}
}
#else
tbb::spin_mutex writeMutex;
static tbb::affinity_partitioner ap;
tbb::parallel_for(
tbb::blocked_range<size_t>(0, mesh.face.size()),
[&](const tbb::blocked_range<size_t> r) {
// Prepare local_L
Layer _L(grid_size + 2);
_L.resize(grid_size + 2);
for (size_t i = 0; i <= grid_size + 1; i++) _L[i].clear();
for (size_t i = r.begin(); i < r.end(); i++) {
if (!mesh.face[i].IsD()) {
Triangle triangle(mesh.face[i]);
size_t level = size_t(ceil((triangle.min[direction] - P[1]) / delta) + 1);
assert(level > 0 && level <= grid_size + 1);
_L[level].push_back(triangle);
}
}
{
tbb::spin_mutex::scoped_lock lock(writeMutex);
for (size_t i = 0; i <= grid_size + 1; i++) {
L[i].reserve(L[i].size() + _L[i].size());
L[i].insert(L[i].end(), _L[i].begin(), _L[i].end());
}
}
}, ap
);
#endif
}

inline Point3d compute_point_at_plane(Point3d v0, Point3d v1, double position, int direction = Direction::Z) {
Expand Down
2 changes: 2 additions & 0 deletions include/ProgressBar.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ class ProgressBar {
unsigned int operator++() { return ++ticks; }
ProgressBar& operator+=(const unsigned int tick) { ticks += tick; return *this; }

void update(const unsigned int tick) { ticks = tick; }

void display() const
{
float progress = (float)ticks / total_ticks;
Expand Down
156 changes: 18 additions & 138 deletions include/Scaffolder_2.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,145 +118,25 @@ inline void marching_cube(TMesh &mesh, Eigen::MatrixXd &Fxyz, Eigen::RowVector3i
}
}

inline void clean_mesh(TMesh& mesh, double minimum_diameter, uint16_t smooth_step, bool verbose = true) {
if (verbose) std::cout << "[libVCG Cleaning] ";
vcg::tri::Clean<TMesh>::RemoveDuplicateVertex(mesh);
vcg::tri::Allocator<TMesh>::CompactEveryVector(mesh);
vcg::tri::UpdateTopology<TMesh>::FaceFace(mesh);
vcg::tri::Clean<TMesh>::RemoveDuplicateFace(mesh);
vcg::tri::UpdateTopology<TMesh>::FaceFace(mesh);
vcg::tri::Clean<TMesh>::RemoveZeroAreaFace(mesh);
vcg::tri::Clean<TMesh>::RemoveUnreferencedVertex(mesh);
vcg::tri::UpdateTopology<TMesh>::FaceFace(mesh);
vcg::tri::UpdateBounding<TMesh>::Box(mesh);
vcg::tri::Clean<TMesh>::RemoveSmallConnectedComponentsDiameter(mesh, minimum_diameter * mesh.bbox.Diag());
vcg::tri::Clean<TMesh>::RemoveUnreferencedVertex(mesh);
vcg::tri::UpdateTopology<TMesh>::FaceFace(mesh);
vcg::tri::UpdateBounding<TMesh>::Box(mesh);
if (verbose) std::cout << "OK" << std::endl;
if (smooth_step > 0) {
if (verbose) std::cout << "[Laplacian smoothing] ";
vcg::tri::Smooth<TMesh>::VertexCoordLaplacian(mesh, smooth_step, false, true);
if (verbose) std::cout << "OK" << std::endl;
inline void mesh_to_eigen_vector(TMesh& mesh, Eigen::MatrixXd& V, Eigen::MatrixXi& F) {
V.resize(mesh.VN(), 3);
size_t i = 0;
std::vector<size_t> vertexId(mesh.vert.size());
for (TMesh::VertexIterator it = mesh.vert.begin(); it != mesh.vert.end(); ++it) if (!it->IsD()) {
vertexId[it - mesh.vert.begin()] = i;
vcg::Point3d point = it->P();
V(i, 0) = point[0];
V(i, 1) = point[1];
V(i, 2) = point[2];
i++;
}
vcg::tri::Clean<TMesh>::MergeCloseVertex(mesh, SLICE_PRECISION*1000);
vcg::tri::Clean<TMesh>::RemoveUnreferencedVertex(mesh);
vcg::tri::Allocator<TMesh>::CompactEveryVector(mesh);
vcg::tri::UpdateTopology<TMesh>::FaceFace(mesh);
}

inline void fix_self_intersect_mesh(TMesh& mesh, double minimum_diameter, uint16_t max_iteration = 10, bool verbose = false) {

std::vector<TMesh::FaceType*> faces;
vcg::tri::Clean<TMesh>::SelfIntersections(mesh, faces);

uint16_t iteration = 0;
int maxSize = mesh.bbox.SquaredDiag();
size_t nf = 0;
while (iteration < max_iteration && (faces.size() > 0 || nf > 0)) {

if (verbose) std::cout << "[Fix Self-intersect face]" << std::endl << " -- Iteration " << iteration + 1 << std::endl;

if (faces.size() > 0) {
for (size_t i = 0; i < faces.size(); i++) {
if (!faces[i]->IsD())
vcg::tri::Allocator<TMesh>::DeleteFace(mesh, *(faces[i]));
}
if (verbose) std::cout << " -- self-intersect faces: " << faces.size() << std::endl;
vcg::tri::Clean<TMesh>::RemoveUnreferencedVertex(mesh);
vcg::tri::Allocator<TMesh>::CompactEveryVector(mesh);
vcg::tri::UpdateTopology<TMesh>::FaceFace(mesh);
vcg::tri::UpdateBounding<TMesh>::Box(mesh);
if (verbose) std::cout << " -- Remove faces [OK]" << std::endl;
vcg::tri::Clean<TMesh>::RemoveSmallConnectedComponentsDiameter(mesh, minimum_diameter * mesh.bbox.Diag());
vcg::tri::Clean<TMesh>::RemoveUnreferencedVertex(mesh);
if (verbose) std::cout << " -- Remove small components " << minimum_diameter * mesh.bbox.Diag() << " [OK]" << std::endl;
vcg::tri::Clean<TMesh>::RemoveNonManifoldFace(mesh);
vcg::tri::UpdateTopology<TMesh>::FaceFace(mesh);
if (verbose) std::cout << " -- Remove non-manifold edges [OK]" << std::endl;
if (vcg::tri::Clean<TMesh>::CountNonManifoldEdgeFF(mesh) > 0) {
std::cout << "[Warning]: Fixed Self-intersecting failed: Mesh has some not 2-manifold edges" << std::endl;
return;
}
vcg::tri::Hole<TMesh>::EarCuttingIntersectionFill<vcg::tri::SelfIntersectionEar<TMesh>>(mesh, maxSize, false);
if (verbose) std::cout << " -- Close holes [OK]" << std::endl;
}

vcg::tri::UpdateFlags<TMesh>::FaceBorderFromNone(mesh);
vcg::tri::UpdateFlags<TMesh>::VertexBorderFromFaceBorder(mesh);
vcg::tri::UpdateSelection<TMesh>::FaceFromBorderFlag(mesh);
vcg::tri::UpdateSelection<TMesh>::VertexFromBorderFlag(mesh);
nf = vcg::tri::UpdateSelection<TMesh>::FaceCount(mesh);
if (nf > 0) {
vcg::tri::UpdateSelection<TMesh>::VertexFromFaceLoose(mesh);
vcg::tri::UpdateSelection<TMesh>::FaceFromVertexLoose(mesh);
vcg::tri::UpdateSelection<TMesh>::VertexClear(mesh);
vcg::tri::UpdateSelection<TMesh>::VertexFromFaceStrict(mesh);
for (TMesh::FaceIterator it = mesh.face.begin(); it != mesh.face.end(); ++it) {
if (!it->IsD() && it->IsS())
vcg::tri::Allocator<TMesh>::DeleteFace(mesh, *it);
}
for (TMesh::VertexIterator it = mesh.vert.begin(); it != mesh.vert.end(); ++it) {
if (!it->IsD() && it->IsS())
vcg::tri::Allocator<TMesh>::DeleteVertex(mesh, *it);
}
vcg::tri::Allocator<TMesh>::CompactEveryVector(mesh);
vcg::tri::UpdateTopology<TMesh>::FaceFace(mesh);
if (verbose) std::cout << " -- Remove Border faces [OK]" << std::endl;
vcg::tri::Clean<TMesh>::RemoveNonManifoldFace(mesh);
vcg::tri::UpdateBounding<TMesh>::Box(mesh);
vcg::tri::UpdateTopology<TMesh>::FaceFace(mesh);
if (verbose) std::cout << " -- Remove non-manifold edges [OK]" << std::endl;
vcg::tri::Hole<TMesh>::EarCuttingIntersectionFill<vcg::tri::SelfIntersectionEar<TMesh>>(mesh, maxSize, false);
if (verbose) std::cout << " -- Close holes [OK]" << std::endl;

vcg::tri::UpdateFlags<TMesh>::FaceBorderFromNone(mesh);
vcg::tri::UpdateFlags<TMesh>::VertexBorderFromFaceBorder(mesh);
vcg::tri::UpdateSelection<TMesh>::FaceFromBorderFlag(mesh);
vcg::tri::UpdateSelection<TMesh>::VertexFromBorderFlag(mesh);
nf = vcg::tri::UpdateSelection<TMesh>::FaceCount(mesh);
// Faces to Eigen matrixXi F1
i = 0;
F.resize(mesh.FN(), mesh.face.begin()->VN());
for (TMesh::FaceIterator it = mesh.face.begin(); it != mesh.face.end(); ++it) if (!it->IsD()) {
for (int k = 0; k < it->VN(); k++) {
F(i, k) = vertexId[vcg::tri::Index(mesh, it->V(k))];
}

vcg::tri::Clean<TMesh>::SelfIntersections(mesh, faces);
iteration++;
}
vcg::tri::Allocator<TMesh>::CompactEveryVector(mesh);

while (iteration < max_iteration && nf > 0) {
if (verbose) std::cout << "[Fix Border Edges and holes]" << std::endl << " -- Iteration " << iteration + 1 << std::endl;



iteration++;
}
vcg::tri::UpdateBounding<TMesh>::Box(mesh);
vcg::tri::UpdateTopology<TMesh>::FaceFace(mesh);
}

inline void report_mesh(TMesh& mesh) {
int connectedComponentsNum = vcg::tri::Clean<TMesh>::CountConnectedComponents(mesh);
std::cout
<< "[Topology Measurement] " << std::endl
<< "-- Mesh is composed by " << connectedComponentsNum << " connected component(s)" << std::endl;

int edgeNum = 0, edgeBorderNum = 0, edgeNonManifoldNum = 0;
vcg::tri::Clean<TMesh>::CountEdgeNum(mesh, edgeNum, edgeBorderNum, edgeNonManifoldNum);
int vertManifNum = vcg::tri::Clean<TMesh>::CountNonManifoldVertexFF(mesh, true);

if (edgeNonManifoldNum == 0 && vertManifNum == 0) {
int holeNum = vcg::tri::Clean<TMesh>::CountHoles(mesh);
int genus = vcg::tri::Clean<TMesh>::MeshGenus(mesh.vn, edgeNum, mesh.fn, holeNum, connectedComponentsNum);

std::cout
<< "-- Mesh is two-manifold " << std::endl
<< "-- Mesh has " << holeNum << " holes" << std::endl
<< "-- Genus is " << genus << std::endl;
i++;
}
}

inline bool is_mesh_manifold(TMesh &mesh) {
int edgeNum = 0, edgeBorderNum = 0, edgeNonManifoldNum = 0;
vcg::tri::Clean<TMesh>::CountEdgeNum(mesh, edgeNum, edgeBorderNum, edgeNonManifoldNum);
int vertManifNum = vcg::tri::Clean<TMesh>::CountNonManifoldVertexFF(mesh, true);
return edgeNonManifoldNum == 0 && vertManifNum == 0;
}
6 changes: 0 additions & 6 deletions include/implicit_function.h
Original file line number Diff line number Diff line change
Expand Up @@ -233,12 +233,6 @@ class Implicit_function : public Function {
}
};

inline void to_lower(std::string& s) {
std::locale loc;
for (std::string::size_type i = 0; i < s.length(); ++i)
s[i] = std::tolower(s[i], loc);
}

Function* isosurface(std::string name, FT t) {
if (name == "empty") {
return new Fixed(1);
Expand Down
10 changes: 9 additions & 1 deletion include/utils.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#pragma once

#include <string>

#ifdef _WIN32
#include <Windows.h>
#include <direct.h>
Expand Down Expand Up @@ -69,7 +71,7 @@ namespace util {

// Find the last dot, if any.
size_t dotIdx = path.find_last_of(".");
if (dotIdx != string::npos)
if (dotIdx != std::string::npos)
{
// Find the last directory separator, if any.
size_t dirSepIdx = path.find_last_of("/\\");
Expand All @@ -86,4 +88,10 @@ namespace util {

return ext;
}

inline void to_lower(std::string& s) {
std::locale loc;
for (std::string::size_type i = 0; i < s.length(); ++i)
s[i] = std::tolower(s[i], loc);
}
}
Loading

0 comments on commit 31610ab

Please sign in to comment.