Remove collinear points from polygons right after slicing the stl into polygons.

Triangulation of planar surfaces results in additional edges (i.e. splitting a rectangle into two triangles).
Those edges end up as collinear points in the contour polygons and cause additional, redundant
computation. Most collinear points would be removed by Douglas-Peucker during gcode export.

Fixes #4726.
This commit is contained in:
Florens Wasserfall 2019-02-06 12:28:29 +01:00 committed by Joseph Lenox
parent 66b00c90c3
commit faeb213ce1
7 changed files with 71 additions and 0 deletions

View File

@ -129,6 +129,14 @@ ExPolygon::has_boundary_point(const Point &point) const
return false;
}
void
ExPolygon::remove_colinear_points()
{
this->contour.remove_collinear_points();
for (Polygon &p : this->holes)
p.remove_collinear_points();
}
void
ExPolygon::remove_vertical_collinear_points(coord_t tolerance)
{

View File

@ -37,6 +37,8 @@ class ExPolygon
bool contains_b(const Point &point) const;
bool has_boundary_point(const Point &point) const;
BoundingBox bounding_box() const { return this->contour.bounding_box(); };
/// removes collinear points within SCALED_EPSILON tolerance
void remove_colinear_points();
void remove_vertical_collinear_points(coord_t tolerance);
void simplify_p(double tolerance, Polygons* polygons) const;
Polygons simplify_p(double tolerance) const;

View File

@ -156,6 +156,42 @@ Polygon::douglas_peucker(double tolerance)
this->points.pop_back();
}
void
Polygon::remove_collinear_points()
{
if(this->points.size() > 2) {
// copy points and append both 1 and last point in place to cover the boundaries
Points pp;
pp.reserve(this->points.size()+2);
pp.push_back(this->points.back());
pp.insert(pp.begin()+1, this->points.begin(), this->points.end());
pp.push_back(this->points.front());
// delete old points vector. Will be re-filled in the loop
this->points.clear();
size_t i = 0;
size_t k = 0;
while (i < pp.size()-2) {
k = i+1;
const Point &p1 = pp[i];
while (k < pp.size()-1) {
const Point &p2 = pp[k];
const Point &p3 = pp[k+1];
Line l(p1, p3);
if(l.distance_to(p2) < SCALED_EPSILON) {
k++;
} else {
if(i > 0) this->points.push_back(p1); // implicitly removes the first point we appended above
i = k;
break;
}
}
if(k > pp.size()-2) break; // all remaining points are collinear and can be skipped
}
this->points.push_back(pp[i]);
}
}
void
Polygon::remove_vertical_collinear_points(coord_t tolerance)
{

View File

@ -41,6 +41,8 @@ class Polygon : public MultiPoint {
// Tested by counting intersections along a horizontal line.
bool contains(const Point &point) const;
void douglas_peucker(double tolerance);
/// removes collinear points within SCALED_EPSILON tolerance
void remove_collinear_points();
void remove_vertical_collinear_points(coord_t tolerance);
Polygons simplify(double tolerance) const;
void simplify(double tolerance, Polygons &polygons) const;

View File

@ -842,6 +842,19 @@ void PrintObject::_slice()
}
}
// remove collinear points from slice polygons (artifacts from stl-triangulation)
std::queue<SurfaceCollection*> queue;
for (Layer* layer : this->layers) {
for (LayerRegion* layerm : layer->regions) {
queue.push(&layerm->slices);
}
}
parallelize<SurfaceCollection*>(
queue,
boost::bind(&Slic3r::SurfaceCollection::remove_collinear_points, _1),
this->_print->config.threads.value
);
// remove last layer(s) if empty
bool done = false;
while (! this->layers.empty()) {

View File

@ -39,6 +39,14 @@ SurfaceCollection::simplify(double tolerance)
this->surfaces = ss;
}
void
SurfaceCollection::remove_collinear_points()
{
for(Surface &surface : this->surfaces) {
surface.expolygon.remove_colinear_points();
}
}
/* group surfaces by common properties */
void
SurfaceCollection::group(std::vector<SurfacesConstPtr> *retval) const

View File

@ -18,6 +18,8 @@ class SurfaceCollection
operator Polygons() const;
operator ExPolygons() const;
void simplify(double tolerance);
/// Unifies straight multi-segment lines to a single line (artifacts from stl-triangulation)
void remove_collinear_points();
void group(std::vector<SurfacesConstPtr> *retval) const;
template <class T> bool any_internal_contains(const T &item) const;
template <class T> bool any_bottom_contains(const T &item) const;