Merge branch 'master' of https://github.com/prusa3d/PrusaSlicer into et_sequential_limits

This commit is contained in:
enricoturri1966 2021-05-20 10:47:51 +02:00
commit 33d489df30
7 changed files with 97 additions and 108 deletions

View file

@ -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 // 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); 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)); });
// sort input points 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());
std::sort(points.begin(), points.end(), sort_points);
int n = points.size(), k = 0;
Polygon hull; Polygon hull;
int n = (int)pts.size();
if (n >= 3) { if (n >= 3) {
int k = 0;
hull.points.resize(2 * n); hull.points.resize(2 * n);
// Build lower hull // Build lower hull
for (int i = 0; i < n; i++) { for (int i = 0; i < n; ++ i) {
while (k >= 2 && points[i].ccw(hull[k-2], hull[k-1]) <= 0) k--; while (k >= 2 && pts[i].ccw(hull[k-2], hull[k-1]) <= 0)
hull[k++] = points[i]; -- k;
hull[k ++] = pts[i];
} }
// Build upper hull // Build upper hull
for (int i = n-2, t = k+1; i >= 0; i--) { 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--; while (k >= t && pts[i].ccw(hull[k-2], hull[k-1]) <= 0)
hull[k++] = points[i]; -- k;
hull[k ++] = pts[i];
} }
hull.points.resize(k); hull.points.resize(k);
assert(hull.points.front() == hull.points.back()); assert(hull.points.front() == hull.points.back());
hull.points.pop_back(); hull.points.pop_back();
} }
return hull; return hull;
} }

View file

@ -1,3 +1,4 @@
#include "libslic3r.h"
#include "Exception.hpp" #include "Exception.hpp"
#include "Model.hpp" #include "Model.hpp"
#include "ModelArrange.hpp" #include "ModelArrange.hpp"
@ -889,35 +890,22 @@ BoundingBoxf3 ModelObject::instance_bounding_box(size_t instance_idx, bool dont_
// Calculate 2D convex hull of of a projection of the transformed printable volumes into the XY plane. // Calculate 2D convex hull of of a projection of the transformed printable volumes into the XY plane.
// This method is cheap in that it does not make any unnecessary copy of the volume meshes. // This method is cheap in that it does not make any unnecessary copy of the volume meshes.
// This method is used by the auto arrange function. // This method is used by the auto arrange function.
#if ENABLE_ALLOW_NEGATIVE_Z
Polygon ModelObject::convex_hull_2d(const Transform3d& trafo_instance) const
{
Points pts;
for (const ModelVolume* v : volumes) {
if (v->is_model_part())
append(pts, its_convex_hull_2d_above(v->mesh().its, (trafo_instance * v->get_matrix()).cast<float>(), 0.0f).points);
}
return Geometry::convex_hull(std::move(pts));
}
#else
Polygon ModelObject::convex_hull_2d(const Transform3d &trafo_instance) const Polygon ModelObject::convex_hull_2d(const Transform3d &trafo_instance) const
{ {
Points pts; Points pts;
for (const ModelVolume *v : this->volumes) for (const ModelVolume *v : this->volumes)
if (v->is_model_part()) { if (v->is_model_part()) {
#if ENABLE_ALLOW_NEGATIVE_Z
const Transform3d trafo = trafo_instance * v->get_matrix();
const TriangleMesh& hull_3d = v->get_convex_hull();
const indexed_triangle_set& its = hull_3d.its;
if (its.vertices.empty()) {
// Using the STL faces.
const stl_file& stl = hull_3d.stl;
for (const stl_facet& facet : stl.facet_start) {
for (size_t j = 0; j < 3; ++j) {
const Vec3d p = trafo * facet.vertex[j].cast<double>();
if (p.z() >= 0.0)
pts.emplace_back(coord_t(scale_(p.x())), coord_t(scale_(p.y())));
}
}
}
else {
// Using the shared vertices should be a bit quicker than using the STL faces.
for (size_t i = 0; i < its.vertices.size(); ++i) {
const Vec3d p = trafo * its.vertices[i].cast<double>();
if (p.z() >= 0.0)
pts.emplace_back(coord_t(scale_(p.x())), coord_t(scale_(p.y())));
}
}
#else
Transform3d trafo = trafo_instance * v->get_matrix(); Transform3d trafo = trafo_instance * v->get_matrix();
const indexed_triangle_set &its = v->mesh().its; const indexed_triangle_set &its = v->mesh().its;
if (its.vertices.empty()) { if (its.vertices.empty()) {
@ -935,34 +923,10 @@ Polygon ModelObject::convex_hull_2d(const Transform3d &trafo_instance) const
pts.emplace_back(coord_t(scale_(p.x())), coord_t(scale_(p.y()))); pts.emplace_back(coord_t(scale_(p.x())), coord_t(scale_(p.y())));
} }
} }
#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)); }); return Geometry::convex_hull(std::move(pts));
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;
} }
#endif // ENABLE_ALLOW_NEGATIVE_Z
void ModelObject::center_around_origin(bool include_modifiers) void ModelObject::center_around_origin(bool include_modifiers)
{ {

View file

@ -117,7 +117,9 @@ bool Point::nearest_point(const Points &points, Point* point) const
*/ */
double Point::ccw(const Point &p1, const Point &p2) 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<int64_t>(), (*this - p1).cast<int64_t>());
// return cross2((p2 - p1).cast<double>(), (*this - p1).cast<double>());
} }
double Point::ccw(const Line &line) const 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 // 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 Point::ccw_angle(const Point &p1, const Point &p2) const
{ {
double angle = atan2(p1(0) - (*this)(0), p1(1) - (*this)(1)) //FIXME this calculates an atan2 twice! Project one vector into the other!
- atan2(p2(0) - (*this)(0), p2(1) - (*this)(1)); 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 // we only want to return only positive angles
return angle <= 0 ? angle + 2*PI : angle; 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 v1(p2 - p1);
Slic3r::Vector v2(p3 - 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) 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());
} }
} }

