Removal of not numerically robust libraries "poly2tree" and "polypartition".

Adjustment of GUI/3DBed.cpp,hpp to use the more stable triangulation algoritm
derived from SGI glut.
Fix of an extremely slow bridging calculation, caused by an extremely
slow bridged area detection function, of which the results were never used.
Fixes "slicing fails or takes too long #5974"
This commit is contained in:
Vojtech Bubnik 2021-02-09 18:36:28 +01:00
parent 820c18923b
commit 2e55898d78
33 changed files with 94 additions and 5126 deletions

View file

@ -207,6 +207,62 @@ std::vector<double> BridgeDetector::bridge_direction_candidates() const
return angles;
}
/*
static void get_trapezoids(const ExPolygon &expoly, Polygons* polygons) const
{
ExPolygons expp;
expp.push_back(expoly);
boost::polygon::get_trapezoids(*polygons, expp);
}
void ExPolygon::get_trapezoids(ExPolygon clone, Polygons* polygons, double angle) const
{
clone.rotate(PI/2 - angle, Point(0,0));
clone.get_trapezoids(polygons);
for (Polygons::iterator polygon = polygons->begin(); polygon != polygons->end(); ++polygon)
polygon->rotate(-(PI/2 - angle), Point(0,0));
}
*/
// This algorithm may return more trapezoids than necessary
// (i.e. it may break a single trapezoid in several because
// other parts of the object have x coordinates in the middle)
static void get_trapezoids2(const ExPolygon &expoly, Polygons* polygons)
{
Polygons src_polygons = to_polygons(expoly);
// get all points of this ExPolygon
const Points pp = to_points(src_polygons);
// build our bounding box
BoundingBox bb(pp);
// get all x coordinates
std::vector<coord_t> xx;
xx.reserve(pp.size());
for (Points::const_iterator p = pp.begin(); p != pp.end(); ++p)
xx.push_back(p->x());
std::sort(xx.begin(), xx.end());
// find trapezoids by looping from first to next-to-last coordinate
for (std::vector<coord_t>::const_iterator x = xx.begin(); x != xx.end()-1; ++x) {
coord_t next_x = *(x + 1);
if (*x != next_x)
// intersect with rectangle
// append results to return value
polygons_append(*polygons, intersection({ { { *x, bb.min.y() }, { next_x, bb.min.y() }, { next_x, bb.max.y() }, { *x, bb.max.y() } } }, src_polygons));
}
}
static void get_trapezoids2(const ExPolygon &expoly, Polygons* polygons, double angle)
{
ExPolygon clone = expoly;
clone.rotate(PI/2 - angle, Point(0,0));
get_trapezoids2(clone, polygons);
for (Polygon &polygon : *polygons)
polygon.rotate(-(PI/2 - angle), Point(0,0));
}
// Coverage is currently only used by the unit tests. It is extremely slow and unreliable!
Polygons BridgeDetector::coverage(double angle) const
{
if (angle == -1)
@ -228,7 +284,7 @@ Polygons BridgeDetector::coverage(double angle) const
for (ExPolygon &expoly : offset_ex(expolygon, 0.5f * float(this->spacing))) {
// Compute trapezoids according to a vertical orientation
Polygons trapezoids;
expoly.get_trapezoids2(&trapezoids, PI/2.0);
get_trapezoids2(expoly, &trapezoids, PI/2.0);
for (const Polygon &trapezoid : trapezoids) {
// not nice, we need a more robust non-numeric check
size_t n_supported = 0;

View file

@ -32,6 +32,7 @@ public:
BridgeDetector(const ExPolygons &_expolygons, const ExPolygons &_lower_slices, coord_t _extrusion_width);
// If bridge_direction_override != 0, then the angle is used instead of auto-detect.
bool detect_angle(double bridge_direction_override = 0.);
// Coverage is currently only used by the unit tests. It is extremely slow and unreliable!
Polygons coverage(double angle = -1) const;
void unsupported_edges(double angle, Polylines* unsupported) const;
Polylines unsupported_edges(double angle = -1) const;

View file

@ -309,8 +309,6 @@ target_link_libraries(libslic3r
nowide
${EXPAT_LIBRARIES}
glu-libtess
polypartition
poly2tri
qhull
semver
TBB::tbb

View file

@ -6,8 +6,6 @@
#include "Line.hpp"
#include "ClipperUtils.hpp"
#include "SVG.hpp"
#include "polypartition.h"
#include "poly2tri/poly2tri.h"
#include <algorithm>
#include <cassert>
#include <list>
@ -318,284 +316,6 @@ ExPolygon::medial_axis(double max_width, double min_width, Polylines* polylines)
polylines->insert(polylines->end(), tp.begin(), tp.end());
}
/*
void ExPolygon::get_trapezoids(Polygons* polygons) const
{
ExPolygons expp;
expp.push_back(*this);
boost::polygon::get_trapezoids(*polygons, expp);
}
void ExPolygon::get_trapezoids(Polygons* polygons, double angle) const
{
ExPolygon clone = *this;
clone.rotate(PI/2 - angle, Point(0,0));
clone.get_trapezoids(polygons);
for (Polygons::iterator polygon = polygons->begin(); polygon != polygons->end(); ++polygon)
polygon->rotate(-(PI/2 - angle), Point(0,0));
}
*/
// This algorithm may return more trapezoids than necessary
// (i.e. it may break a single trapezoid in several because
// other parts of the object have x coordinates in the middle)
void ExPolygon::get_trapezoids2(Polygons* polygons) const
{
// get all points of this ExPolygon
Points pp = *this;
// build our bounding box
BoundingBox bb(pp);
// get all x coordinates
std::vector<coord_t> xx;
xx.reserve(pp.size());
for (Points::const_iterator p = pp.begin(); p != pp.end(); ++p)
xx.push_back(p->x());
std::sort(xx.begin(), xx.end());
// find trapezoids by looping from first to next-to-last coordinate
for (std::vector<coord_t>::const_iterator x = xx.begin(); x != xx.end()-1; ++x) {
coord_t next_x = *(x + 1);
if (*x != next_x)
// intersect with rectangle
// append results to return value
polygons_append(*polygons, intersection({ { { *x, bb.min.y() }, { next_x, bb.min.y() }, { next_x, bb.max.y() }, { *x, bb.max.y() } } }, to_polygons(*this)));
}
}
void ExPolygon::get_trapezoids2(Polygons* polygons, double angle) const
{
ExPolygon clone = *this;
clone.rotate(PI/2 - angle, Point(0,0));
clone.get_trapezoids2(polygons);
for (Polygons::iterator polygon = polygons->begin(); polygon != polygons->end(); ++polygon)
polygon->rotate(-(PI/2 - angle), Point(0,0));
}
// While this triangulates successfully, it's NOT a constrained triangulation
// as it will create more vertices on the boundaries than the ones supplied.
void ExPolygon::triangulate(Polygons* polygons) const
{
// first make trapezoids
Polygons trapezoids;
this->get_trapezoids2(&trapezoids);
// then triangulate each trapezoid
for (Polygons::iterator polygon = trapezoids.begin(); polygon != trapezoids.end(); ++polygon)
polygon->triangulate_convex(polygons);
}
/*
void ExPolygon::triangulate_pp(Polygons* polygons) const
{
// convert polygons
std::list<TPPLPoly> input;
ExPolygons expp = union_ex(simplify_polygons(to_polygons(*this), true));
for (ExPolygons::const_iterator ex = expp.begin(); ex != expp.end(); ++ex) {
// contour
{
TPPLPoly p;
p.Init(int(ex->contour.points.size()));
//printf("%zu\n0\n", ex->contour.points.size());
for (const Point &point : ex->contour.points) {
size_t i = &point - &ex->contour.points.front();
p[i].x = point(0);
p[i].y = point(1);
//printf("%ld %ld\n", point->x(), point->y());
}
p.SetHole(false);
input.push_back(p);
}
// holes
for (Polygons::const_iterator hole = ex->holes.begin(); hole != ex->holes.end(); ++hole) {
TPPLPoly p;
p.Init(hole->points.size());
//printf("%zu\n1\n", hole->points.size());
for (const Point &point : hole->points) {
size_t i = &point - &hole->points.front();
p[i].x = point(0);
p[i].y = point(1);
//printf("%ld %ld\n", point->x(), point->y());
}
p.SetHole(true);
input.push_back(p);
}
}
// perform triangulation
std::list<TPPLPoly> output;
int res = TPPLPartition().Triangulate_MONO(&input, &output);
if (res != 1)
throw Slic3r::RuntimeError("Triangulation failed");
// convert output polygons
for (std::list<TPPLPoly>::iterator poly = output.begin(); poly != output.end(); ++poly) {
long num_points = poly->GetNumPoints();
Polygon p;
p.points.resize(num_points);
for (long i = 0; i < num_points; ++i) {
p.points[i](0) = coord_t((*poly)[i].x);
p.points[i](1) = coord_t((*poly)[i].y);
}
polygons->push_back(p);
}
}
*/
std::list<TPPLPoly> expoly_to_polypartition_input(const ExPolygon &ex)
{
std::list<TPPLPoly> input;
// contour
{
input.emplace_back();
TPPLPoly &p = input.back();
p.Init(int(ex.contour.points.size()));
for (const Point &point : ex.contour.points) {
size_t i = &point - &ex.contour.points.front();
p[i].x = point(0);
p[i].y = point(1);
}
p.SetHole(false);
}
// holes
for (const Polygon &hole : ex.holes) {
input.emplace_back();
TPPLPoly &p = input.back();
p.Init(hole.points.size());
for (const Point &point : hole.points) {
size_t i = &point - &hole.points.front();
p[i].x = point(0);
p[i].y = point(1);
}
p.SetHole(true);
}
return input;
}
std::list<TPPLPoly> expoly_to_polypartition_input(const ExPolygons &expps)
{
std::list<TPPLPoly> input;
for (const ExPolygon &ex : expps) {
// contour
{
input.emplace_back();
TPPLPoly &p = input.back();
p.Init(int(ex.contour.points.size()));
for (const Point &point : ex.contour.points) {
size_t i = &point - &ex.contour.points.front();
p[i].x = point(0);
p[i].y = point(1);
}
p.SetHole(false);
}
// holes
for (const Polygon &hole : ex.holes) {
input.emplace_back();
TPPLPoly &p = input.back();
p.Init(hole.points.size());
for (const Point &point : hole.points) {
size_t i = &point - &hole.points.front();
p[i].x = point(0);
p[i].y = point(1);
}
p.SetHole(true);
}
}
return input;
}
std::vector<Point> polypartition_output_to_triangles(const std::list<TPPLPoly> &output)
{
size_t num_triangles = 0;
for (const TPPLPoly &poly : output)
if (poly.GetNumPoints() >= 3)
num_triangles += (size_t)poly.GetNumPoints() - 2;
std::vector<Point> triangles;
triangles.reserve(triangles.size() + num_triangles * 3);
for (const TPPLPoly &poly : output) {
long num_points = poly.GetNumPoints();
if (num_points >= 3) {
const TPPLPoint *pt0 = &poly[0];
const TPPLPoint *pt1 = nullptr;
const TPPLPoint *pt2 = &poly[1];
for (long i = 2; i < num_points; ++ i) {
pt1 = pt2;
pt2 = &poly[i];
triangles.emplace_back(coord_t(pt0->x), coord_t(pt0->y));
triangles.emplace_back(coord_t(pt1->x), coord_t(pt1->y));
triangles.emplace_back(coord_t(pt2->x), coord_t(pt2->y));
}
}
}
return triangles;
}
void ExPolygon::triangulate_pp(Points *triangles) const
{
ExPolygons expp = union_ex(simplify_polygons(to_polygons(*this), true));
std::list<TPPLPoly> input = expoly_to_polypartition_input(expp);
// perform triangulation
std::list<TPPLPoly> output;
int res = TPPLPartition().Triangulate_MONO(&input, &output);
// int TPPLPartition::Triangulate_EC(TPPLPolyList *inpolys, TPPLPolyList *triangles) {
if (res != 1)
throw Slic3r::RuntimeError("Triangulation failed");
*triangles = polypartition_output_to_triangles(output);
}
// Uses the Poly2tri library maintained by Jan Niklas Hasse @jhasse // https://github.com/jhasse/poly2tri
// See https://github.com/jhasse/poly2tri/blob/master/README.md for the limitations of the library!
// No duplicate points are allowed, no very close points, holes must not touch outer contour etc.
void ExPolygon::triangulate_p2t(Polygons* polygons) const
{
ExPolygons expp = simplify_polygons_ex(*this, true);
for (ExPolygons::const_iterator ex = expp.begin(); ex != expp.end(); ++ex) {
// TODO: prevent duplicate points
// contour
std::vector<p2t::Point*> ContourPoints;
for (const Point &pt : ex->contour.points)
// We should delete each p2t::Point object
ContourPoints.push_back(new p2t::Point(pt(0), pt(1)));
p2t::CDT cdt(ContourPoints);
// holes
for (Polygons::const_iterator hole = ex->holes.begin(); hole != ex->holes.end(); ++hole) {
std::vector<p2t::Point*> points;
for (const Point &pt : hole->points)
// will be destructed in SweepContext::~SweepContext
points.push_back(new p2t::Point(pt(0), pt(1)));
cdt.AddHole(points);
}
// perform triangulation
try {
cdt.Triangulate();
std::vector<p2t::Triangle*> triangles = cdt.GetTriangles();
for (std::vector<p2t::Triangle*>::const_iterator triangle = triangles.begin(); triangle != triangles.end(); ++triangle) {
Polygon p;
for (int i = 0; i <= 2; ++i) {
p2t::Point* point = (*triangle)->GetPoint(i);
p.points.push_back(Point(point->x, point->y));
}
polygons->push_back(p);
}
} catch (const Slic3r::RuntimeError & /* err */) {
assert(false);
// just ignore, don't triangulate
}
for (p2t::Point *ptr : ContourPoints)
delete ptr;
}
}
Lines ExPolygon::lines() const
{
Lines lines = this->contour.lines();

View file

@ -6,9 +6,6 @@
#include "Polyline.hpp"
#include <vector>
// polygon class of the polypartition library
class TPPLPoly;
namespace Slic3r {
class ExPolygon;
@ -70,14 +67,6 @@ public:
void simplify(double tolerance, ExPolygons* expolygons) const;
void medial_axis(double max_width, double min_width, ThickPolylines* polylines) const;
void medial_axis(double max_width, double min_width, Polylines* polylines) const;
// void get_trapezoids(Polygons* polygons) const;
// void get_trapezoids(Polygons* polygons, double angle) const;
void get_trapezoids2(Polygons* polygons) const;
void get_trapezoids2(Polygons* polygons, double angle) const;
void triangulate(Polygons* polygons) const;
// Triangulate into triples of points.
void triangulate_pp(Points *triangles) const;
void triangulate_p2t(Polygons* polygons) const;
Lines lines() const;
// Number of contours (outer contour with holes).
@ -349,10 +338,6 @@ extern std::vector<BoundingBox> get_extents_vector(const ExPolygons &polygons);
extern bool remove_sticks(ExPolygon &poly);
extern void keep_largest_contour_only(ExPolygons &polygons);
extern std::list<TPPLPoly> expoly_to_polypartition_input(const ExPolygons &expp);
extern std::list<TPPLPoly> expoly_to_polypartition_input(const ExPolygon &ex);
extern std::vector<Point> polypartition_output_to_triangles(const std::list<TPPLPoly> &output);
inline double area(const ExPolygons &polys)
{
double s = 0.;

View file

@ -46,7 +46,7 @@ public:
// collection of expolygons representing the bridged areas (thus not
// needing support material)
Polygons bridged;
// Polygons bridged;
// collection of polylines representing the unsupported bridge edges
Polylines unsupported_bridge_edges;

View file

@ -278,7 +278,7 @@ void LayerRegion::process_external_surfaces(const Layer *lower_layer, const Poly
if (bd.detect_angle(custom_angle)) {
bridges[idx_last].bridge_angle = bd.angle;
if (this->layer()->object()->config().support_material) {
polygons_append(this->bridged, bd.coverage());
// polygons_append(this->bridged, bd.coverage());
append(this->unsupported_bridge_edges, bd.unsupported_edges());
}
} else if (custom_angle > 0) {