Fixing Cut numerical issues on 45 degree rotated cube and

on 90 degree rotated cylinder.
This commit is contained in:
Vojtech Bubnik 2022-12-06 11:44:56 +01:00
parent 7309c729e0
commit 96ab500a13
4 changed files with 80 additions and 9 deletions

View File

@ -738,6 +738,13 @@ void its_flip_triangles(indexed_triangle_set &its)
std::swap(face(1), face(2)); std::swap(face(1), face(2));
} }
int its_num_degenerate_faces(const indexed_triangle_set &its)
{
return std::count_if(its.indices.begin(), its.indices.end(), [](auto &face) {
return face(0) == face(1) || face(0) == face(2) || face(1) == face(2);
});
}
int its_remove_degenerate_faces(indexed_triangle_set &its, bool shrink_to_fit) int its_remove_degenerate_faces(indexed_triangle_set &its, bool shrink_to_fit)
{ {
auto it = std::remove_if(its.indices.begin(), its.indices.end(), [](auto &face) { auto it = std::remove_if(its.indices.begin(), its.indices.end(), [](auto &face) {

View File

@ -204,6 +204,8 @@ void its_flip_triangles(indexed_triangle_set &its);
// or more than two faces share the same edge position! // or more than two faces share the same edge position!
int its_merge_vertices(indexed_triangle_set &its, bool shrink_to_fit = true); int its_merge_vertices(indexed_triangle_set &its, bool shrink_to_fit = true);
// Calculate number of degenerate faces. There should be no degenerate faces in a nice mesh.
int its_num_degenerate_faces(const indexed_triangle_set &its);
// Remove degenerate faces, return number of faces removed. // Remove degenerate faces, return number of faces removed.
int its_remove_degenerate_faces(indexed_triangle_set &its, bool shrink_to_fit = true); int its_remove_degenerate_faces(indexed_triangle_set &its, bool shrink_to_fit = true);

View File

@ -242,7 +242,12 @@ static FacetSliceType slice_facet(
std::swap(a, b); std::swap(a, b);
} }
IntersectionPoint &point = points[num_points]; IntersectionPoint &point = points[num_points];
double t = (double(slice_z) - double(b->z())) / (double(a->z()) - double(b->z())); double t = (double(slice_z) - double(a->z())) / (double(b->z()) - double(a->z()));
#if 0
// If the intersection point falls into one of the end points, mark it with the end point identifier.
// While this sounds like a good idea, it likely breaks the chaining by logical addresses of the intersection points
// and the branch for 0 < t < 1 does not guarantee uniqness of the interection point anyways.
// Thus this branch is only kept for reference and it is not used in production code.
if (t <= 0.) { if (t <= 0.) {
if (point_on_layer == size_t(-1) || points[point_on_layer].point_id != a_id) { if (point_on_layer == size_t(-1) || points[point_on_layer].point_id != a_id) {
point.x() = a->x(); point.x() = a->x();
@ -258,11 +263,26 @@ static FacetSliceType slice_facet(
point.point_id = b_id; point.point_id = b_id;
} }
} else { } else {
point.x() = coord_t(floor(double(b->x()) + (double(a->x()) - double(b->x())) * t + 0.5)); point.x() = coord_t(floor(double(a->x()) + (double(b->x()) - double(a->x())) * t + 0.5));
point.y() = coord_t(floor(double(b->y()) + (double(a->y()) - double(b->y())) * t + 0.5)); point.y() = coord_t(floor(double(a->y()) + (double(b->y()) - double(a->y())) * t + 0.5));
point.edge_id = edge_id; point.edge_id = edge_id;
++ num_points; ++ num_points;
} }
#else
// Just clamp the intersection point to source triangle edge.
if (t <= 0.) {
point.x() = a->x();
point.y() = a->y();
} else if (t >= 1.) {
point.x() = b->x();
point.y() = b->y();
} else {
point.x() = coord_t(floor(double(a->x()) + (double(b->x()) - double(a->x())) * t + 0.5));
point.y() = coord_t(floor(double(a->y()) + (double(b->y()) - double(a->y())) * t + 0.5));
}
point.edge_id = edge_id;
++ num_points;
#endif
} }
} }
@ -284,6 +304,11 @@ static FacetSliceType slice_facet(
assert(line_out.edge_a_id != -1 || line_out.edge_b_id != -1); assert(line_out.edge_a_id != -1 || line_out.edge_b_id != -1);
// General slicing position, use the segment for both slicing and object cutting. // General slicing position, use the segment for both slicing and object cutting.
#if 0 #if 0
// See the discussion on calculating the intersection point on a triangle edge.
// Even if the intersection point is clamped to one of the end points of the triangle edge,
// the intersection point is still marked as "on edge", not "on vertex". Such implementation
// may produce degenerate triangles, but is topologically correct.
// Therefore this block for solving snapping of an intersection edge to triangle vertices is not used.
if (line_out.a_id != -1 && line_out.b_id != -1) { if (line_out.a_id != -1 && line_out.b_id != -1) {
// Solving a degenerate case, where both the intersections snapped to an edge. // Solving a degenerate case, where both the intersections snapped to an edge.
// Correctly classify the face as below or above based on the position of the 3rd point. // Correctly classify the face as below or above based on the position of the 3rd point.
@ -2009,6 +2034,7 @@ static void triangulate_slice(
(l.first.y() == r.first.y() && l.second < r.second))); }); (l.first.y() == r.first.y() && l.second < r.second))); });
// 2) Discover duplicate points on the slice. Remap duplicate vertices to a vertex with a lowest index. // 2) Discover duplicate points on the slice. Remap duplicate vertices to a vertex with a lowest index.
// Remove denegerate triangles, if they happen to be created by merging duplicate vertices.
{ {
std::vector<int> map_duplicate_vertex(int(its.vertices.size()) - num_original_vertices, -1); std::vector<int> map_duplicate_vertex(int(its.vertices.size()) - num_original_vertices, -1);
int i = 0; int i = 0;
@ -2031,10 +2057,20 @@ static void triangulate_slice(
i = j; i = j;
} }
map_vertex_to_index.erase(map_vertex_to_index.begin() + k, map_vertex_to_index.end()); map_vertex_to_index.erase(map_vertex_to_index.begin() + k, map_vertex_to_index.end());
for (stl_triangle_vertex_indices &f : its.indices) for (i = 0; i < int(its.indices.size());) {
for (i = 0; i < 3; ++ i) stl_triangle_vertex_indices &f = its.indices[i];
if (f(i) >= num_original_vertices) // Remap the newly added face vertices.
f(i) = map_duplicate_vertex[f(i) - num_original_vertices]; for (k = 0; k < 3; ++ k)
if (f(k) >= num_original_vertices)
f(k) = map_duplicate_vertex[f(k) - num_original_vertices];
if (f(0) == f(1) || f(0) == f(2) || f(1) == f(2)) {
// Remove degenerate face.
f = its.indices.back();
its.indices.pop_back();
} else
// Keep the face.
++ i;
}
} }
if (triangulate) { if (triangulate) {
@ -2108,6 +2144,10 @@ void cut_mesh(const indexed_triangle_set &mesh, float z, indexed_triangle_set *u
if (upper == nullptr && lower == nullptr) if (upper == nullptr && lower == nullptr)
return; return;
#ifndef NDEBUG
const size_t had_degenerate_faces = its_num_degenerate_faces(mesh);
#endif // NDEBUG
BOOST_LOG_TRIVIAL(trace) << "cut_mesh - slicing object"; BOOST_LOG_TRIVIAL(trace) << "cut_mesh - slicing object";
if (upper) { if (upper) {
@ -2251,8 +2291,27 @@ void cut_mesh(const indexed_triangle_set &mesh, float z, indexed_triangle_set *u
new_face(lower, iv0, iv0v1_lower, iv2v0_lower); new_face(lower, iv0, iv0v1_lower, iv2v0_lower);
} }
} }
/*
char buf[2048];
static int irun = 0;
++irun;
temp.indices.emplace_back(int(temp.vertices.size()), int(temp.vertices.size() + 1), int(temp.vertices.size() + 2));
temp.vertices.emplace_back(vertices[0]);
temp.vertices.emplace_back(vertices[1]);
temp.vertices.emplace_back(vertices[2]);
sprintf(buf, "D:\\temp\\test\\temp-%d.obj", irun);
its_write_obj(temp, buf);
sprintf(buf, "D:\\temp\\test\\upper-%d.obj", irun);
its_write_obj(*upper, buf);
sprintf(buf, "D:\\temp\\test\\lower-%d.obj", irun);
its_write_obj(*lower, buf);
*/
} }
assert(had_degenerate_faces || ! upper || its_num_degenerate_faces(*upper) == 0);
assert(had_degenerate_faces || ! lower || its_num_degenerate_faces(*lower) == 0);
if (upper != nullptr) { if (upper != nullptr) {
triangulate_slice(*upper, upper_lines, upper_slice_vertices, int(mesh.vertices.size()), z, triangulate_caps, NORMALS_DOWN); triangulate_slice(*upper, upper_lines, upper_slice_vertices, int(mesh.vertices.size()), z, triangulate_caps, NORMALS_DOWN);
#ifndef NDEBUG #ifndef NDEBUG
@ -2272,6 +2331,9 @@ void cut_mesh(const indexed_triangle_set &mesh, float z, indexed_triangle_set *u
} }
#endif // NDEBUG #endif // NDEBUG
} }
assert(had_degenerate_faces || ! upper || its_num_degenerate_faces(*upper) == 0);
assert(had_degenerate_faces || ! lower || its_num_degenerate_faces(*lower) == 0);
} }
} // namespace Slic3r } // namespace Slic3r

View File

@ -130,6 +130,6 @@ void cut_mesh(
indexed_triangle_set *lower, indexed_triangle_set *lower,
bool triangulate_caps = true); bool triangulate_caps = true);
} } // namespace Slic3r
#endif // slic3r_TriangleMeshSlicer_hpp_ #endif // slic3r_TriangleMeshSlicer_hpp_