View file

@ -611,7 +611,7 @@ TriangleMesh TriangleMesh::convex_hull_3d() const
return output_mesh; return output_mesh;
} }
std::vector<ExPolygons> TriangleMesh::slice(const std::vector<double> &z) std::vector<ExPolygons> TriangleMesh::slice(const std::vector<double> &z) const
{ {
// convert doubles to floats // convert doubles to floats
std::vector<float> z_f(z.begin(), z.end()); std::vector<float> z_f(z.begin(), z.end());
@ -900,25 +900,42 @@ void its_shrink_to_fit(indexed_triangle_set &its)
} }
template<typename TransformVertex> template<typename TransformVertex>
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; all_pts.reserve(all_pts.size() + its.indices.size() * 3);
for (const stl_triangle_vertex_indices &tri : its.indices) { 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)]) }; 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; int iprev = 2;
for (int iedge = 0; iedge < 3; ++ iedge) { for (int iedge = 0; iedge < 3; ++ iedge) {
const Vec3f &p1 = pts[iprev]; const Vec3f &p1 = pts[iprev];
const Vec3f &p2 = pts[iedge]; const Vec3f &p2 = pts[iedge];
if ((p1.z() < z && p2.z() > z) || (p2.z() < z && p1.z() > z)) { if ((p1.z() < z && p2.z() > z) || (p2.z() < z && p1.z() > z)) {
// Edge crosses the z plane. Calculate intersection point with the plane. // Edge crosses the z plane. Calculate intersection point with the plane.
float t = z / (p2.z() - p1.z()); float t = (z - p1.z()) / (p2.z() - p1.z());
all_pts.emplace_back(scaled<coord_t>(p1.x() + (p2.x() - p1.x()) * t), scaled<coord_t>(p2.x() + (p2.y() - p2.y()) * t)); all_pts.emplace_back(scaled<coord_t>(p1.x() + (p2.x() - p1.x()) * t), scaled<coord_t>(p1.y() + (p2.y() - p1.y()) * t));
} }
if (p2.z() > z) if (p2.z() > z)
all_pts.emplace_back(scaled<coord_t>(p2.x()), scaled<coord_t>(p2.y())); all_pts.emplace_back(scaled<coord_t>(p2.x()), scaled<coord_t>(p2.y()));
iprev = iedge; 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<typename TransformVertex>
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)); return Geometry::convex_hull(std::move(all_pts));
} }

View file

@ -65,7 +65,7 @@ public:
// Returns the convex hull of this TriangleMesh // Returns the convex hull of this TriangleMesh
TriangleMesh convex_hull_3d() const; TriangleMesh convex_hull_3d() const;
// Slice this mesh at the provided Z levels and return the vector // Slice this mesh at the provided Z levels and return the vector
std::vector<ExPolygons> slice(const std::vector<double>& z); std::vector<ExPolygons> slice(const std::vector<double>& z) const;
void reset_repair_stats(); void reset_repair_stats();
bool needed_repair() const; bool needed_repair() const;
void require_shared_vertices(); void require_shared_vertices();
@ -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. // 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); 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 Matrix3f &m, const float z);
Polygon its_convex_hull_2d_above(const indexed_triangle_set &its, const Transform3f &t, const float z); Polygon its_convex_hull_2d_above(const indexed_triangle_set &its, const Transform3f &t, const float z);

