CLIPPER_OFFSET_SCALE was made a power of two, the scaling functions

inside ClipperUtils are now using bit shifts instead of multiplication
by doubles, which makes the scaling precise.

Removed the scale parameter from all offset functions.

Modified the safety offset to calculate offset per polygon instead
of over all polygons at once. The old way was not safe and very slow,
sometimes this meant a kiss of death for supports for example.
This commit is contained in:
bubnikv 2016-11-28 17:33:17 +01:00
parent e93253e270
commit 695c92fb00
14 changed files with 214 additions and 152 deletions

View File

@ -173,7 +173,7 @@ sub repaint {
# if sequential printing is enabled and we have more than one object, draw clearance area # if sequential printing is enabled and we have more than one object, draw clearance area
if ($self->{config}->complete_objects && (map @{$_->instances}, @{$self->{model}->objects}) > 1) { if ($self->{config}->complete_objects && (map @{$_->instances}, @{$self->{model}->objects}) > 1) {
my ($clearance) = @{offset([$thumbnail->convex_hull], (scale($self->{config}->extruder_clearance_radius) / 2), 1, JT_ROUND, scale(0.1))}; my ($clearance) = @{offset([$thumbnail->convex_hull], (scale($self->{config}->extruder_clearance_radius) / 2), JT_ROUND, scale(0.1))};
$dc->SetPen($self->{clearance_pen}); $dc->SetPen($self->{clearance_pen});
$dc->SetBrush($self->{transparent_brush}); $dc->SetBrush($self->{transparent_brush});
$dc->DrawPolygon($self->scaled_points_to_pixel($clearance, 1), 0, 0); $dc->DrawPolygon($self->scaled_points_to_pixel($clearance, 1), 0, 0);
@ -185,7 +185,7 @@ sub repaint {
if (@{$self->{objects}} && $self->{config}->skirts) { if (@{$self->{objects}} && $self->{config}->skirts) {
my @points = map @{$_->contour}, map @$_, map @{$_->instance_thumbnails}, @{$self->{objects}}; my @points = map @{$_->contour}, map @$_, map @{$_->instance_thumbnails}, @{$self->{objects}};
if (@points >= 3) { if (@points >= 3) {
my ($convex_hull) = @{offset([convex_hull(\@points)], scale max($self->{config}->brim_width + $self->{config}->skirt_distance), 1, JT_ROUND, scale(0.1))}; my ($convex_hull) = @{offset([convex_hull(\@points)], scale max($self->{config}->brim_width + $self->{config}->skirt_distance), JT_ROUND, scale(0.1))};
$dc->SetPen($self->{skirt_pen}); $dc->SetPen($self->{skirt_pen});
$dc->SetBrush($self->{transparent_brush}); $dc->SetBrush($self->{transparent_brush});
$dc->DrawPolygon($self->scaled_points_to_pixel($convex_hull, 1), 0, 0); $dc->DrawPolygon($self->scaled_points_to_pixel($convex_hull, 1), 0, 0);

View File

@ -7,7 +7,7 @@ our @ISA = qw(Exporter);
our @EXPORT_OK = qw(offset offset_ex our @EXPORT_OK = qw(offset offset_ex
diff_ex diff union_ex intersection_ex xor_ex JT_ROUND JT_MITER diff_ex diff union_ex intersection_ex xor_ex JT_ROUND JT_MITER
JT_SQUARE is_counter_clockwise union_pt offset2 offset2_ex JT_SQUARE is_counter_clockwise union_pt offset2 offset2_ex
intersection intersection_pl diff_pl union CLIPPER_OFFSET_SCALE intersection intersection_pl diff_pl union
union_pt_chained diff_ppl intersection_ppl); union_pt_chained diff_ppl intersection_ppl);
1; 1;

View File

@ -276,7 +276,7 @@ sub make_skirt {
my $distance = scale max($self->config->skirt_distance, $self->config->brim_width); my $distance = scale max($self->config->skirt_distance, $self->config->brim_width);
for (my $i = $skirts; $i > 0; $i--) { for (my $i = $skirts; $i > 0; $i--) {
$distance += scale $spacing; $distance += scale $spacing;
my $loop = offset([$convex_hull], $distance, 1, JT_ROUND, scale(0.1))->[0]; my $loop = offset([$convex_hull], $distance, JT_ROUND, scale(0.1))->[0];
my $eloop = Slic3r::ExtrusionLoop->new_from_paths( my $eloop = Slic3r::ExtrusionLoop->new_from_paths(
Slic3r::ExtrusionPath->new( Slic3r::ExtrusionPath->new(
polyline => Slic3r::Polygon->new(@$loop)->split_at_first_point, polyline => Slic3r::Polygon->new(@$loop)->split_at_first_point,
@ -369,7 +369,7 @@ sub make_brim {
# -0.5 because islands are not represented by their centerlines # -0.5 because islands are not represented by their centerlines
# (first offset more, then step back - reverse order than the one used for # (first offset more, then step back - reverse order than the one used for
# perimeters because here we're offsetting outwards) # perimeters because here we're offsetting outwards)
push @loops, @{offset2(\@islands, ($i + 0.5) * $flow->scaled_spacing, -1.0 * $flow->scaled_spacing, 100000, JT_SQUARE)}; push @loops, @{offset2(\@islands, ($i + 0.5) * $flow->scaled_spacing, -1.0 * $flow->scaled_spacing, JT_SQUARE)};
} }
$self->brim->append(map Slic3r::ExtrusionLoop->new_from_paths( $self->brim->append(map Slic3r::ExtrusionLoop->new_from_paths(

View File

@ -7,7 +7,7 @@ use List::Util qw(min max sum first);
use Slic3r::Flow ':roles'; use Slic3r::Flow ':roles';
use Slic3r::Geometry qw(X Y Z PI scale unscale chained_path epsilon); use Slic3r::Geometry qw(X Y Z PI scale unscale chained_path epsilon);
use Slic3r::Geometry::Clipper qw(diff diff_ex intersection intersection_ex union union_ex use Slic3r::Geometry::Clipper qw(diff diff_ex intersection intersection_ex union union_ex
offset offset_ex offset2 offset2_ex intersection_ppl CLIPPER_OFFSET_SCALE JT_MITER); offset offset_ex offset2 offset2_ex intersection_ppl JT_MITER);
use Slic3r::Print::State ':steps'; use Slic3r::Print::State ':steps';
use Slic3r::Surface ':types'; use Slic3r::Surface ':types';
@ -863,7 +863,7 @@ sub discover_horizontal_shells {
# and it's not wanted in a hollow print even if it would make sense when # and it's not wanted in a hollow print even if it would make sense when
# obeying the solid shell count option strictly (DWIM!) # obeying the solid shell count option strictly (DWIM!)
my $margin = $neighbor_layerm->flow(FLOW_ROLE_EXTERNAL_PERIMETER)->scaled_width; my $margin = $neighbor_layerm->flow(FLOW_ROLE_EXTERNAL_PERIMETER)->scaled_width;
my $regularized = offset2($new_internal_solid, -$margin, +$margin, CLIPPER_OFFSET_SCALE, JT_MITER, 5); my $regularized = offset2($new_internal_solid, -$margin, +$margin, JT_MITER, 5);
my $too_narrow = diff( my $too_narrow = diff(
$new_internal_solid, $new_internal_solid,
$regularized, $regularized,
@ -893,7 +893,7 @@ sub discover_horizontal_shells {
# have the same angle, so the next shell would be grown even more and so on. # have the same angle, so the next shell would be grown even more and so on.
my $too_narrow = diff( my $too_narrow = diff(
$new_internal_solid, $new_internal_solid,
offset2($new_internal_solid, -$margin, +$margin, CLIPPER_OFFSET_SCALE, JT_MITER, 5), offset2($new_internal_solid, -$margin, +$margin, JT_MITER, 5),
1, 1,
); );

View File

@ -8,7 +8,7 @@ use Slic3r::ExtrusionPath ':roles';
use Slic3r::Flow ':roles'; use Slic3r::Flow ':roles';
use Slic3r::Geometry qw(epsilon scale scaled_epsilon PI rad2deg deg2rad convex_hull); use Slic3r::Geometry qw(epsilon scale scaled_epsilon PI rad2deg deg2rad convex_hull);
use Slic3r::Geometry::Clipper qw(offset diff union union_ex intersection offset_ex offset2 use Slic3r::Geometry::Clipper qw(offset diff union union_ex intersection offset_ex offset2
intersection_pl offset2_ex diff_pl CLIPPER_OFFSET_SCALE JT_MITER JT_ROUND); intersection_pl offset2_ex diff_pl JT_MITER JT_ROUND);
use Slic3r::Surface ':types'; use Slic3r::Surface ':types';
has 'print_config' => (is => 'rw', required => 1); has 'print_config' => (is => 'rw', required => 1);
@ -299,9 +299,8 @@ sub contact_area {
offset( offset(
$diff, $diff,
$_, $_,
CLIPPER_OFFSET_SCALE,
JT_ROUND, JT_ROUND,
scale(0.05)*CLIPPER_OFFSET_SCALE), scale(0.05)),
$slices_margin $slices_margin
); );
} }
@ -584,9 +583,8 @@ sub generate_base_layers {
$fillet_radius_scaled, $fillet_radius_scaled,
-$fillet_radius_scaled, -$fillet_radius_scaled,
# Use a geometric offsetting for filleting. # Use a geometric offsetting for filleting.
CLIPPER_OFFSET_SCALE,
JT_ROUND, JT_ROUND,
0.2*$fillet_radius_scaled*CLIPPER_OFFSET_SCALE), 0.2*$fillet_radius_scaled),
$trim_polygons, $trim_polygons,
0); # don't apply the safety offset. 0); # don't apply the safety offset.
} }

View File

@ -9,8 +9,51 @@
#include <Shiny/Shiny.h> #include <Shiny/Shiny.h>
// Factor to convert from coord_t (which is int32) to an int64 type used by the Clipper library
// for general offsetting (the offset(), offset2(), offset_ex() functions) and for the safety offset,
// which is optionally executed by other functions (union, intersection, diff).
// By the way, is the scalling for offset needed at all?
#define CLIPPER_OFFSET_POWER_OF_2 17
// 2^17=131072
#define CLIPPER_OFFSET_SCALE (1 << CLIPPER_OFFSET_POWER_OF_2)
#define CLIPPER_OFFSET_SCALE_ROUNDING_DELTA ((1 << (CLIPPER_OFFSET_POWER_OF_2 - 1)) - 1)
namespace Slic3r { namespace Slic3r {
#ifdef CLIPPER_UTILS_DEBUG
bool clipper_export_enabled = false;
// For debugging the Clipper library, for providing bug reports to the Clipper author.
bool export_clipper_input_polygons_bin(const char *path, const ClipperLib::Paths &input_subject, const ClipperLib::Paths &input_clip)
{
FILE *pfile = fopen(path, "wb");
if (pfile == NULL)
return false;
uint32_t sz = uint32_t(input_subject.size());
fwrite(&sz, 1, sizeof(sz), pfile);
for (size_t i = 0; i < input_subject.size(); ++i) {
const ClipperLib::Path &path = input_subject[i];
sz = uint32_t(path.size());
::fwrite(&sz, 1, sizeof(sz), pfile);
::fwrite(path.data(), sizeof(ClipperLib::IntPoint), sz, pfile);
}
sz = uint32_t(input_clip.size());
::fwrite(&sz, 1, sizeof(sz), pfile);
for (size_t i = 0; i < input_clip.size(); ++i) {
const ClipperLib::Path &path = input_clip[i];
sz = uint32_t(path.size());
::fwrite(&sz, 1, sizeof(sz), pfile);
::fwrite(path.data(), sizeof(ClipperLib::IntPoint), sz, pfile);
}
::fclose(pfile);
return true;
err:
::fclose(pfile);
return false;
}
#endif /* CLIPPER_UTILS_DEBUG */
//----------------------------------------------------------- //-----------------------------------------------------------
// legacy code from Clipper documentation // legacy code from Clipper documentation
void AddOuterPolyNodeToExPolygons(ClipperLib::PolyNode& polynode, Slic3r::ExPolygons* expolygons) void AddOuterPolyNodeToExPolygons(ClipperLib::PolyNode& polynode, Slic3r::ExPolygons* expolygons)
@ -120,37 +163,51 @@ Slic3rMultiPoints_to_ClipperPaths(const T &input, ClipperLib::Paths* output)
} }
} }
void void scaleClipperPolygon(ClipperLib::Path &polygon)
scaleClipperPolygon(ClipperLib::Path &polygon, const double scale)
{ {
PROFILE_FUNC(); PROFILE_FUNC();
for (ClipperLib::Path::iterator pit = polygon.begin(); pit != polygon.end(); ++pit) { for (ClipperLib::Path::iterator pit = polygon.begin(); pit != polygon.end(); ++pit) {
//FIXME multiplication of int64_t by double! pit->X <<= CLIPPER_OFFSET_POWER_OF_2;
// Replace by bit shifts? pit->Y <<= CLIPPER_OFFSET_POWER_OF_2;
(*pit).X *= scale;
(*pit).Y *= scale;
} }
} }
void void scaleClipperPolygons(ClipperLib::Paths &polygons)
scaleClipperPolygons(ClipperLib::Paths &polygons, const double scale)
{ {
PROFILE_FUNC(); PROFILE_FUNC();
for (ClipperLib::Paths::iterator it = polygons.begin(); it != polygons.end(); ++it)
for (ClipperLib::Paths::iterator it = polygons.begin(); it != polygons.end(); ++it) {
for (ClipperLib::Path::iterator pit = (*it).begin(); pit != (*it).end(); ++pit) { for (ClipperLib::Path::iterator pit = (*it).begin(); pit != (*it).end(); ++pit) {
//FIXME multiplication of int64_t by double! pit->X <<= CLIPPER_OFFSET_POWER_OF_2;
// Replace by bit shifts? pit->Y <<= CLIPPER_OFFSET_POWER_OF_2;
(*pit).X *= scale;
(*pit).Y *= scale;
} }
}
void unscaleClipperPolygon(ClipperLib::Path &polygon)
{
PROFILE_FUNC();
for (ClipperLib::Path::iterator pit = polygon.begin(); pit != polygon.end(); ++pit) {
pit->X += CLIPPER_OFFSET_SCALE_ROUNDING_DELTA;
pit->Y += CLIPPER_OFFSET_SCALE_ROUNDING_DELTA;
pit->X >>= CLIPPER_OFFSET_POWER_OF_2;
pit->Y >>= CLIPPER_OFFSET_POWER_OF_2;
} }
} }
void unscaleClipperPolygons(ClipperLib::Paths &polygons)
{
PROFILE_FUNC();
for (ClipperLib::Paths::iterator it = polygons.begin(); it != polygons.end(); ++it)
for (ClipperLib::Path::iterator pit = (*it).begin(); pit != (*it).end(); ++pit) {
pit->X += CLIPPER_OFFSET_SCALE_ROUNDING_DELTA;
pit->Y += CLIPPER_OFFSET_SCALE_ROUNDING_DELTA;
pit->X >>= CLIPPER_OFFSET_POWER_OF_2;
pit->Y >>= CLIPPER_OFFSET_POWER_OF_2;
}
}
void void
offset(const Slic3r::Polygons &polygons, ClipperLib::Paths* retval, const float delta, offset(const Slic3r::Polygons &polygons, ClipperLib::Paths* retval, const float delta,
double scale, ClipperLib::JoinType joinType, double miterLimit) ClipperLib::JoinType joinType, double miterLimit)
{ {
PROFILE_FUNC(); PROFILE_FUNC();
// read input // read input
@ -158,12 +215,12 @@ offset(const Slic3r::Polygons &polygons, ClipperLib::Paths* retval, const float
Slic3rMultiPoints_to_ClipperPaths(polygons, &input); Slic3rMultiPoints_to_ClipperPaths(polygons, &input);
// scale input // scale input
scaleClipperPolygons(input, scale); scaleClipperPolygons(input);
// perform offset // perform offset
ClipperLib::ClipperOffset co; ClipperLib::ClipperOffset co;
if (joinType == jtRound) { if (joinType == jtRound) {
co.ArcTolerance = miterLimit; co.ArcTolerance = miterLimit * double(CLIPPER_OFFSET_SCALE);
} else { } else {
co.MiterLimit = miterLimit; co.MiterLimit = miterLimit;
} }
@ -173,20 +230,20 @@ offset(const Slic3r::Polygons &polygons, ClipperLib::Paths* retval, const float
} }
{ {
PROFILE_BLOCK(offset_Execute); PROFILE_BLOCK(offset_Execute);
co.Execute(*retval, (delta*scale)); co.Execute(*retval, delta * float(CLIPPER_OFFSET_SCALE));
} }
// unscale output // unscale output
scaleClipperPolygons(*retval, 1/scale); unscaleClipperPolygons(*retval);
} }
void void
offset(const Slic3r::Polygons &polygons, Slic3r::Polygons* retval, const float delta, offset(const Slic3r::Polygons &polygons, Slic3r::Polygons* retval, const float delta,
double scale, ClipperLib::JoinType joinType, double miterLimit) ClipperLib::JoinType joinType, double miterLimit)
{ {
// perform offset // perform offset
ClipperLib::Paths output; ClipperLib::Paths output;
offset(polygons, &output, delta, scale, joinType, miterLimit); offset(polygons, &output, delta, joinType, miterLimit);
// convert into ExPolygons // convert into ExPolygons
ClipperPaths_to_Slic3rMultiPoints(output, retval); ClipperPaths_to_Slic3rMultiPoints(output, retval);
@ -194,45 +251,45 @@ offset(const Slic3r::Polygons &polygons, Slic3r::Polygons* retval, const float d
Slic3r::Polygons Slic3r::Polygons
offset(const Slic3r::Polygons &polygons, const float delta, offset(const Slic3r::Polygons &polygons, const float delta,
double scale, ClipperLib::JoinType joinType, double miterLimit) ClipperLib::JoinType joinType, double miterLimit)
{ {
Slic3r::Polygons pp; Slic3r::Polygons pp;
offset(polygons, &pp, delta, scale, joinType, miterLimit); offset(polygons, &pp, delta, joinType, miterLimit);
return pp; return pp;
} }
void void
offset(const Slic3r::Polylines &polylines, ClipperLib::Paths* retval, const float delta, offset(const Slic3r::Polylines &polylines, ClipperLib::Paths* retval, const float delta,
double scale, ClipperLib::JoinType joinType, double miterLimit) ClipperLib::JoinType joinType, double miterLimit)
{ {
// read input // read input
ClipperLib::Paths input; ClipperLib::Paths input;
Slic3rMultiPoints_to_ClipperPaths(polylines, &input); Slic3rMultiPoints_to_ClipperPaths(polylines, &input);
// scale input // scale input
scaleClipperPolygons(input, scale); scaleClipperPolygons(input);
// perform offset // perform offset
ClipperLib::ClipperOffset co; ClipperLib::ClipperOffset co;
if (joinType == jtRound) { if (joinType == jtRound) {
co.ArcTolerance = miterLimit; co.ArcTolerance = miterLimit * double(CLIPPER_OFFSET_SCALE);
} else { } else {
co.MiterLimit = miterLimit; co.MiterLimit = miterLimit;
} }
co.AddPaths(input, joinType, ClipperLib::etOpenButt); co.AddPaths(input, joinType, ClipperLib::etOpenButt);
co.Execute(*retval, (delta*scale)); co.Execute(*retval, delta * float(CLIPPER_OFFSET_SCALE));
// unscale output // unscale output
scaleClipperPolygons(*retval, 1/scale); unscaleClipperPolygons(*retval);
} }
void void
offset(const Slic3r::Polylines &polylines, Slic3r::Polygons* retval, const float delta, offset(const Slic3r::Polylines &polylines, Slic3r::Polygons* retval, const float delta,
double scale, ClipperLib::JoinType joinType, double miterLimit) ClipperLib::JoinType joinType, double miterLimit)
{ {
// perform offset // perform offset
ClipperLib::Paths output; ClipperLib::Paths output;
offset(polylines, &output, delta, scale, joinType, miterLimit); offset(polylines, &output, delta, joinType, miterLimit);
// convert into ExPolygons // convert into ExPolygons
ClipperPaths_to_Slic3rMultiPoints(output, retval); ClipperPaths_to_Slic3rMultiPoints(output, retval);
@ -240,11 +297,11 @@ offset(const Slic3r::Polylines &polylines, Slic3r::Polygons* retval, const float
void void
offset(const Slic3r::Surface &surface, Slic3r::Surfaces* retval, const float delta, offset(const Slic3r::Surface &surface, Slic3r::Surfaces* retval, const float delta,
double scale, ClipperLib::JoinType joinType, double miterLimit) ClipperLib::JoinType joinType, double miterLimit)
{ {
// perform offset // perform offset
Slic3r::ExPolygons expp; Slic3r::ExPolygons expp;
offset(surface.expolygon, &expp, delta, scale, joinType, miterLimit); offset(surface.expolygon, &expp, delta, joinType, miterLimit);
// clone the input surface for each expolygon we got // clone the input surface for each expolygon we got
retval->clear(); retval->clear();
@ -258,11 +315,11 @@ offset(const Slic3r::Surface &surface, Slic3r::Surfaces* retval, const float del
void void
offset(const Slic3r::Polygons &polygons, Slic3r::ExPolygons* retval, const float delta, offset(const Slic3r::Polygons &polygons, Slic3r::ExPolygons* retval, const float delta,
double scale, ClipperLib::JoinType joinType, double miterLimit) ClipperLib::JoinType joinType, double miterLimit)
{ {
// perform offset // perform offset
ClipperLib::Paths output; ClipperLib::Paths output;
offset(polygons, &output, delta, scale, joinType, miterLimit); offset(polygons, &output, delta, joinType, miterLimit);
// convert into ExPolygons // convert into ExPolygons
ClipperPaths_to_Slic3rExPolygons(output, retval); ClipperPaths_to_Slic3rExPolygons(output, retval);
@ -272,19 +329,19 @@ offset(const Slic3r::Polygons &polygons, Slic3r::ExPolygons* retval, const float
// a single polygon with multiple non-overlapping holes. // a single polygon with multiple non-overlapping holes.
// Each contour and hole is offsetted separately, then the holes are subtracted from the outer contours. // Each contour and hole is offsetted separately, then the holes are subtracted from the outer contours.
void offset(const Slic3r::ExPolygon &expolygon, ClipperLib::Paths* retval, const float delta, void offset(const Slic3r::ExPolygon &expolygon, ClipperLib::Paths* retval, const float delta,
double scale, ClipperLib::JoinType joinType, double miterLimit) ClipperLib::JoinType joinType, double miterLimit)
{ {
// printf("new ExPolygon offset\n"); // printf("new ExPolygon offset\n");
// 1) Offset the outer contour. // 1) Offset the outer contour.
const float delta_scaled = float(delta * scale); const float delta_scaled = delta * float(CLIPPER_OFFSET_SCALE);
ClipperLib::Paths contours; ClipperLib::Paths contours;
{ {
ClipperLib::Path input; ClipperLib::Path input;
Slic3rMultiPoint_to_ClipperPath(expolygon.contour, &input); Slic3rMultiPoint_to_ClipperPath(expolygon.contour, &input);
scaleClipperPolygon(input, scale); scaleClipperPolygon(input);
ClipperLib::ClipperOffset co; ClipperLib::ClipperOffset co;
if (joinType == jtRound) if (joinType == jtRound)
co.ArcTolerance = miterLimit; co.ArcTolerance = miterLimit * double(CLIPPER_OFFSET_SCALE);
else else
co.MiterLimit = miterLimit; co.MiterLimit = miterLimit;
co.AddPath(input, joinType, ClipperLib::etClosedPolygon); co.AddPath(input, joinType, ClipperLib::etClosedPolygon);
@ -298,10 +355,10 @@ void offset(const Slic3r::ExPolygon &expolygon, ClipperLib::Paths* retval, const
for (Polygons::const_iterator it_hole = expolygon.holes.begin(); it_hole != expolygon.holes.end(); ++ it_hole) { for (Polygons::const_iterator it_hole = expolygon.holes.begin(); it_hole != expolygon.holes.end(); ++ it_hole) {
ClipperLib::Path input; ClipperLib::Path input;
Slic3rMultiPoint_to_ClipperPath_reversed(*it_hole, &input); Slic3rMultiPoint_to_ClipperPath_reversed(*it_hole, &input);
scaleClipperPolygon(input, scale); scaleClipperPolygon(input);
ClipperLib::ClipperOffset co; ClipperLib::ClipperOffset co;
if (joinType == jtRound) if (joinType == jtRound)
co.ArcTolerance = miterLimit; co.ArcTolerance = miterLimit * double(CLIPPER_OFFSET_SCALE);
else else
co.MiterLimit = miterLimit; co.MiterLimit = miterLimit;
co.AddPath(input, joinType, ClipperLib::etClosedPolygon); co.AddPath(input, joinType, ClipperLib::etClosedPolygon);
@ -322,15 +379,15 @@ void offset(const Slic3r::ExPolygon &expolygon, ClipperLib::Paths* retval, const
} }
// 4) Unscale the output. // 4) Unscale the output.
scaleClipperPolygons(*retval, 1/scale); unscaleClipperPolygons(*retval);
} }
Slic3r::Polygons offset(const Slic3r::ExPolygon &expolygon, const float delta, Slic3r::Polygons offset(const Slic3r::ExPolygon &expolygon, const float delta,
double scale, ClipperLib::JoinType joinType, double miterLimit) ClipperLib::JoinType joinType, double miterLimit)
{ {
// perform offset // perform offset
ClipperLib::Paths output; ClipperLib::Paths output;
offset(expolygon, &output, delta, scale, joinType, miterLimit); offset(expolygon, &output, delta, joinType, miterLimit);
// convert into ExPolygons // convert into ExPolygons
Slic3r::Polygons retval; Slic3r::Polygons retval;
@ -339,11 +396,11 @@ Slic3r::Polygons offset(const Slic3r::ExPolygon &expolygon, const float delta,
} }
Slic3r::ExPolygons offset_ex(const Slic3r::ExPolygon &expolygon, const float delta, Slic3r::ExPolygons offset_ex(const Slic3r::ExPolygon &expolygon, const float delta,
double scale, ClipperLib::JoinType joinType, double miterLimit) ClipperLib::JoinType joinType, double miterLimit)
{ {
// perform offset // perform offset
ClipperLib::Paths output; ClipperLib::Paths output;
offset(expolygon, &output, delta, scale, joinType, miterLimit); offset(expolygon, &output, delta, joinType, miterLimit);
// convert into ExPolygons // convert into ExPolygons
Slic3r::ExPolygons retval; Slic3r::ExPolygons retval;
@ -355,10 +412,10 @@ Slic3r::ExPolygons offset_ex(const Slic3r::ExPolygon &expolygon, const float del
// a single polygon with multiple non-overlapping holes. // a single polygon with multiple non-overlapping holes.
// Each contour and hole is offsetted separately, then the holes are subtracted from the outer contours. // Each contour and hole is offsetted separately, then the holes are subtracted from the outer contours.
void offset(const Slic3r::ExPolygons &expolygons, ClipperLib::Paths* retval, const float delta, void offset(const Slic3r::ExPolygons &expolygons, ClipperLib::Paths* retval, const float delta,
double scale, ClipperLib::JoinType joinType, double miterLimit) ClipperLib::JoinType joinType, double miterLimit)
{ {
// printf("new ExPolygon offset\n"); // printf("new ExPolygon offset\n");
const float delta_scaled = float(delta * scale); const float delta_scaled = delta * float(CLIPPER_OFFSET_SCALE);
ClipperLib::Paths contours; ClipperLib::Paths contours;
ClipperLib::Paths holes; ClipperLib::Paths holes;
contours.reserve(expolygons.size()); contours.reserve(expolygons.size());
@ -374,10 +431,10 @@ void offset(const Slic3r::ExPolygons &expolygons, ClipperLib::Paths* retval, con
{ {
ClipperLib::Path input; ClipperLib::Path input;
Slic3rMultiPoint_to_ClipperPath(it_expoly->contour, &input); Slic3rMultiPoint_to_ClipperPath(it_expoly->contour, &input);
scaleClipperPolygon(input, scale); scaleClipperPolygon(input);
ClipperLib::ClipperOffset co; ClipperLib::ClipperOffset co;
if (joinType == jtRound) if (joinType == jtRound)
co.ArcTolerance = miterLimit; co.ArcTolerance = miterLimit * double(CLIPPER_OFFSET_SCALE);
else else
co.MiterLimit = miterLimit; co.MiterLimit = miterLimit;
co.AddPath(input, joinType, ClipperLib::etClosedPolygon); co.AddPath(input, joinType, ClipperLib::etClosedPolygon);
@ -391,10 +448,10 @@ void offset(const Slic3r::ExPolygons &expolygons, ClipperLib::Paths* retval, con
for (Polygons::const_iterator it_hole = it_expoly->holes.begin(); it_hole != it_expoly->holes.end(); ++ it_hole) { for (Polygons::const_iterator it_hole = it_expoly->holes.begin(); it_hole != it_expoly->holes.end(); ++ it_hole) {
ClipperLib::Path input; ClipperLib::Path input;
Slic3rMultiPoint_to_ClipperPath_reversed(*it_hole, &input); Slic3rMultiPoint_to_ClipperPath_reversed(*it_hole, &input);
scaleClipperPolygon(input, scale); scaleClipperPolygon(input);
ClipperLib::ClipperOffset co; ClipperLib::ClipperOffset co;
if (joinType == jtRound) if (joinType == jtRound)
co.ArcTolerance = miterLimit; co.ArcTolerance = miterLimit * double(CLIPPER_OFFSET_SCALE);
else else
co.MiterLimit = miterLimit; co.MiterLimit = miterLimit;
co.AddPath(input, joinType, ClipperLib::etClosedPolygon); co.AddPath(input, joinType, ClipperLib::etClosedPolygon);
@ -416,15 +473,15 @@ void offset(const Slic3r::ExPolygons &expolygons, ClipperLib::Paths* retval, con
} }
// 4) Unscale the output. // 4) Unscale the output.
scaleClipperPolygons(*retval, 1/scale); unscaleClipperPolygons(*retval);
} }
Slic3r::Polygons offset(const Slic3r::ExPolygons &expolygons, const float delta, Slic3r::Polygons offset(const Slic3r::ExPolygons &expolygons, const float delta,
double scale, ClipperLib::JoinType joinType, double miterLimit) ClipperLib::JoinType joinType, double miterLimit)
{ {
// perform offset // perform offset
ClipperLib::Paths output; ClipperLib::Paths output;
offset(expolygons, &output, delta, scale, joinType, miterLimit); offset(expolygons, &output, delta, joinType, miterLimit);
// convert into ExPolygons // convert into ExPolygons
Slic3r::Polygons retval; Slic3r::Polygons retval;
@ -433,11 +490,11 @@ Slic3r::Polygons offset(const Slic3r::ExPolygons &expolygons, const float delta,
} }
Slic3r::ExPolygons offset_ex(const Slic3r::ExPolygons &expolygons, const float delta, Slic3r::ExPolygons offset_ex(const Slic3r::ExPolygons &expolygons, const float delta,
double scale, ClipperLib::JoinType joinType, double miterLimit) ClipperLib::JoinType joinType, double miterLimit)
{ {
// perform offset // perform offset
ClipperLib::Paths output; ClipperLib::Paths output;
offset(expolygons, &output, delta, scale, joinType, miterLimit); offset(expolygons, &output, delta, joinType, miterLimit);
// convert into ExPolygons // convert into ExPolygons
Slic3r::ExPolygons retval; Slic3r::ExPolygons retval;
@ -447,20 +504,20 @@ Slic3r::ExPolygons offset_ex(const Slic3r::ExPolygons &expolygons, const float d
Slic3r::ExPolygons Slic3r::ExPolygons
offset_ex(const Slic3r::Polygons &polygons, const float delta, offset_ex(const Slic3r::Polygons &polygons, const float delta,
double scale, ClipperLib::JoinType joinType, double miterLimit) ClipperLib::JoinType joinType, double miterLimit)
{ {
Slic3r::ExPolygons expp; Slic3r::ExPolygons expp;
offset(polygons, &expp, delta, scale, joinType, miterLimit); offset(polygons, &expp, delta, joinType, miterLimit);
return expp; return expp;
} }
void void
offset2(const Slic3r::Polygons &polygons, ClipperLib::Paths* retval, const float delta1, offset2(const Slic3r::Polygons &polygons, ClipperLib::Paths* retval, const float delta1,
const float delta2, const double scale, const ClipperLib::JoinType joinType, const double miterLimit) const float delta2, const ClipperLib::JoinType joinType, const double miterLimit)
{ {
if (delta1 * delta2 >= 0) { if (delta1 * delta2 >= 0) {
// Both deltas are the same signum // Both deltas are the same signum
offset(polygons, retval, delta1 + delta2, scale, joinType, miterLimit); offset(polygons, retval, delta1 + delta2, joinType, miterLimit);
return; return;
} }
#ifdef CLIPPER_UTILS_DEBUG #ifdef CLIPPER_UTILS_DEBUG
@ -479,12 +536,12 @@ offset2(const Slic3r::Polygons &polygons, ClipperLib::Paths* retval, const float
Slic3rMultiPoints_to_ClipperPaths(polygons, &input); Slic3rMultiPoints_to_ClipperPaths(polygons, &input);
// scale input // scale input
scaleClipperPolygons(input, scale); scaleClipperPolygons(input);
// prepare ClipperOffset object // prepare ClipperOffset object
ClipperLib::ClipperOffset co; ClipperLib::ClipperOffset co;
if (joinType == jtRound) { if (joinType == jtRound) {
co.ArcTolerance = miterLimit; co.ArcTolerance = miterLimit * double(CLIPPER_OFFSET_SCALE);
} else { } else {
co.MiterLimit = miterLimit; co.MiterLimit = miterLimit;
} }
@ -492,30 +549,30 @@ offset2(const Slic3r::Polygons &polygons, ClipperLib::Paths* retval, const float
// perform first offset // perform first offset
ClipperLib::Paths output1; ClipperLib::Paths output1;
co.AddPaths(input, joinType, ClipperLib::etClosedPolygon); co.AddPaths(input, joinType, ClipperLib::etClosedPolygon);
co.Execute(output1, (delta1*scale)); co.Execute(output1, delta1 * float(CLIPPER_OFFSET_SCALE));
#ifdef CLIPPER_UTILS_DEBUG #ifdef CLIPPER_UTILS_DEBUG
svg.draw(output1, 1./CLIPPER_OFFSET_SCALE, "red", stroke_width); svg.draw(output1, 1. / double(CLIPPER_OFFSET_SCALE), "red", stroke_width);
#endif /* CLIPPER_UTILS_DEBUG */ #endif /* CLIPPER_UTILS_DEBUG */
// perform second offset // perform second offset
co.Clear(); co.Clear();
co.AddPaths(output1, joinType, ClipperLib::etClosedPolygon); co.AddPaths(output1, joinType, ClipperLib::etClosedPolygon);
co.Execute(*retval, (delta2*scale)); co.Execute(*retval, delta2 * float(CLIPPER_OFFSET_SCALE));
#ifdef CLIPPER_UTILS_DEBUG #ifdef CLIPPER_UTILS_DEBUG
svg.draw(*retval, 1./CLIPPER_OFFSET_SCALE, "green", stroke_width); svg.draw(*retval, 1. / double(CLIPPER_OFFSET_SCALE), "green", stroke_width);
#endif /* CLIPPER_UTILS_DEBUG */ #endif /* CLIPPER_UTILS_DEBUG */
// unscale output // unscale output
scaleClipperPolygons(*retval, 1/scale); unscaleClipperPolygons(*retval);
} }
void void
offset2(const Slic3r::Polygons &polygons, Slic3r::Polygons* retval, const float delta1, offset2(const Slic3r::Polygons &polygons, Slic3r::Polygons* retval, const float delta1,
const float delta2, const double scale, const ClipperLib::JoinType joinType, const double miterLimit) const float delta2, const ClipperLib::JoinType joinType, const double miterLimit)
{ {
// perform offset // perform offset
ClipperLib::Paths output; ClipperLib::Paths output;
offset2(polygons, &output, delta1, delta2, scale, joinType, miterLimit); offset2(polygons, &output, delta1, delta2, joinType, miterLimit);
// convert into ExPolygons // convert into ExPolygons
ClipperPaths_to_Slic3rMultiPoints(output, retval); ClipperPaths_to_Slic3rMultiPoints(output, retval);
@ -523,20 +580,20 @@ offset2(const Slic3r::Polygons &polygons, Slic3r::Polygons* retval, const float
Slic3r::Polygons Slic3r::Polygons
offset2(const Slic3r::Polygons &polygons, const float delta1, offset2(const Slic3r::Polygons &polygons, const float delta1,
const float delta2, const double scale, const ClipperLib::JoinType joinType, const double miterLimit) const float delta2, const ClipperLib::JoinType joinType, const double miterLimit)
{ {
Slic3r::Polygons pp; Slic3r::Polygons pp;
offset2(polygons, &pp, delta1, delta2, scale, joinType, miterLimit); offset2(polygons, &pp, delta1, delta2, joinType, miterLimit);
return pp; return pp;
} }
void void
offset2(const Slic3r::Polygons &polygons, Slic3r::ExPolygons* retval, const float delta1, offset2(const Slic3r::Polygons &polygons, Slic3r::ExPolygons* retval, const float delta1,
const float delta2, const double scale, const ClipperLib::JoinType joinType, const double miterLimit) const float delta2, const ClipperLib::JoinType joinType, const double miterLimit)
{ {
// perform offset // perform offset
ClipperLib::Paths output; ClipperLib::Paths output;
offset2(polygons, &output, delta1, delta2, scale, joinType, miterLimit); offset2(polygons, &output, delta1, delta2, joinType, miterLimit);
// convert into ExPolygons // convert into ExPolygons
ClipperPaths_to_Slic3rExPolygons(output, retval); ClipperPaths_to_Slic3rExPolygons(output, retval);
@ -544,10 +601,10 @@ offset2(const Slic3r::Polygons &polygons, Slic3r::ExPolygons* retval, const floa
Slic3r::ExPolygons Slic3r::ExPolygons
offset2_ex(const Slic3r::Polygons &polygons, const float delta1, offset2_ex(const Slic3r::Polygons &polygons, const float delta1,
const float delta2, const double scale, const ClipperLib::JoinType joinType, const double miterLimit) const float delta2, const ClipperLib::JoinType joinType, const double miterLimit)
{ {
Slic3r::ExPolygons expp; Slic3r::ExPolygons expp;
offset2(polygons, &expp, delta1, delta2, scale, joinType, miterLimit); offset2(polygons, &expp, delta1, delta2, joinType, miterLimit);
return expp; return expp;
} }
@ -580,6 +637,13 @@ void _clipper_do(const ClipperLib::ClipType clipType, const Slic3r::Polygons &su
PROFILE_BLOCK(_clipper_do_polygons_AddPaths); PROFILE_BLOCK(_clipper_do_polygons_AddPaths);
clipper.AddPaths(input_subject, ClipperLib::ptSubject, true); clipper.AddPaths(input_subject, ClipperLib::ptSubject, true);
clipper.AddPaths(input_clip, ClipperLib::ptClip, true); clipper.AddPaths(input_clip, ClipperLib::ptClip, true);
#ifdef CLIPPER_UTILS_DEBUG
if (clipper_export_enabled) {
static int iRun = 0;
export_clipper_input_polygons_bin(debug_out_path("_clipper_do_polygons_AddPaths-polygons-%d", ++iRun).c_str(), input_subject, input_clip);
}
#endif /* CLIPPER_UTILS_DEBUG */
} }
// perform operation // perform operation
@ -986,22 +1050,39 @@ void safety_offset(ClipperLib::Paths* paths)
PROFILE_FUNC(); PROFILE_FUNC();
// scale input // scale input
scaleClipperPolygons(*paths, CLIPPER_OFFSET_SCALE); scaleClipperPolygons(*paths);
// perform offset (delta = scale 1e-05) // perform offset (delta = scale 1e-05)
ClipperLib::ClipperOffset co; ClipperLib::ClipperOffset co;
co.MiterLimit = 2; #ifdef CLIPPER_UTILS_DEBUG
{ if (clipper_export_enabled) {
PROFILE_BLOCK(safety_offset_AddPaths); static int iRun = 0;
co.AddPaths(*paths, ClipperLib::jtMiter, ClipperLib::etClosedPolygon); export_clipper_input_polygons_bin(debug_out_path("safety_offset-polygons-%d", ++iRun).c_str(), *paths, ClipperLib::Paths());
} }
{ #endif /* CLIPPER_UTILS_DEBUG */
PROFILE_BLOCK(safety_offset_Execute); ClipperLib::Paths out;
co.Execute(*paths, 10.0 * CLIPPER_OFFSET_SCALE); for (size_t i = 0; i < paths->size(); ++ i) {
co.Clear();
co.MiterLimit = 2;
{
PROFILE_BLOCK(safety_offset_AddPaths);
co.AddPath((*paths)[i], ClipperLib::jtMiter, ClipperLib::etClosedPolygon);
}
{
PROFILE_BLOCK(safety_offset_Execute);
// offset outside by 10um
ClipperLib::Paths out_this;
co.Execute(out_this, 10.f * float(CLIPPER_OFFSET_SCALE));
if (out.empty())
out = std::move(out_this);
else
std::move(std::begin(out_this), std::end(out_this), std::back_inserter(out));
}
} }
*paths = std::move(out);
// unscale output // unscale output
scaleClipperPolygons(*paths, 1.0/CLIPPER_OFFSET_SCALE); unscaleClipperPolygons(*paths);
} }
Polygons top_level_islands(const Slic3r::Polygons &polygons) Polygons top_level_islands(const Slic3r::Polygons &polygons)

View File

@ -14,13 +14,6 @@ using ClipperLib::jtSquare;
namespace Slic3r { namespace Slic3r {
// Factor to convert from coord_t (which is int32) to an int64 type used by the Clipper library.
//FIXME Vojtech: Better to use a power of 2 coefficient and to use bit shifts for scaling.
// How about 2^17=131072?
// By the way, is the scalling needed at all? Cura runs all the computation with a fixed point precision of 1um, while Slic3r scales to 1nm,
// further scaling by 10e5 brings us to
#define CLIPPER_OFFSET_SCALE 100000.0
//----------------------------------------------------------- //-----------------------------------------------------------
// legacy code from Clipper documentation // legacy code from Clipper documentation
void AddOuterPolyNodeToExPolygons(ClipperLib::PolyNode& polynode, Slic3r::ExPolygons& expolygons); void AddOuterPolyNodeToExPolygons(ClipperLib::PolyNode& polynode, Slic3r::ExPolygons& expolygons);
@ -40,29 +33,29 @@ void scaleClipperPolygons(ClipperLib::Paths &polygons, const double scale);
// offset Polygons // offset Polygons
void offset(const Slic3r::Polygons &polygons, ClipperLib::Paths* retval, const float delta, void offset(const Slic3r::Polygons &polygons, ClipperLib::Paths* retval, const float delta,
double scale = CLIPPER_OFFSET_SCALE, ClipperLib::JoinType joinType = ClipperLib::jtMiter, ClipperLib::JoinType joinType = ClipperLib::jtMiter,
double miterLimit = 3); double miterLimit = 3);
void offset(const Slic3r::Polygons &polygons, Slic3r::Polygons* retval, const float delta, void offset(const Slic3r::Polygons &polygons, Slic3r::Polygons* retval, const float delta,
double scale = CLIPPER_OFFSET_SCALE, ClipperLib::JoinType joinType = ClipperLib::jtMiter, ClipperLib::JoinType joinType = ClipperLib::jtMiter,
double miterLimit = 3); double miterLimit = 3);
Slic3r::Polygons offset(const Slic3r::Polygons &polygons, const float delta, Slic3r::Polygons offset(const Slic3r::Polygons &polygons, const float delta,
double scale = CLIPPER_OFFSET_SCALE, ClipperLib::JoinType joinType = ClipperLib::jtMiter, ClipperLib::JoinType joinType = ClipperLib::jtMiter,
double miterLimit = 3); double miterLimit = 3);
// This is a safe variant of the polygon offset, tailored for a single ExPolygon: // This is a safe variant of the polygon offset, tailored for a single ExPolygon:
// a single polygon with multiple non-overlapping holes. // a single polygon with multiple non-overlapping holes.
// Each contour and hole is offsetted separately, then the holes are subtracted from the outer contours. // Each contour and hole is offsetted separately, then the holes are subtracted from the outer contours.
void offset(const Slic3r::ExPolygon &expolygon, ClipperLib::Paths* retval, const float delta, void offset(const Slic3r::ExPolygon &expolygon, ClipperLib::Paths* retval, const float delta,
double scale = CLIPPER_OFFSET_SCALE, ClipperLib::JoinType joinType = ClipperLib::jtMiter, ClipperLib::JoinType joinType = ClipperLib::jtMiter,
double miterLimit = 3); double miterLimit = 3);
void offset(const Slic3r::ExPolygons &expolygons, ClipperLib::Paths* retval, const float delta, void offset(const Slic3r::ExPolygons &expolygons, ClipperLib::Paths* retval, const float delta,
double scale = CLIPPER_OFFSET_SCALE, ClipperLib::JoinType joinType = ClipperLib::jtMiter, ClipperLib::JoinType joinType = ClipperLib::jtMiter,
double miterLimit = 3); double miterLimit = 3);
Slic3r::Polygons offset(const Slic3r::ExPolygon &expolygon, const float delta, Slic3r::Polygons offset(const Slic3r::ExPolygon &expolygon, const float delta,
double scale = CLIPPER_OFFSET_SCALE, ClipperLib::JoinType joinType = ClipperLib::jtMiter, ClipperLib::JoinType joinType = ClipperLib::jtMiter,
double miterLimit = 3); double miterLimit = 3);
Slic3r::Polygons offset(const Slic3r::ExPolygons &expolygons, const float delta, Slic3r::Polygons offset(const Slic3r::ExPolygons &expolygons, const float delta,
double scale = CLIPPER_OFFSET_SCALE, ClipperLib::JoinType joinType = ClipperLib::jtMiter, ClipperLib::JoinType joinType = ClipperLib::jtMiter,
double miterLimit = 3); double miterLimit = 3);
Slic3r::ExPolygons offset_ex(const Slic3r::ExPolygon &expolygon, const float delta, Slic3r::ExPolygons offset_ex(const Slic3r::ExPolygon &expolygon, const float delta,
double scale, ClipperLib::JoinType joinType, double miterLimit); double scale, ClipperLib::JoinType joinType, double miterLimit);
@ -71,36 +64,36 @@ Slic3r::ExPolygons offset_ex(const Slic3r::ExPolygons &expolygons, const float d
// offset Polylines // offset Polylines
void offset(const Slic3r::Polylines &polylines, ClipperLib::Paths* retval, const float delta, void offset(const Slic3r::Polylines &polylines, ClipperLib::Paths* retval, const float delta,
double scale = CLIPPER_OFFSET_SCALE, ClipperLib::JoinType joinType = ClipperLib::jtSquare, ClipperLib::JoinType joinType = ClipperLib::jtSquare,
double miterLimit = 3); double miterLimit = 3);
void offset(const Slic3r::Polylines &polylines, Slic3r::Polygons* retval, const float delta, void offset(const Slic3r::Polylines &polylines, Slic3r::Polygons* retval, const float delta,
double scale = CLIPPER_OFFSET_SCALE, ClipperLib::JoinType joinType = ClipperLib::jtSquare, ClipperLib::JoinType joinType = ClipperLib::jtSquare,
double miterLimit = 3); double miterLimit = 3);
void offset(const Slic3r::Surface &surface, Slic3r::Surfaces* retval, const float delta, void offset(const Slic3r::Surface &surface, Slic3r::Surfaces* retval, const float delta,
double scale = CLIPPER_OFFSET_SCALE, ClipperLib::JoinType joinType = ClipperLib::jtSquare, ClipperLib::JoinType joinType = ClipperLib::jtSquare,
double miterLimit = 3); double miterLimit = 3);
void offset(const Slic3r::Polygons &polygons, Slic3r::ExPolygons* retval, const float delta, void offset(const Slic3r::Polygons &polygons, Slic3r::ExPolygons* retval, const float delta,
double scale = CLIPPER_OFFSET_SCALE, ClipperLib::JoinType joinType = ClipperLib::jtMiter, ClipperLib::JoinType joinType = ClipperLib::jtMiter,
double miterLimit = 3); double miterLimit = 3);
Slic3r::ExPolygons offset_ex(const Slic3r::Polygons &polygons, const float delta, Slic3r::ExPolygons offset_ex(const Slic3r::Polygons &polygons, const float delta,
double scale = CLIPPER_OFFSET_SCALE, ClipperLib::JoinType joinType = ClipperLib::jtMiter, ClipperLib::JoinType joinType = ClipperLib::jtMiter,
double miterLimit = 3); double miterLimit = 3);
void offset2(const Slic3r::Polygons &polygons, ClipperLib::Paths* retval, const float delta1, void offset2(const Slic3r::Polygons &polygons, ClipperLib::Paths* retval, const float delta1,
const float delta2, double scale = CLIPPER_OFFSET_SCALE, ClipperLib::JoinType joinType = ClipperLib::jtMiter, const float delta2, ClipperLib::JoinType joinType = ClipperLib::jtMiter,
double miterLimit = 3); double miterLimit = 3);
void offset2(const Slic3r::Polygons &polygons, Slic3r::Polygons* retval, const float delta1, void offset2(const Slic3r::Polygons &polygons, Slic3r::Polygons* retval, const float delta1,
const float delta2, double scale = CLIPPER_OFFSET_SCALE, ClipperLib::JoinType joinType = ClipperLib::jtMiter, const float delta2, ClipperLib::JoinType joinType = ClipperLib::jtMiter,
double miterLimit = 3); double miterLimit = 3);
Slic3r::Polygons offset2(const Slic3r::Polygons &polygons, const float delta1, Slic3r::Polygons offset2(const Slic3r::Polygons &polygons, const float delta1,
const float delta2, double scale = CLIPPER_OFFSET_SCALE, ClipperLib::JoinType joinType = ClipperLib::jtMiter, const float delta2, ClipperLib::JoinType joinType = ClipperLib::jtMiter,
double miterLimit = 3); double miterLimit = 3);
void offset2(const Slic3r::Polygons &polygons, Slic3r::ExPolygons* retval, const float delta1, void offset2(const Slic3r::Polygons &polygons, Slic3r::ExPolygons* retval, const float delta1,
const float delta2, double scale = CLIPPER_OFFSET_SCALE, ClipperLib::JoinType joinType = ClipperLib::jtMiter, const float delta2, ClipperLib::JoinType joinType = ClipperLib::jtMiter,
double miterLimit = 3); double miterLimit = 3);
Slic3r::ExPolygons offset2_ex(const Slic3r::Polygons &polygons, const float delta1, Slic3r::ExPolygons offset2_ex(const Slic3r::Polygons &polygons, const float delta1,
const float delta2, double scale = CLIPPER_OFFSET_SCALE, ClipperLib::JoinType joinType = ClipperLib::jtMiter, const float delta2, ClipperLib::JoinType joinType = ClipperLib::jtMiter,
double miterLimit = 3); double miterLimit = 3);
template <class T> template <class T>

View File

@ -372,11 +372,9 @@ public:
bool sticks_removed = remove_sticks(polygons_src); bool sticks_removed = remove_sticks(polygons_src);
// if (sticks_removed) printf("Sticks removed!\n"); // if (sticks_removed) printf("Sticks removed!\n");
polygons_outer = offset(polygons_src, aoffset1, polygons_outer = offset(polygons_src, aoffset1,
CLIPPER_OFFSET_SCALE,
ClipperLib::jtMiter, ClipperLib::jtMiter,
mitterLimit); mitterLimit);
polygons_inner = offset(polygons_outer, aoffset2 - aoffset1, polygons_inner = offset(polygons_outer, aoffset2 - aoffset1,
CLIPPER_OFFSET_SCALE,
ClipperLib::jtMiter, ClipperLib::jtMiter,
mitterLimit); mitterLimit);
// Filter out contours with zero area or small area, contours with 2 points only. // Filter out contours with zero area or small area, contours with 2 points only.

View File

@ -91,9 +91,9 @@ LayerRegion::make_perimeters(const SurfaceCollection &slices, SurfaceCollection*
g.process(); g.process();
} }
//#define EXTERNAL_SURFACES_OFFSET_PARAMETERS CLIPPER_OFFSET_SCALE, ClipperLib::jtMiter, 3. //#define EXTERNAL_SURFACES_OFFSET_PARAMETERS ClipperLib::jtMiter, 3.
//#define EXTERNAL_SURFACES_OFFSET_PARAMETERS CLIPPER_OFFSET_SCALE, ClipperLib::jtMiter, 1.5 //#define EXTERNAL_SURFACES_OFFSET_PARAMETERS ClipperLib::jtMiter, 1.5
#define EXTERNAL_SURFACES_OFFSET_PARAMETERS CLIPPER_OFFSET_SCALE, ClipperLib::jtSquare, 0. #define EXTERNAL_SURFACES_OFFSET_PARAMETERS ClipperLib::jtSquare, 0.
void void
LayerRegion::process_external_surfaces(const Layer* lower_layer) LayerRegion::process_external_surfaces(const Layer* lower_layer)
@ -194,7 +194,7 @@ LayerRegion::process_external_surfaces(const Layer* lower_layer)
break; break;
} }
// Grown by 3mm. // Grown by 3mm.
Polygons polys = offset(bridges[i].expolygon, float(margin), EXTERNAL_SURFACES_OFFSET_PARAMETERS); Polygons polys = offset(to_polygons(bridges[i].expolygon), float(margin), EXTERNAL_SURFACES_OFFSET_PARAMETERS);
if (idx_island == -1) { if (idx_island == -1) {
printf("Bridge did not fall into the source region!\r\n"); printf("Bridge did not fall into the source region!\r\n");
} else { } else {

View File

@ -610,7 +610,7 @@ Print::validate() const
// grow convex hull with the clearance margin // grow convex hull with the clearance margin
{ {
Polygons grown_hull; Polygons grown_hull;
offset(convex_hull, &grown_hull, scale_(this->config.extruder_clearance_radius.value)/2, 1, jtRound, scale_(0.1)); offset(convex_hull, &grown_hull, scale_(this->config.extruder_clearance_radius.value)/2, jtRound, scale_(0.1));
convex_hull = grown_hull.front(); convex_hull = grown_hull.front();
} }

View File

@ -692,8 +692,7 @@ PrintObject::discover_vertical_shells()
#if 1 #if 1
// Intentionally inflate a bit more than how much the region has been shrunk, // Intentionally inflate a bit more than how much the region has been shrunk,
// so there will be some overlap between this solid infill and the other infill regions (mainly the sparse infill). // so there will be some overlap between this solid infill and the other infill regions (mainly the sparse infill).
shell = offset2(shell, - 0.5f * min_perimeter_infill_spacing, 0.8f * min_perimeter_infill_spacing, shell = offset2(shell, - 0.5f * min_perimeter_infill_spacing, 0.8f * min_perimeter_infill_spacing, ClipperLib::jtSquare);
CLIPPER_OFFSET_SCALE, ClipperLib::jtSquare);
if (shell.empty()) if (shell.empty())
continue; continue;
#else #else
@ -705,7 +704,7 @@ PrintObject::discover_vertical_shells()
// get a triangle in $too_narrow; if we grow it below then the shell // get a triangle in $too_narrow; if we grow it below then the shell
// would have a different shape from the external surface and we'd still // would have a different shape from the external surface and we'd still
// have the same angle, so the next shell would be grown even more and so on. // have the same angle, so the next shell would be grown even more and so on.
Polygons too_narrow = diff(shell, offset2(shell, -margin, margin, CLIPPER_OFFSET_SCALE, ClipperLib::jtMiter, 5.), true); Polygons too_narrow = diff(shell, offset2(shell, -margin, margin, ClipperLib::jtMiter, 5.), true);
if (! too_narrow.empty()) { if (! too_narrow.empty()) {
// grow the collapsing parts and add the extra area to the neighbor layer // grow the collapsing parts and add the extra area to the neighbor layer
// as well as to our original surfaces so that we support this // as well as to our original surfaces so that we support this

View File

@ -16,58 +16,53 @@ _constant()
JT_MITER = jtMiter JT_MITER = jtMiter
JT_ROUND = jtRound JT_ROUND = jtRound
JT_SQUARE = jtSquare JT_SQUARE = jtSquare
CLIPPER_OFFSET_SCALE = CLIPPER_OFFSET_SCALE
CODE: CODE:
RETVAL = ix; RETVAL = ix;
OUTPUT: RETVAL OUTPUT: RETVAL
Polygons Polygons
offset(polygons, delta, scale = CLIPPER_OFFSET_SCALE, joinType = ClipperLib::jtMiter, miterLimit = 3) offset(polygons, delta, joinType = ClipperLib::jtMiter, miterLimit = 3)
Polygons polygons Polygons polygons
const float delta const float delta
double scale
ClipperLib::JoinType joinType ClipperLib::JoinType joinType
double miterLimit double miterLimit
CODE: CODE:
offset(polygons, &RETVAL, delta, scale, joinType, miterLimit); offset(polygons, &RETVAL, delta, joinType, miterLimit);
OUTPUT: OUTPUT:
RETVAL RETVAL
ExPolygons ExPolygons
offset_ex(polygons, delta, scale = CLIPPER_OFFSET_SCALE, joinType = ClipperLib::jtMiter, miterLimit = 3) offset_ex(polygons, delta, joinType = ClipperLib::jtMiter, miterLimit = 3)
Polygons polygons Polygons polygons
const float delta const float delta
double scale
ClipperLib::JoinType joinType ClipperLib::JoinType joinType
double miterLimit double miterLimit
CODE: CODE:
offset(polygons, &RETVAL, delta, scale, joinType, miterLimit); offset(polygons, &RETVAL, delta, joinType, miterLimit);
OUTPUT: OUTPUT:
RETVAL RETVAL
Polygons Polygons
offset2(polygons, delta1, delta2, scale = CLIPPER_OFFSET_SCALE, joinType = ClipperLib::jtMiter, miterLimit = 3) offset2(polygons, delta1, delta2, joinType = ClipperLib::jtMiter, miterLimit = 3)
Polygons polygons Polygons polygons
const float delta1 const float delta1
const float delta2 const float delta2
double scale
ClipperLib::JoinType joinType ClipperLib::JoinType joinType
double miterLimit double miterLimit
CODE: CODE:
offset2(polygons, &RETVAL, delta1, delta2, scale, joinType, miterLimit); offset2(polygons, &RETVAL, delta1, delta2, joinType, miterLimit);
OUTPUT: OUTPUT:
RETVAL RETVAL
ExPolygons ExPolygons
offset2_ex(polygons, delta1, delta2, scale = CLIPPER_OFFSET_SCALE, joinType = ClipperLib::jtMiter, miterLimit = 3) offset2_ex(polygons, delta1, delta2, joinType = ClipperLib::jtMiter, miterLimit = 3)
Polygons polygons Polygons polygons
const float delta1 const float delta1
const float delta2 const float delta2
double scale
ClipperLib::JoinType joinType ClipperLib::JoinType joinType
double miterLimit double miterLimit
CODE: CODE:
offset2(polygons, &RETVAL, delta1, delta2, scale, joinType, miterLimit); offset2(polygons, &RETVAL, delta1, delta2, joinType, miterLimit);
OUTPUT: OUTPUT:
RETVAL RETVAL

View File

@ -80,13 +80,12 @@ Polyline::rotate(angle, center_sv)
THIS->rotate(angle, center); THIS->rotate(angle, center);
Polygons Polygons
Polyline::grow(delta, scale = CLIPPER_OFFSET_SCALE, joinType = ClipperLib::jtSquare, miterLimit = 3) Polyline::grow(delta, joinType = ClipperLib::jtSquare, miterLimit = 3)
const float delta const float delta
double scale
ClipperLib::JoinType joinType ClipperLib::JoinType joinType
double miterLimit double miterLimit
CODE: CODE:
offset(*THIS, &RETVAL, delta, scale, joinType, miterLimit); offset(*THIS, &RETVAL, delta, joinType, miterLimit);
OUTPUT: OUTPUT:
RETVAL RETVAL

View File

@ -83,13 +83,12 @@ Surface::polygons()
RETVAL RETVAL
Surfaces Surfaces
Surface::offset(delta, scale = CLIPPER_OFFSET_SCALE, joinType = ClipperLib::jtMiter, miterLimit = 3) Surface::offset(delta, joinType = ClipperLib::jtMiter, miterLimit = 3)
const float delta const float delta
double scale
ClipperLib::JoinType joinType ClipperLib::JoinType joinType
double miterLimit double miterLimit
CODE: CODE:
offset(*THIS, &RETVAL, delta, scale, joinType, miterLimit); offset(*THIS, &RETVAL, delta, joinType, miterLimit);
OUTPUT: OUTPUT:
RETVAL RETVAL