From e892550cb0378ce9f57d6f418e001b7c2a9ff1a4 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Wed, 19 May 2021 10:08:01 +0200 Subject: [PATCH 1/7] Fix warning of ignored variable in structured binding --- src/slic3r/GUI/Jobs/RotoptimizeJob.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/Jobs/RotoptimizeJob.cpp b/src/slic3r/GUI/Jobs/RotoptimizeJob.cpp index a670affef..95821a674 100644 --- a/src/slic3r/GUI/Jobs/RotoptimizeJob.cpp +++ b/src/slic3r/GUI/Jobs/RotoptimizeJob.cpp @@ -37,8 +37,12 @@ void RotoptimizeJob::prepare() m_selected_object_ids.clear(); m_selected_object_ids.reserve(sel.size()); - for (auto &[obj_idx, ignore] : sel) - m_selected_object_ids.emplace_back(obj_idx); + + for (const auto &s : sel) { + int obj_id; + std::tie(obj_id, std::ignore) = s; + m_selected_object_ids.emplace_back(obj_id); + } } void RotoptimizeJob::process() From 6b54f34ce15c9594a1e1348708c881e318281bc6 Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Wed, 19 May 2021 11:35:27 +0200 Subject: [PATCH 2/7] New functions: its_convex_hull_2d_above() --- src/libslic3r/TriangleMesh.cpp | 33 +++++++++++++++++++++++++++++++++ src/libslic3r/TriangleMesh.hpp | 3 +++ 2 files changed, 36 insertions(+) diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp index 4a1039b56..a92e55194 100644 --- a/src/libslic3r/TriangleMesh.cpp +++ b/src/libslic3r/TriangleMesh.cpp @@ -899,6 +899,39 @@ void its_shrink_to_fit(indexed_triangle_set &its) its.vertices.shrink_to_fit(); } +template +Polygon its_convex_hull_2d_above(const indexed_triangle_set &its, const TransformVertex &transform_fn, const float z) +{ + Points all_pts; + for (const stl_triangle_vertex_indices &tri : its.indices) { + const Vec3f pts[3] = { transform_fn(its.vertices[tri(0)]), transform_fn(its.vertices[tri(1)]), transform_fn(its.vertices[tri(2)]) }; + int iprev = 3; + for (int iedge = 0; iedge < 3; ++ iedge) { + const Vec3f &p1 = pts[iprev]; + const Vec3f &p2 = pts[iedge]; + if ((p1.z() < z && p2.z() > z) || (p2.z() < z && p1.z() > z)) { + // Edge crosses the z plane. Calculate intersection point with the plane. + float t = z / (p2.z() - p1.z()); + all_pts.emplace_back(scaled(p1.x() + (p2.x() - p1.x()) * t), scaled(p2.x() + (p2.y() - p2.y()) * t)); + } + if (p2.z() > z) + all_pts.emplace_back(scaled(p2.x()), scaled(p2.y())); + iprev = iedge; + } + } + return Geometry::convex_hull(std::move(all_pts)); +} + +Polygon its_convex_hull_2d_above(const indexed_triangle_set &its, const Matrix3f &m, const float z) +{ + return its_convex_hull_2d_above(its, [m](const Vec3f &p){ return m * p; }, z); +} + +Polygon its_convex_hull_2d_above(const indexed_triangle_set &its, const Transform3f &t, const float z) +{ + return its_convex_hull_2d_above(its, [t](const Vec3f &p){ return t * p; }, z); +} + // Generate the vertex list for a cube solid of arbitrary size in X/Y/Z. TriangleMesh make_cube(double x, double y, double z) { diff --git a/src/libslic3r/TriangleMesh.hpp b/src/libslic3r/TriangleMesh.hpp index 5d3c15ec1..59a8715a0 100644 --- a/src/libslic3r/TriangleMesh.hpp +++ b/src/libslic3r/TriangleMesh.hpp @@ -113,6 +113,9 @@ 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); +Polygon its_convex_hull_2d_above(const indexed_triangle_set &its, const Matrix3f &m, const float z); +Polygon its_convex_hull_2d_above(const indexed_triangle_set &its, const Transform3f &t, const float z); + TriangleMesh make_cube(double x, double y, double z); // Generate a TriangleMesh of a cylinder From 8db2d96c75006155af969633ea493950a4011756 Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Wed, 19 May 2021 12:01:30 +0200 Subject: [PATCH 3/7] Point::ccw() optimization: Calculate with int64, not doubles. --- src/libslic3r/Point.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/libslic3r/Point.cpp b/src/libslic3r/Point.cpp index b16abe7be..7f351d259 100644 --- a/src/libslic3r/Point.cpp +++ b/src/libslic3r/Point.cpp @@ -117,7 +117,9 @@ bool Point::nearest_point(const Points &points, Point* point) const */ double Point::ccw(const Point &p1, const Point &p2) const { - return (double)(p2(0) - p1(0))*(double)((*this)(1) - p1(1)) - (double)(p2(1) - p1(1))*(double)((*this)(0) - p1(0)); + static_assert(sizeof(coord_t) == 4, "Point::ccw() requires a 32 bit coord_t"); + return cross2((p2 - p1).cast(), (*this - p1).cast()); +// return cross2((p2 - p1).cast(), (*this - p1).cast()); } double Point::ccw(const Line &line) const @@ -129,9 +131,9 @@ double Point::ccw(const Line &line) const // i.e. this assumes a CCW rotation from p1 to p2 around this double Point::ccw_angle(const Point &p1, const Point &p2) const { - double angle = atan2(p1(0) - (*this)(0), p1(1) - (*this)(1)) - - atan2(p2(0) - (*this)(0), p2(1) - (*this)(1)); - + //FIXME this calculates an atan2 twice! Project one vector into the other! + double angle = atan2(p1.x() - (*this).x(), p1.y() - (*this).y()) + - atan2(p2.x() - (*this).x(), p2.y() - (*this).y()); // we only want to return only positive angles return angle <= 0 ? angle + 2*PI : angle; } @@ -201,12 +203,12 @@ int orient(const Vec2crd &p1, const Vec2crd &p2, const Vec2crd &p3) { Slic3r::Vector v1(p2 - p1); Slic3r::Vector v2(p3 - p1); - return Int128::sign_determinant_2x2_filtered(v1(0), v1(1), v2(0), v2(1)); + return Int128::sign_determinant_2x2_filtered(v1.x(), v1.y(), v2.x(), v2.y()); } int cross(const Vec2crd &v1, const Vec2crd &v2) { - return Int128::sign_determinant_2x2_filtered(v1(0), v1(1), v2(0), v2(1)); + return Int128::sign_determinant_2x2_filtered(v1.x(), v1.y(), v2.x(), v2.y()); } } From 5644b98d3bc7c8733699802425410944d9251e2c Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Wed, 19 May 2021 13:23:19 +0200 Subject: [PATCH 4/7] Factored out convex hull calculation from ModelObject::convex_hull_2d() to Geometry::convex_hull(). Update Geometry::convex_hull() to handle duplicate points. --- src/libslic3r/Geometry.cpp | 28 ++++++++++++---------------- src/libslic3r/Model.cpp | 26 +------------------------- 2 files changed, 13 insertions(+), 41 deletions(-) diff --git a/src/libslic3r/Geometry.cpp b/src/libslic3r/Geometry.cpp index e60eb01b6..e9fc22ab0 100644 --- a/src/libslic3r/Geometry.cpp +++ b/src/libslic3r/Geometry.cpp @@ -212,36 +212,32 @@ static bool sort_pointfs(const Vec3d& a, const Vec3d& b) } // This implementation is based on Andrew's monotone chain 2D convex hull algorithm -Polygon convex_hull(Points points) +Polygon convex_hull(Points pts) { - assert(points.size() >= 3); - // sort input points - std::sort(points.begin(), points.end(), sort_points); + std::sort(pts.begin(), pts.end(), [](const Point& a, const Point& b) { return a(0) < b(0) || (a(0) == b(0) && a(1) < b(1)); }); + pts.erase(std::unique(pts.begin(), pts.end(), [](const Point& a, const Point& b) { return a(0) == b(0) && a(1) == b(1); }), pts.end()); - int n = points.size(), k = 0; Polygon hull; - + int n = (int)pts.size(); if (n >= 3) { + int k = 0; hull.points.resize(2 * n); - // Build lower hull - for (int i = 0; i < n; i++) { - while (k >= 2 && points[i].ccw(hull[k-2], hull[k-1]) <= 0) k--; - hull[k++] = points[i]; + for (int i = 0; i < n; ++ i) { + while (k >= 2 && pts[i].ccw(hull[k-2], hull[k-1]) <= 0) + -- k; + hull[k ++] = pts[i]; } - // Build upper hull for (int i = n-2, t = k+1; i >= 0; i--) { - while (k >= t && points[i].ccw(hull[k-2], hull[k-1]) <= 0) k--; - hull[k++] = points[i]; + while (k >= t && pts[i].ccw(hull[k-2], hull[k-1]) <= 0) + -- k; + hull[k ++] = pts[i]; } - hull.points.resize(k); - assert(hull.points.front() == hull.points.back()); hull.points.pop_back(); } - return hull; } diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 4b6b838be..f916fbdcd 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -937,31 +937,7 @@ Polygon ModelObject::convex_hull_2d(const Transform3d &trafo_instance) const } #endif // ENABLE_ALLOW_NEGATIVE_Z } - std::sort(pts.begin(), pts.end(), [](const Point& a, const Point& b) { return a(0) < b(0) || (a(0) == b(0) && a(1) < b(1)); }); - pts.erase(std::unique(pts.begin(), pts.end(), [](const Point& a, const Point& b) { return a(0) == b(0) && a(1) == b(1); }), pts.end()); - - Polygon hull; - int n = (int)pts.size(); - if (n >= 3) { - int k = 0; - hull.points.resize(2 * n); - // Build lower hull - for (int i = 0; i < n; ++ i) { - while (k >= 2 && pts[i].ccw(hull[k-2], hull[k-1]) <= 0) - -- k; - hull[k ++] = pts[i]; - } - // Build upper hull - for (int i = n-2, t = k+1; i >= 0; i--) { - while (k >= t && pts[i].ccw(hull[k-2], hull[k-1]) <= 0) - -- k; - hull[k ++] = pts[i]; - } - hull.points.resize(k); - assert(hull.points.front() == hull.points.back()); - hull.points.pop_back(); - } - return hull; + return Geometry::convex_hull(std::move(pts)); } void ModelObject::center_around_origin(bool include_modifiers) From 66cf7ea9d30421d3a2b2a223896d92e2da7db492 Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Wed, 19 May 2021 13:39:56 +0200 Subject: [PATCH 5/7] Extracting its_collect_mesh_projection_points_above() out of its_convex_hull_2d_above(), so that the projected points may get collected over multiple volumes before applying Geometry::convex_hull() --- src/libslic3r/TriangleMesh.cpp | 20 ++++++++++++++++++-- src/libslic3r/TriangleMesh.hpp | 5 +++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp index a92e55194..8487e43cb 100644 --- a/src/libslic3r/TriangleMesh.cpp +++ b/src/libslic3r/TriangleMesh.cpp @@ -900,9 +900,8 @@ void its_shrink_to_fit(indexed_triangle_set &its) } template -Polygon its_convex_hull_2d_above(const indexed_triangle_set &its, const TransformVertex &transform_fn, const float z) +void its_collect_mesh_projection_points_above(const indexed_triangle_set &its, const TransformVertex &transform_fn, const float z, Points &all_pts) { - Points all_pts; for (const stl_triangle_vertex_indices &tri : its.indices) { const Vec3f pts[3] = { transform_fn(its.vertices[tri(0)]), transform_fn(its.vertices[tri(1)]), transform_fn(its.vertices[tri(2)]) }; int iprev = 3; @@ -919,6 +918,23 @@ Polygon its_convex_hull_2d_above(const indexed_triangle_set &its, const Transfor iprev = iedge; } } +} + +void its_collect_mesh_projection_points_above(const indexed_triangle_set &its, const Matrix3f &m, const float z, Points &all_pts) +{ + return its_collect_mesh_projection_points_above(its, [m](const Vec3f &p){ return m * p; }, z, all_pts); +} + +void its_collect_mesh_projection_points_above(const indexed_triangle_set &its, const Transform3f &t, const float z, Points &all_pts) +{ + return its_collect_mesh_projection_points_above(its, [t](const Vec3f &p){ return t * p; }, z, all_pts); +} + +template +Polygon its_convex_hull_2d_above(const indexed_triangle_set &its, const TransformVertex &transform_fn, const float z) +{ + Points all_pts; + its_collect_mesh_projection_points_above(its, transform_fn, z, all_pts); return Geometry::convex_hull(std::move(all_pts)); } diff --git a/src/libslic3r/TriangleMesh.hpp b/src/libslic3r/TriangleMesh.hpp index 59a8715a0..29a42eab3 100644 --- a/src/libslic3r/TriangleMesh.hpp +++ b/src/libslic3r/TriangleMesh.hpp @@ -113,6 +113,11 @@ 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); +// For convex hull calculation: Transform mesh, trim it by the Z plane and collect all vertices. Duplicate vertices will be produced. +void its_collect_mesh_projection_points_above(const indexed_triangle_set &its, const Matrix3f &m, const float z, Points &all_pts); +void its_collect_mesh_projection_points_above(const indexed_triangle_set &its, const Transform3f &t, const float z, Points &all_pts); + +// Calculate 2D convex hull of a transformed and clipped mesh. Uses the function above. Polygon its_convex_hull_2d_above(const indexed_triangle_set &its, const Matrix3f &m, const float z); Polygon its_convex_hull_2d_above(const indexed_triangle_set &its, const Transform3f &t, const float z); From e952aded781591d21a8b15f7fc4d358def71d3c9 Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Wed, 19 May 2021 13:52:47 +0200 Subject: [PATCH 6/7] cut_mesh(): new parameter to optionally not triangulate the caps. --- src/libslic3r/TriangleMeshSlicer.cpp | 58 +++++++++++++++------------- src/libslic3r/TriangleMeshSlicer.hpp | 3 +- 2 files changed, 33 insertions(+), 28 deletions(-) diff --git a/src/libslic3r/TriangleMeshSlicer.cpp b/src/libslic3r/TriangleMeshSlicer.cpp index 7d0c2516c..e27766fb8 100644 --- a/src/libslic3r/TriangleMeshSlicer.cpp +++ b/src/libslic3r/TriangleMeshSlicer.cpp @@ -1179,6 +1179,7 @@ std::vector slice_mesh_ex( return layers; } +// Remove duplicates of slice_vertices, optionally triangulate the cut. static void triangulate_slice( indexed_triangle_set &its, IntersectionLines &lines, @@ -1186,7 +1187,8 @@ static void triangulate_slice( // Vertices of the original (unsliced) mesh. Newly added vertices are those on the slice. int num_original_vertices, // Z height of the slice. - float z) + float z, + bool triangulate) { sort_remove_duplicates(slice_vertices); @@ -1230,33 +1232,35 @@ static void triangulate_slice( f(i) = map_duplicate_vertex[f(i) - num_original_vertices]; } - size_t idx_vertex_new_first = its.vertices.size(); - Pointf3s triangles = triangulate_expolygons_3d(make_expolygons_simple(lines), z, true); - for (size_t i = 0; i < triangles.size(); ) { - stl_triangle_vertex_indices facet; - for (size_t j = 0; j < 3; ++ j) { - Vec3f v = triangles[i ++].cast(); - auto it = lower_bound_by_predicate(map_vertex_to_index.begin(), map_vertex_to_index.end(), - [&v](const std::pair &l) { return l.first.x() < v.x() || (l.first.x() == v.x() && l.first.y() < v.y()); }); - int idx = -1; - if (it != map_vertex_to_index.end() && it->first.x() == v.x() && it->first.y() == v.y()) - idx = it->second; - else { - // Try to find the vertex in the list of newly added vertices. Those vertices are not matched on the cut and they shall be rare. - for (size_t k = idx_vertex_new_first; k < its.vertices.size(); ++ k) - if (its.vertices[k] == v) { - idx = int(k); - break; + if (triangulate) { + size_t idx_vertex_new_first = its.vertices.size(); + Pointf3s triangles = triangulate_expolygons_3d(make_expolygons_simple(lines), z, true); + for (size_t i = 0; i < triangles.size(); ) { + stl_triangle_vertex_indices facet; + for (size_t j = 0; j < 3; ++ j) { + Vec3f v = triangles[i ++].cast(); + auto it = lower_bound_by_predicate(map_vertex_to_index.begin(), map_vertex_to_index.end(), + [&v](const std::pair &l) { return l.first.x() < v.x() || (l.first.x() == v.x() && l.first.y() < v.y()); }); + int idx = -1; + if (it != map_vertex_to_index.end() && it->first.x() == v.x() && it->first.y() == v.y()) + idx = it->second; + else { + // Try to find the vertex in the list of newly added vertices. Those vertices are not matched on the cut and they shall be rare. + for (size_t k = idx_vertex_new_first; k < its.vertices.size(); ++ k) + if (its.vertices[k] == v) { + idx = int(k); + break; + } + if (idx == -1) { + idx = int(its.vertices.size()); + its.vertices.emplace_back(v); } - if (idx == -1) { - idx = int(its.vertices.size()); - its.vertices.emplace_back(v); } + facet(j) = idx; } - facet(j) = idx; + if (facet(0) != facet(1) && facet(0) != facet(2) && facet(1) != facet(2)) + its.indices.emplace_back(facet); } - if (facet(0) != facet(1) && facet(0) != facet(2) && facet(1) != facet(2)) - its.indices.emplace_back(facet); } // Remove vertices, which are not referenced by any face. @@ -1266,7 +1270,7 @@ static void triangulate_slice( // its_remove_degenerate_faces(its); } -void cut_mesh(const indexed_triangle_set &mesh, float z, indexed_triangle_set *upper, indexed_triangle_set *lower) +void cut_mesh(const indexed_triangle_set &mesh, float z, indexed_triangle_set *upper, indexed_triangle_set *lower, bool triangulate_caps) { assert(upper || lower); if (upper == nullptr && lower == nullptr) @@ -1413,10 +1417,10 @@ void cut_mesh(const indexed_triangle_set &mesh, float z, indexed_triangle_set *u } if (upper != nullptr) - triangulate_slice(*upper, upper_lines, upper_slice_vertices, int(mesh.vertices.size()), z); + triangulate_slice(*upper, upper_lines, upper_slice_vertices, int(mesh.vertices.size()), z, triangulate_caps); if (lower != nullptr) - triangulate_slice(*lower, lower_lines, lower_slice_vertices, int(mesh.vertices.size()), z); + triangulate_slice(*lower, lower_lines, lower_slice_vertices, int(mesh.vertices.size()), z, triangulate_caps); } } diff --git a/src/libslic3r/TriangleMeshSlicer.hpp b/src/libslic3r/TriangleMeshSlicer.hpp index 4ae972d00..3a144d834 100644 --- a/src/libslic3r/TriangleMeshSlicer.hpp +++ b/src/libslic3r/TriangleMeshSlicer.hpp @@ -76,7 +76,8 @@ void cut_mesh( const indexed_triangle_set &mesh, float z, indexed_triangle_set *upper, - indexed_triangle_set *lower); + indexed_triangle_set *lower, + bool triangulate_caps = true); } From 31942e03db4a6cd9df6462d4184dbb5fb581c908 Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Wed, 19 May 2021 13:59:34 +0200 Subject: [PATCH 7/7] Optimization of its_collect_mesh_projection_points_above(): Reserve points. --- src/libslic3r/TriangleMesh.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp index 8487e43cb..5e18e43ef 100644 --- a/src/libslic3r/TriangleMesh.cpp +++ b/src/libslic3r/TriangleMesh.cpp @@ -902,6 +902,7 @@ void its_shrink_to_fit(indexed_triangle_set &its) template void its_collect_mesh_projection_points_above(const indexed_triangle_set &its, const TransformVertex &transform_fn, const float z, Points &all_pts) { + all_pts.reserve(all_pts.size() + its.indices.size() * 3); for (const stl_triangle_vertex_indices &tri : its.indices) { const Vec3f pts[3] = { transform_fn(its.vertices[tri(0)]), transform_fn(its.vertices[tri(1)]), transform_fn(its.vertices[tri(2)]) }; int iprev = 3;