mirror of
https://git.mirrors.martin98.com/https://github.com/slic3r/Slic3r.git
synced 2025-08-01 04:21:59 +08:00
Further cleanup of BridgeDetector and other minor things
This commit is contained in:
parent
6a3eb3d038
commit
ef3d235e79
24
t/bridges.t
24
t/bridges.t
@ -82,8 +82,27 @@ use Slic3r::Test;
|
|||||||
ok check_angle($lower, $bridge, 45, undef, $bridge->area/2), 'correct bridge angle for square overhang with L-shaped anchors';
|
ok check_angle($lower, $bridge, 45, undef, $bridge->area/2), 'correct bridge angle for square overhang with L-shaped anchors';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (0) {
|
||||||
|
# GH #2477:
|
||||||
|
# This rectangle-shaped bridge is actually unsupported (i.e. the potential anchors are
|
||||||
|
# a bit far away from the contour of the bridge area) because perimeters are reducing
|
||||||
|
# its area.
|
||||||
|
my $bridge = Slic3r::ExPolygon->new(
|
||||||
|
Slic3r::Polygon->new([30023195,14023195],[1776805,14023195],[1776805,1776805],[30023195,1776805]),
|
||||||
|
);
|
||||||
|
my $lower = [
|
||||||
|
Slic3r::ExPolygon->new(
|
||||||
|
Slic3r::Polygon->new([31800000,15800000],[0,15800000],[0,0],[31800000,0]),
|
||||||
|
Slic3r::Polygon->new([1499999,1500000],[1499999,14300000],[30300000,14300000],[30300000,1500000]),
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
ok check_angle($lower, $bridge, 90, undef, $bridge->area, 500000),
|
||||||
|
'correct bridge angle for rectangle';
|
||||||
|
}
|
||||||
|
|
||||||
sub check_angle {
|
sub check_angle {
|
||||||
my ($lower, $bridge, $expected, $tolerance, $expected_coverage) = @_;
|
my ($lower, $bridge, $expected, $tolerance, $expected_coverage, $extrusion_width) = @_;
|
||||||
|
|
||||||
if (ref($lower) eq 'ARRAY') {
|
if (ref($lower) eq 'ARRAY') {
|
||||||
$lower = Slic3r::ExPolygon::Collection->new(@$lower);
|
$lower = Slic3r::ExPolygon::Collection->new(@$lower);
|
||||||
@ -91,8 +110,9 @@ sub check_angle {
|
|||||||
|
|
||||||
$expected_coverage //= -1;
|
$expected_coverage //= -1;
|
||||||
$expected_coverage = $bridge->area if $expected_coverage == -1;
|
$expected_coverage = $bridge->area if $expected_coverage == -1;
|
||||||
|
$extrusion_width //= scale 0.5;
|
||||||
|
|
||||||
my $bd = Slic3r::BridgeDetector->new($bridge, $lower, scale 0.5);
|
my $bd = Slic3r::BridgeDetector->new($bridge, $lower, $extrusion_width);
|
||||||
|
|
||||||
$tolerance //= rad2deg($bd->resolution) + epsilon;
|
$tolerance //= rad2deg($bd->resolution) + epsilon;
|
||||||
$bd->detect_angle;
|
$bd->detect_angle;
|
||||||
|
@ -26,16 +26,16 @@ BridgeDetector::BridgeDetector(const ExPolygon &_expolygon, const ExPolygonColle
|
|||||||
// safety offset required to avoid Clipper from detecting empty intersection while Boost actually found some edges
|
// safety offset required to avoid Clipper from detecting empty intersection while Boost actually found some edges
|
||||||
this->_anchors = intersection_ex(grown, this->lower_slices, true);
|
this->_anchors = intersection_ex(grown, this->lower_slices, true);
|
||||||
|
|
||||||
/*
|
#if 0
|
||||||
if (0) {
|
{
|
||||||
require "Slic3r/SVG.pm";
|
SVG svg("bridge.svg");
|
||||||
Slic3r::SVG::output("bridge.svg",
|
svg.draw(this->expolygon);
|
||||||
expolygons => [ $self->expolygon ],
|
svg.draw(this->lower_slices, "red");
|
||||||
red_expolygons => $self->lower_slices,
|
svg.draw(this->_anchors, "yellow");
|
||||||
polylines => $self->_edges,
|
//svg.draw(this->_edges, "black", scale_(0.2));
|
||||||
);
|
svg.Close();
|
||||||
}
|
}
|
||||||
*/
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@ -48,7 +48,7 @@ BridgeDetector::detect_angle()
|
|||||||
/* Outset the bridge expolygon by half the amount we used for detecting anchors;
|
/* Outset the bridge expolygon by half the amount we used for detecting anchors;
|
||||||
we'll use this one to clip our test lines and be sure that their endpoints
|
we'll use this one to clip our test lines and be sure that their endpoints
|
||||||
are inside the anchors and not on their contours leading to false negatives. */
|
are inside the anchors and not on their contours leading to false negatives. */
|
||||||
Polygons clip_area = offset(this->expolygon, +this->extrusion_width/2);
|
const Polygons clip_area = offset(this->expolygon, +this->extrusion_width/2);
|
||||||
|
|
||||||
/* we'll now try several directions using a rudimentary visibility check:
|
/* we'll now try several directions using a rudimentary visibility check:
|
||||||
bridge in several directions and then sum the length of lines having both
|
bridge in several directions and then sum the length of lines having both
|
||||||
@ -74,13 +74,13 @@ BridgeDetector::detect_angle()
|
|||||||
|
|
||||||
/* we also test angles of each open supporting edge
|
/* we also test angles of each open supporting edge
|
||||||
(this finds the optimal angle for C-shaped supports) */
|
(this finds the optimal angle for C-shaped supports) */
|
||||||
for (Polylines::const_iterator edge = this->_edges.begin(); edge != this->_edges.end(); ++edge) {
|
for (const Polyline &edge : this->_edges) {
|
||||||
if (edge->first_point().coincides_with(edge->last_point())) continue;
|
if (edge.first_point().coincides_with(edge.last_point())) continue;
|
||||||
angles.push_back(Line(edge->first_point(), edge->last_point()).direction());
|
angles.push_back(Line(edge.first_point(), edge.last_point()).direction());
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove duplicates
|
// remove duplicates
|
||||||
double min_resolution = PI/180.0; // 1 degree
|
constexpr double min_resolution = PI/180.0; // 1 degree
|
||||||
std::sort(angles.begin(), angles.end());
|
std::sort(angles.begin(), angles.end());
|
||||||
for (size_t i = 1; i < angles.size(); ++i) {
|
for (size_t i = 1; i < angles.size(); ++i) {
|
||||||
if (Slic3r::Geometry::directions_parallel(angles[i], angles[i-1], min_resolution)) {
|
if (Slic3r::Geometry::directions_parallel(angles[i], angles[i-1], min_resolution)) {
|
||||||
@ -97,7 +97,7 @@ BridgeDetector::detect_angle()
|
|||||||
candidates.push_back(BridgeDirection(angle));
|
candidates.push_back(BridgeDirection(angle));
|
||||||
}
|
}
|
||||||
|
|
||||||
double line_increment = this->extrusion_width;
|
const double line_increment = this->extrusion_width;
|
||||||
bool have_coverage = false;
|
bool have_coverage = false;
|
||||||
for (BridgeDirection &candidate : candidates) {
|
for (BridgeDirection &candidate : candidates) {
|
||||||
Polygons my_clip_area = clip_area;
|
Polygons my_clip_area = clip_area;
|
||||||
@ -112,27 +112,22 @@ BridgeDetector::detect_angle()
|
|||||||
// generate lines in this direction
|
// generate lines in this direction
|
||||||
BoundingBox bb;
|
BoundingBox bb;
|
||||||
for (const ExPolygon &e : my_anchors)
|
for (const ExPolygon &e : my_anchors)
|
||||||
bb.merge((Points)e);
|
bb.merge(e.bounding_box());
|
||||||
|
|
||||||
Lines lines;
|
Lines lines;
|
||||||
for (coord_t y = bb.min.y; y <= bb.max.y; y += line_increment)
|
for (coord_t y = bb.min.y; y <= bb.max.y; y += line_increment)
|
||||||
lines.push_back(Line(Point(bb.min.x, y), Point(bb.max.x, y)));
|
lines.push_back(Line(Point(bb.min.x, y), Point(bb.max.x, y)));
|
||||||
|
|
||||||
Lines clipped_lines = intersection_ln(lines, my_clip_area);
|
const Lines clipped_lines = intersection_ln(lines, my_clip_area);
|
||||||
|
|
||||||
// remove any line not having both endpoints within anchors
|
|
||||||
for (size_t i = 0; i < clipped_lines.size(); ++i) {
|
|
||||||
Line &line = clipped_lines[i];
|
|
||||||
if (!Slic3r::Geometry::contains(my_anchors, line.a)
|
|
||||||
|| !Slic3r::Geometry::contains(my_anchors, line.b)) {
|
|
||||||
clipped_lines.erase(clipped_lines.begin() + i);
|
|
||||||
--i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<double> lengths;
|
std::vector<double> lengths;
|
||||||
double total_length = 0;
|
double total_length = 0;
|
||||||
for (const Line &line : clipped_lines) {
|
for (const Line &line : clipped_lines) {
|
||||||
|
// skip any line not having both endpoints within anchors
|
||||||
|
if (!Slic3r::Geometry::contains(my_anchors, line.a)
|
||||||
|
|| !Slic3r::Geometry::contains(my_anchors, line.b))
|
||||||
|
continue;
|
||||||
|
|
||||||
const double len = line.length();
|
const double len = line.length();
|
||||||
lengths.push_back(len);
|
lengths.push_back(len);
|
||||||
total_length += len;
|
total_length += len;
|
||||||
@ -220,13 +215,13 @@ BridgeDetector::coverage(double angle) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
// merge trapezoids and rotate them back
|
// merge trapezoids and rotate them back
|
||||||
Polygons _coverage = union_(covered);
|
covered = union_(covered);
|
||||||
for (Polygons::iterator p = _coverage.begin(); p != _coverage.end(); ++p)
|
for (Polygon &p : covered)
|
||||||
p->rotate(-(PI/2.0 - angle), Point(0,0));
|
p.rotate(-(PI/2.0 - angle), Point(0,0));
|
||||||
|
|
||||||
// intersect trapezoids with actual bridge area to remove extra margins
|
// intersect trapezoids with actual bridge area to remove extra margins
|
||||||
// and append it to result
|
// and append it to result
|
||||||
return intersection(_coverage, this->expolygon);
|
return intersection(covered, this->expolygon);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
if (0) {
|
if (0) {
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#define slic3r_ExPolygon_hpp_
|
#define slic3r_ExPolygon_hpp_
|
||||||
|
|
||||||
#include "libslic3r.h"
|
#include "libslic3r.h"
|
||||||
|
#include "BoundingBox.hpp"
|
||||||
#include "Polygon.hpp"
|
#include "Polygon.hpp"
|
||||||
#include "Polyline.hpp"
|
#include "Polyline.hpp"
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
@ -30,6 +31,7 @@ class ExPolygon
|
|||||||
bool contains(const Point &point) const;
|
bool contains(const Point &point) const;
|
||||||
bool contains_b(const Point &point) const;
|
bool contains_b(const Point &point) const;
|
||||||
bool has_boundary_point(const Point &point) const;
|
bool has_boundary_point(const Point &point) const;
|
||||||
|
BoundingBox bounding_box() const { return this->contour.bounding_box(); };
|
||||||
void remove_vertical_collinear_points(coord_t tolerance);
|
void remove_vertical_collinear_points(coord_t tolerance);
|
||||||
void simplify_p(double tolerance, Polygons* polygons) const;
|
void simplify_p(double tolerance, Polygons* polygons) const;
|
||||||
Polygons simplify_p(double tolerance) const;
|
Polygons simplify_p(double tolerance) const;
|
||||||
|
@ -71,13 +71,12 @@ void
|
|||||||
LayerRegion::process_external_surfaces()
|
LayerRegion::process_external_surfaces()
|
||||||
{
|
{
|
||||||
const Surfaces &surfaces = this->fill_surfaces.surfaces;
|
const Surfaces &surfaces = this->fill_surfaces.surfaces;
|
||||||
const double margin = scale_(EXTERNAL_INFILL_MARGIN);
|
|
||||||
|
|
||||||
SurfaceCollection bottom;
|
SurfaceCollection bottom;
|
||||||
for (Surfaces::const_iterator surface = surfaces.begin(); surface != surfaces.end(); ++surface) {
|
for (Surfaces::const_iterator surface = surfaces.begin(); surface != surfaces.end(); ++surface) {
|
||||||
if (!surface->is_bottom()) continue;
|
if (!surface->is_bottom()) continue;
|
||||||
|
|
||||||
const ExPolygons grown = offset_ex(surface->expolygon, +margin);
|
const ExPolygons grown = offset_ex(surface->expolygon, +SCALED_EXTERNAL_INFILL_MARGIN);
|
||||||
|
|
||||||
/* detect bridge direction before merging grown surfaces otherwise adjacent bridges
|
/* detect bridge direction before merging grown surfaces otherwise adjacent bridges
|
||||||
would get merged into a single one while they need different directions
|
would get merged into a single one while they need different directions
|
||||||
@ -92,7 +91,7 @@ LayerRegion::process_external_surfaces()
|
|||||||
);
|
);
|
||||||
|
|
||||||
#ifdef SLIC3R_DEBUG
|
#ifdef SLIC3R_DEBUG
|
||||||
printf("Processing bridge at layer %zu:\n", this->layer()->id());
|
printf("Processing bridge at layer %zu (z = %f):\n", this->layer()->id(), this->layer()->print_z);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (bd.detect_angle()) {
|
if (bd.detect_angle()) {
|
||||||
@ -119,7 +118,7 @@ LayerRegion::process_external_surfaces()
|
|||||||
|
|
||||||
// give priority to bottom surfaces
|
// give priority to bottom surfaces
|
||||||
ExPolygons grown = diff_ex(
|
ExPolygons grown = diff_ex(
|
||||||
offset(surface->expolygon, +margin),
|
offset(surface->expolygon, +SCALED_EXTERNAL_INFILL_MARGIN),
|
||||||
(Polygons)bottom
|
(Polygons)bottom
|
||||||
);
|
);
|
||||||
for (ExPolygons::const_iterator it = grown.begin(); it != grown.end(); ++it) {
|
for (ExPolygons::const_iterator it = grown.begin(); it != grown.end(); ++it) {
|
||||||
|
@ -35,6 +35,11 @@ SVG::SVG(const char* filename, const BoundingBox &bbox)
|
|||||||
h, w);
|
h, w);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SVG::~SVG()
|
||||||
|
{
|
||||||
|
this->Close();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
SVG::draw(const Line &line, std::string stroke, coord_t stroke_width)
|
SVG::draw(const Line &line, std::string stroke, coord_t stroke_width)
|
||||||
{
|
{
|
||||||
@ -68,10 +73,10 @@ void SVG::draw(const ThickLine &line, const std::string &fill, const std::string
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
SVG::draw(const Lines &lines, std::string stroke)
|
SVG::draw(const Lines &lines, std::string stroke, coord_t stroke_width)
|
||||||
{
|
{
|
||||||
for (Lines::const_iterator it = lines.begin(); it != lines.end(); ++it)
|
for (Lines::const_iterator it = lines.begin(); it != lines.end(); ++it)
|
||||||
this->draw(*it, stroke);
|
this->draw(*it, stroke, stroke_width);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -94,6 +99,12 @@ SVG::draw(const ExPolygon &expolygon, std::string fill)
|
|||||||
this->path(d, true);
|
this->path(d, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SVG::draw(const ExPolygonCollection &coll, std::string fill)
|
||||||
|
{
|
||||||
|
this->draw(coll.expolygons, fill);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
SVG::draw(const ExPolygons &expolygons, std::string fill)
|
SVG::draw(const ExPolygons &expolygons, std::string fill)
|
||||||
{
|
{
|
||||||
@ -126,7 +137,7 @@ void
|
|||||||
SVG::draw(const Polylines &polylines, std::string stroke, coord_t stroke_width)
|
SVG::draw(const Polylines &polylines, std::string stroke, coord_t stroke_width)
|
||||||
{
|
{
|
||||||
for (Polylines::const_iterator it = polylines.begin(); it != polylines.end(); ++it)
|
for (Polylines::const_iterator it = polylines.begin(); it != polylines.end(); ++it)
|
||||||
this->draw(*it, fill, stroke_width);
|
this->draw(*it, stroke, stroke_width);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SVG::draw(const ThickLines &thicklines, const std::string &fill, const std::string &stroke, coord_t stroke_width)
|
void SVG::draw(const ThickLines &thicklines, const std::string &fill, const std::string &stroke, coord_t stroke_width)
|
||||||
@ -202,9 +213,12 @@ SVG::get_path_d(const MultiPoint &mp, bool closed) const
|
|||||||
void
|
void
|
||||||
SVG::Close()
|
SVG::Close()
|
||||||
{
|
{
|
||||||
fprintf(this->f, "</svg>\n");
|
if (this->f != NULL) {
|
||||||
fclose(this->f);
|
fprintf(this->f, "</svg>\n");
|
||||||
printf("SVG written to %s\n", this->filename.c_str());
|
fclose(this->f);
|
||||||
|
this->f = NULL;
|
||||||
|
printf("SVG written to %s\n", this->filename.c_str());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "libslic3r.h"
|
#include "libslic3r.h"
|
||||||
#include "ExPolygon.hpp"
|
#include "ExPolygon.hpp"
|
||||||
|
#include "ExPolygonCollection.hpp"
|
||||||
#include "Line.hpp"
|
#include "Line.hpp"
|
||||||
#include "TriangleMesh.hpp"
|
#include "TriangleMesh.hpp"
|
||||||
|
|
||||||
@ -17,12 +18,14 @@ class SVG
|
|||||||
|
|
||||||
SVG(const char* filename);
|
SVG(const char* filename);
|
||||||
SVG(const char* filename, const BoundingBox &bbox);
|
SVG(const char* filename, const BoundingBox &bbox);
|
||||||
|
~SVG();
|
||||||
void draw(const Line &line, std::string stroke = "black", coord_t stroke_width = 0);
|
void draw(const Line &line, std::string stroke = "black", coord_t stroke_width = 0);
|
||||||
void draw(const ThickLine &line, const std::string &fill, const std::string &stroke, coord_t stroke_width = 0);
|
void draw(const ThickLine &line, const std::string &fill, const std::string &stroke, coord_t stroke_width = 0);
|
||||||
void draw(const Lines &lines, std::string stroke = "black");
|
void draw(const Lines &lines, std::string stroke = "black", coord_t stroke_width = 0);
|
||||||
void draw(const IntersectionLines &lines, std::string stroke = "black");
|
void draw(const IntersectionLines &lines, std::string stroke = "black");
|
||||||
void draw(const ExPolygon &expolygon, std::string fill = "grey");
|
void draw(const ExPolygon &expolygon, std::string fill = "grey");
|
||||||
void draw(const ExPolygons &expolygons, std::string fill = "grey");
|
void draw(const ExPolygons &expolygons, std::string fill = "grey");
|
||||||
|
void draw(const ExPolygonCollection &coll, std::string fill = "grey");
|
||||||
void draw(const Polygon &polygon, std::string fill = "grey");
|
void draw(const Polygon &polygon, std::string fill = "grey");
|
||||||
void draw(const Polygons &polygons, std::string fill = "grey");
|
void draw(const Polygons &polygons, std::string fill = "grey");
|
||||||
void draw(const Polyline &polyline, std::string stroke = "black", coord_t stroke_width = 0);
|
void draw(const Polyline &polyline, std::string stroke = "black", coord_t stroke_width = 0);
|
||||||
|
@ -64,6 +64,7 @@ constexpr auto LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER = 0.15;
|
|||||||
constexpr coord_t SMALL_PERIMETER_LENGTH = scale_(6.5) * 2 * PI;
|
constexpr coord_t SMALL_PERIMETER_LENGTH = scale_(6.5) * 2 * PI;
|
||||||
constexpr coordf_t INSET_OVERLAP_TOLERANCE = 0.4;
|
constexpr coordf_t INSET_OVERLAP_TOLERANCE = 0.4;
|
||||||
constexpr coordf_t EXTERNAL_INFILL_MARGIN = 3;
|
constexpr coordf_t EXTERNAL_INFILL_MARGIN = 3;
|
||||||
|
constexpr coord_t SCALED_EXTERNAL_INFILL_MARGIN = scale_(EXTERNAL_INFILL_MARGIN);
|
||||||
|
|
||||||
enum Axis { X=0, Y, Z };
|
enum Axis { X=0, Y, Z };
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user