Skip to content

Commit

Permalink
Further cleanup of BridgeDetector and other minor things
Browse files Browse the repository at this point in the history
  • Loading branch information
alranel committed Apr 3, 2017
1 parent 6a3eb3d commit ef3d235
Show file tree
Hide file tree
Showing 7 changed files with 78 additions and 44 deletions.
24 changes: 22 additions & 2 deletions t/bridges.t
Original file line number Diff line number Diff line change
Expand Up @@ -82,17 +82,37 @@ use Slic3r::Test;
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 {
my ($lower, $bridge, $expected, $tolerance, $expected_coverage) = @_;
my ($lower, $bridge, $expected, $tolerance, $expected_coverage, $extrusion_width) = @_;

if (ref($lower) eq 'ARRAY') {
$lower = Slic3r::ExPolygon::Collection->new(@$lower);
}

$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;
$bd->detect_angle;
Expand Down
57 changes: 26 additions & 31 deletions xs/src/libslic3r/BridgeDetector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
this->_anchors = intersection_ex(grown, this->lower_slices, true);

/*
if (0) {
require "Slic3r/SVG.pm";
Slic3r::SVG::output("bridge.svg",
expolygons => [ $self->expolygon ],
red_expolygons => $self->lower_slices,
polylines => $self->_edges,
);
#if 0
{
SVG svg("bridge.svg");
svg.draw(this->expolygon);
svg.draw(this->lower_slices, "red");
svg.draw(this->_anchors, "yellow");
//svg.draw(this->_edges, "black", scale_(0.2));
svg.Close();
}
*/
#endif
}

bool
Expand All @@ -48,7 +48,7 @@ BridgeDetector::detect_angle()
/* 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
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:
bridge in several directions and then sum the length of lines having both
Expand All @@ -74,13 +74,13 @@ BridgeDetector::detect_angle()

/* we also test angles of each open supporting edge
(this finds the optimal angle for C-shaped supports) */
for (Polylines::const_iterator edge = this->_edges.begin(); edge != this->_edges.end(); ++edge) {
if (edge->first_point().coincides_with(edge->last_point())) continue;
angles.push_back(Line(edge->first_point(), edge->last_point()).direction());
for (const Polyline &edge : this->_edges) {
if (edge.first_point().coincides_with(edge.last_point())) continue;
angles.push_back(Line(edge.first_point(), edge.last_point()).direction());
}

// 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());
for (size_t i = 1; i < angles.size(); ++i) {
if (Slic3r::Geometry::directions_parallel(angles[i], angles[i-1], min_resolution)) {
Expand All @@ -97,7 +97,7 @@ BridgeDetector::detect_angle()
candidates.push_back(BridgeDirection(angle));
}

double line_increment = this->extrusion_width;
const double line_increment = this->extrusion_width;
bool have_coverage = false;
for (BridgeDirection &candidate : candidates) {
Polygons my_clip_area = clip_area;
Expand All @@ -112,27 +112,22 @@ BridgeDetector::detect_angle()
// generate lines in this direction
BoundingBox bb;
for (const ExPolygon &e : my_anchors)
bb.merge((Points)e);
bb.merge(e.bounding_box());

Lines lines;
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 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;
}
}
const Lines clipped_lines = intersection_ln(lines, my_clip_area);

std::vector<double> lengths;
double total_length = 0;
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();
lengths.push_back(len);
total_length += len;
Expand Down Expand Up @@ -220,13 +215,13 @@ BridgeDetector::coverage(double angle) const
}

// merge trapezoids and rotate them back
Polygons _coverage = union_(covered);
for (Polygons::iterator p = _coverage.begin(); p != _coverage.end(); ++p)
p->rotate(-(PI/2.0 - angle), Point(0,0));
covered = union_(covered);
for (Polygon &p : covered)
p.rotate(-(PI/2.0 - angle), Point(0,0));

// intersect trapezoids with actual bridge area to remove extra margins
// and append it to result
return intersection(_coverage, this->expolygon);
return intersection(covered, this->expolygon);