View file

@ -1075,7 +1075,7 @@ std::vector<Polygons> slice_mesh(
auto t = params.trafo; auto t = params.trafo;
t.prescale(Vec3d(s, s, 1.)); t.prescale(Vec3d(s, s, 1.));
auto tf = t.cast<float>(); auto tf = t.cast<float>();
slice_make_lines(mesh.vertices, [tf](const Vec3f &p) { return tf * p; }, mesh.indices, facets_edges, zs, throw_on_cancel); lines = slice_make_lines(mesh.vertices, [tf](const Vec3f &p) { return tf * p; }, mesh.indices, facets_edges, zs, throw_on_cancel);
} }
} else { } else {
// Copy and scale vertices in XY, don't scale in Z. // Copy and scale vertices in XY, don't scale in Z.
@ -1179,6 +1179,7 @@ std::vector<ExPolygons> slice_mesh_ex(
return layers; return layers;
} }
// Remove duplicates of slice_vertices, optionally triangulate the cut.
static void triangulate_slice( static void triangulate_slice(
indexed_triangle_set &its, indexed_triangle_set &its,
IntersectionLines &lines, IntersectionLines &lines,
@ -1186,7 +1187,8 @@ static void triangulate_slice(
// Vertices of the original (unsliced) mesh. Newly added vertices are those on the slice. // Vertices of the original (unsliced) mesh. Newly added vertices are those on the slice.
int num_original_vertices, int num_original_vertices,
// Z height of the slice. // Z height of the slice.
float z) float z,
bool triangulate)
{ {
sort_remove_duplicates(slice_vertices); sort_remove_duplicates(slice_vertices);
@ -1230,33 +1232,35 @@ static void triangulate_slice(
f(i) = map_duplicate_vertex[f(i) - num_original_vertices]; f(i) = map_duplicate_vertex[f(i) - num_original_vertices];
} }
size_t idx_vertex_new_first = its.vertices.size(); if (triangulate) {
Pointf3s triangles = triangulate_expolygons_3d(make_expolygons_simple(lines), z, true); size_t idx_vertex_new_first = its.vertices.size();
for (size_t i = 0; i < triangles.size(); ) { Pointf3s triangles = triangulate_expolygons_3d(make_expolygons_simple(lines), z, true);
stl_triangle_vertex_indices facet; for (size_t i = 0; i < triangles.size(); ) {
for (size_t j = 0; j < 3; ++ j) { stl_triangle_vertex_indices facet;
Vec3f v = triangles[i ++].cast<float>(); for (size_t j = 0; j < 3; ++ j) {
auto it = lower_bound_by_predicate(map_vertex_to_index.begin(), map_vertex_to_index.end(), Vec3f v = triangles[i ++].cast<float>();
[&v](const std::pair<Vec2f, int> &l) { return l.first.x() < v.x() || (l.first.x() == v.x() && l.first.y() < v.y()); }); auto it = lower_bound_by_predicate(map_vertex_to_index.begin(), map_vertex_to_index.end(),
int idx = -1; [&v](const std::pair<Vec2f, int> &l) { return l.first.x() < v.x() || (l.first.x() == v.x() && l.first.y() < v.y()); });
if (it != map_vertex_to_index.end() && it->first.x() == v.x() && it->first.y() == v.y()) int idx = -1;
idx = it->second; if (it != map_vertex_to_index.end() && it->first.x() == v.x() && it->first.y() == v.y())
else { idx = it->second;
// 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. else {
for (size_t k = idx_vertex_new_first; k < its.vertices.size(); ++ k) // 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.
if (its.vertices[k] == v) { for (size_t k = idx_vertex_new_first; k < its.vertices.size(); ++ k)
idx = int(k); if (its.vertices[k] == v) {
break; 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. // Remove vertices, which are not referenced by any face.
@ -1266,7 +1270,7 @@ static void triangulate_slice(
// its_remove_degenerate_faces(its); // 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); assert(upper || lower);
if (upper == nullptr && lower == nullptr) 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) 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) 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);
} }
} }

View file

@ -76,7 +76,8 @@ void cut_mesh(
const indexed_triangle_set &mesh, const indexed_triangle_set &mesh,
float z, float z,
indexed_triangle_set *upper, indexed_triangle_set *upper,
indexed_triangle_set *lower); indexed_triangle_set *lower,
bool triangulate_caps = true);
} }