Merge remote-tracking branch 'remotes/origin/master' into vb_print_regions
This commit is contained in:
commit
68b0d92183
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -937,31 +937,7 @@ Polygon ModelObject::convex_hull_2d(const Transform3d &trafo_instance) const
|
|||||||
}
|
}
|
||||||
#endif // ENABLE_ALLOW_NEGATIVE_Z
|
#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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModelObject::center_around_origin(bool include_modifiers)
|
void ModelObject::center_around_origin(bool include_modifiers)
|
||||||
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -899,6 +899,56 @@ void its_shrink_to_fit(indexed_triangle_set &its)
|
|||||||
its.vertices.shrink_to_fit();
|
its.vertices.shrink_to_fit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename TransformVertex>
|
||||||
|
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;
|
||||||
|
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<coord_t>(p1.x() + (p2.x() - p1.x()) * t), scaled<coord_t>(p2.x() + (p2.y() - p2.y()) * t));
|
||||||
|
}
|
||||||
|
if (p2.z() > z)
|
||||||
|
all_pts.emplace_back(scaled<coord_t>(p2.x()), scaled<coord_t>(p2.y()));
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
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.
|
// Generate the vertex list for a cube solid of arbitrary size in X/Y/Z.
|
||||||
TriangleMesh make_cube(double x, double y, double z)
|
TriangleMesh make_cube(double x, double y, double z)
|
||||||
{
|
{
|
||||||
|
@ -113,6 +113,14 @@ 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 Transform3f &t, const float z);
|
||||||
|
|
||||||
TriangleMesh make_cube(double x, double y, double z);
|
TriangleMesh make_cube(double x, double y, double z);
|
||||||
|
|
||||||
// Generate a TriangleMesh of a cylinder
|
// Generate a TriangleMesh of a cylinder
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,8 +37,12 @@ void RotoptimizeJob::prepare()
|
|||||||
|
|
||||||
m_selected_object_ids.clear();
|
m_selected_object_ids.clear();
|
||||||
m_selected_object_ids.reserve(sel.size());
|
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()
|
void RotoptimizeJob::process()
|
||||||
|
Loading…
Reference in New Issue
Block a user