/*
if (0) {
Expand Down
2 changes: 2 additions & 0 deletions xs/src/libslic3r/ExPolygon.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#define slic3r_ExPolygon_hpp_

#include "libslic3r.h"
#include "BoundingBox.hpp"
#include "Polygon.hpp"
#include "Polyline.hpp"
#include <ostream>
Expand Down Expand Up @@ -30,6 +31,7 @@ class ExPolygon
bool contains(const Point &point) const;
bool contains_b(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 simplify_p(double tolerance, Polygons* polygons) const;
Polygons simplify_p(double tolerance) const;
Expand Down
7 changes: 3 additions & 4 deletions xs/src/libslic3r/LayerRegion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,12 @@ void
LayerRegion::process_external_surfaces()
{
const Surfaces &surfaces = this->fill_surfaces.surfaces;
const double margin = scale_(EXTERNAL_INFILL_MARGIN);

SurfaceCollection bottom;
for (Surfaces::const_iterator surface = surfaces.begin(); surface != surfaces.end(); ++surface) {
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
would get merged into a single one while they need different directions
Expand All @@ -92,7 +91,7 @@ LayerRegion::process_external_surfaces()
);

#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

if (bd.detect_angle()) {
Expand All @@ -119,7 +118,7 @@ LayerRegion::process_external_surfaces()

// give priority to bottom surfaces
ExPolygons grown = diff_ex(
offset(surface->expolygon, +margin),
offset(surface->expolygon, +SCALED_EXTERNAL_INFILL_MARGIN),
(Polygons)bottom
);
for (ExPolygons::const_iterator it = grown.begin(); it != grown.end(); ++it) {
Expand Down
26 changes: 20 additions & 6 deletions xs/src/libslic3r/SVG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ SVG::SVG(const char* filename, const BoundingBox &bbox)
h, w);
}

SVG::~SVG()
{
this->Close();
}

void
SVG::draw(const Line &line, std::string stroke, coord_t stroke_width)
{
Expand Down Expand Up @@ -68,10 +73,10 @@ void SVG::draw(const ThickLine &line, const std::string &fill, const std::string
}

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)
this->draw(*it, stroke);
this->draw(*it, stroke, stroke_width);
}

void
Expand All @@ -94,6 +99,12 @@ SVG::draw(const ExPolygon &expolygon, std::string fill)
this->path(d, true);
}

void
SVG::draw(const ExPolygonCollection &coll, std::string fill)
{
this->draw(coll.expolygons, fill);
}

void
SVG::draw(const ExPolygons &expolygons, std::string fill)
{
Expand Down Expand Up @@ -126,7 +137,7 @@ void
SVG::draw(const Polylines &polylines, std::string stroke, coord_t stroke_width)
{
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)
Expand Down Expand Up @@ -202,9 +213,12 @@ SVG::get_path_d(const MultiPoint &mp, bool closed) const
void
SVG::Close()
{
fprintf(this->f, "</svg>\n");
fclose(this->f);
printf("SVG written to %s\n", this->filename.c_str());
if (this->f != NULL) {
fprintf(this->f, "</svg>\n");
fclose(this->f);
this->f = NULL;
printf("SVG written to %s\n", this->filename.c_str());
}
}

}
5 changes: 4 additions & 1 deletion xs/src/libslic3r/SVG.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include "libslic3r.h"
#include "ExPolygon.hpp"
#include "ExPolygonCollection.hpp"
#include "Line.hpp"
#include "TriangleMesh.hpp"

Expand All @@ -17,12 +18,14 @@ class SVG

SVG(const char* filename);
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 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 ExPolygon &expolygon, 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 Polygons &polygons, std::string fill = "grey");
void draw(const Polyline &polyline, std::string stroke = "black", coord_t stroke_width = 0);
Expand Down
1 change: 1 addition & 0 deletions xs/src/libslic3r/libslic3r.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 coordf_t INSET_OVERLAP_TOLERANCE = 0.4;
constexpr coordf_t EXTERNAL_INFILL_MARGIN = 3;
constexpr coord_t SCALED_EXTERNAL_INFILL_MARGIN = scale_(EXTERNAL_INFILL_MARGIN);

enum Axis { X=0, Y, Z };

Expand Down

0 comments on commit ef3d235

Please sign in to comment.