diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp index 2c35c76a2..4a1039b56 100644 --- a/src/libslic3r/TriangleMesh.cpp +++ b/src/libslic3r/TriangleMesh.cpp @@ -779,6 +779,69 @@ std::vector create_face_neighbors_index(const indexed_triangle_set &its, return create_face_neighbors_index_impl(its, throw_on_cancel_callback); } +// Merge duplicate vertices, return number of vertices removed. +int its_merge_vertices(indexed_triangle_set &its, bool shrink_to_fit) +{ + // 1) Sort indices to vertices lexicographically by coordinates AND vertex index. + auto sorted = reserve_vector(its.vertices.size()); + for (int i = 0; i < int(its.vertices.size()); ++ i) + sorted.emplace_back(i); + std::sort(sorted.begin(), sorted.end(), [&its](int il, int ir) { + const Vec3f &l = its.vertices[il]; + const Vec3f &r = its.vertices[ir]; + // Sort lexicographically by coordinates AND vertex index. + return l.x() < r.x() || (l.x() == r.x() && (l.y() < r.y() || (l.y() == r.y() && (l.z() < r.z() || (l.z() == r.z() && il < ir))))); + }); + + // 2) Map duplicate vertices to the one with the lowest vertex index. + // The vertex to stay will have a map_vertices[...] == -1 index assigned, the other vertices will point to it. + std::vector map_vertices(its.vertices.size(), -1); + for (int i = 0; i < int(sorted.size());) { + const int u = sorted[i]; + const Vec3f &p = its.vertices[u]; + int j = i; + for (++ j; j < int(sorted.size()); ++ j) { + const int v = sorted[j]; + const Vec3f &q = its.vertices[v]; + if (p != q) + break; + assert(v > u); + map_vertices[v] = u; + } + i = j; + } + + // 3) Shrink its.vertices, update map_vertices with the new vertex indices. + int k = 0; + for (int i = 0; i < int(its.vertices.size()); ++ i) { + if (map_vertices[i] == -1) { + map_vertices[i] = k; + if (k < i) + its.vertices[k] = its.vertices[i]; + ++ k; + } else { + assert(map_vertices[i] < i); + map_vertices[i] = map_vertices[map_vertices[i]]; + } + } + + int num_erased = int(its.vertices.size()) - k; + + if (num_erased) { + // Shrink the vertices. + its.vertices.erase(its.vertices.begin() + k, its.vertices.end()); + // Remap face indices. + for (stl_triangle_vertex_indices &face : its.indices) + for (int i = 0; i < 3; ++ i) + face(i) = map_vertices[face(i)]; + // Optionally shrink to fit (reallocate) vertices. + if (shrink_to_fit) + its.vertices.shrink_to_fit(); + } + + return num_erased; +} + int its_remove_degenerate_faces(indexed_triangle_set &its, bool shrink_to_fit) { int last = 0; diff --git a/src/libslic3r/TriangleMesh.hpp b/src/libslic3r/TriangleMesh.hpp index 2be822350..5d3c15ec1 100644 --- a/src/libslic3r/TriangleMesh.hpp +++ b/src/libslic3r/TriangleMesh.hpp @@ -98,10 +98,19 @@ std::vector> create_vertex_faces_index(const indexed_triangl // Used for chaining slice lines into polygons. std::vector create_face_neighbors_index(const indexed_triangle_set &its); std::vector create_face_neighbors_index(const indexed_triangle_set &its, std::function throw_on_cancel_callback); + +// Merge duplicate vertices, return number of vertices removed. +// This function will happily create non-manifolds if more than two faces share the same vertex position +// or more than two faces share the same edge position! +int its_merge_vertices(indexed_triangle_set &its, bool shrink_to_fit = true); + // Remove degenerate faces, return number of faces removed. int its_remove_degenerate_faces(indexed_triangle_set &its, bool shrink_to_fit = true); + // Remove vertices, which none of the faces references. Return number of freed vertices. int its_compactify_vertices(indexed_triangle_set &its, bool shrink_to_fit = true); + +// Shrink the vectors of its.vertices and its.faces to a minimum size by reallocating the two vectors. void its_shrink_to_fit(indexed_triangle_set &its); TriangleMesh make_cube(double x, double y, double z); diff --git a/src/libslic3r/TriangleMeshSlicer.cpp b/src/libslic3r/TriangleMeshSlicer.cpp index e7a85e3c5..7d0c2516c 100644 --- a/src/libslic3r/TriangleMeshSlicer.cpp +++ b/src/libslic3r/TriangleMeshSlicer.cpp @@ -1057,6 +1057,10 @@ std::vector slice_mesh( std::vector lines; { + //FIXME facets_edges is likely not needed and quite costly to calculate. + // Instead of edge identifiers, one shall use a sorted pair of edge vertex indices. + // However facets_edges assigns a single edge ID to two triangles only, thus when factoring facets_edges out, one will have + // to make sure that no code relies on it. std::vector facets_edges = create_face_neighbors_index(mesh); const bool identity = params.trafo.matrix() == Transform3d::Identity().matrix(); static constexpr const double s = 1. / SCALING_FACTOR; @@ -1165,6 +1169,9 @@ std::vector slice_mesh_ex( const auto this_mode = layer_id < params.slicing_mode_normal_below_layer ? params.mode_below : params.mode; if (this_mode == MeshSlicingParams::SlicingMode::PositiveLargestContour) keep_largest_contour_only(expolygons); + if (params.resolution != 0.) + for (ExPolygon &ex : expolygons) + ex.simplify(params.resolution); } }); // BOOST_LOG_TRIVIAL(debug) << "slice_mesh make_expolygons in parallel - end"; @@ -1199,7 +1206,9 @@ static void triangulate_slice( { std::vector map_duplicate_vertex(int(its.vertices.size()) - num_original_vertices, -1); int i = 0; + int k = 0; for (; i < int(map_vertex_to_index.size()); ++ i) { + map_vertex_to_index[k ++] = map_vertex_to_index[i]; const Vec2f &ipos = map_vertex_to_index[i].first; const int iidx = map_vertex_to_index[i].second; if (iidx >= num_original_vertices) @@ -1214,6 +1223,7 @@ static void triangulate_slice( map_duplicate_vertex[jidx - num_original_vertices] = iidx; } } + 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 < 3; ++ i) if (f(i) >= num_original_vertices) diff --git a/src/libslic3r/TriangleMeshSlicer.hpp b/src/libslic3r/TriangleMeshSlicer.hpp index 56ad3d9bf..4ae972d00 100644 --- a/src/libslic3r/TriangleMeshSlicer.hpp +++ b/src/libslic3r/TriangleMeshSlicer.hpp @@ -36,7 +36,7 @@ struct MeshSlicingParamsEx : public MeshSlicingParams float closing_radius { 0 }; // Positive offset applied when creating output expolygons. float extra_offset { 0 }; - // Resolution for contour simplification. + // Resolution for contour simplification, scaled! // 0 = don't simplify. double resolution { 0 }; };