diff --git a/lib/Slic3r/GUI/Plater/2D.pm b/lib/Slic3r/GUI/Plater/2D.pm index 8fb8908e1..a24a5a6ff 100644 --- a/lib/Slic3r/GUI/Plater/2D.pm +++ b/lib/Slic3r/GUI/Plater/2D.pm @@ -173,7 +173,7 @@ sub repaint { # 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) { - 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->SetBrush($self->{transparent_brush}); $dc->DrawPolygon($self->scaled_points_to_pixel($clearance, 1), 0, 0); @@ -185,7 +185,7 @@ sub repaint { if (@{$self->{objects}} && $self->{config}->skirts) { my @points = map @{$_->contour}, map @$_, map @{$_->instance_thumbnails}, @{$self->{objects}}; 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->SetBrush($self->{transparent_brush}); $dc->DrawPolygon($self->scaled_points_to_pixel($convex_hull, 1), 0, 0); diff --git a/lib/Slic3r/Geometry/Clipper.pm b/lib/Slic3r/Geometry/Clipper.pm index 652abb8db..16dfa6f6b 100644 --- a/lib/Slic3r/Geometry/Clipper.pm +++ b/lib/Slic3r/Geometry/Clipper.pm @@ -7,7 +7,7 @@ our @ISA = qw(Exporter); our @EXPORT_OK = qw(offset offset_ex diff_ex diff union_ex intersection_ex xor_ex JT_ROUND JT_MITER 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); 1; diff --git a/lib/Slic3r/Print.pm b/lib/Slic3r/Print.pm index 187ee84e5..303058c3f 100644 --- a/lib/Slic3r/Print.pm +++ b/lib/Slic3r/Print.pm @@ -276,7 +276,7 @@ sub make_skirt { my $distance = scale max($self->config->skirt_distance, $self->config->brim_width); for (my $i = $skirts; $i > 0; $i--) { $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( Slic3r::ExtrusionPath->new( 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 # (first offset more, then step back - reverse order than the one used for # 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( diff --git a/lib/Slic3r/Print/Object.pm b/lib/Slic3r/Print/Object.pm index 8fd2bf4cf..00b3ab669 100644 --- a/lib/Slic3r/Print/Object.pm +++ b/lib/Slic3r/Print/Object.pm @@ -7,7 +7,7 @@ use List::Util qw(min max sum first); use Slic3r::Flow ':roles'; 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 - 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::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 # obeying the solid shell count option strictly (DWIM!) 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( $new_internal_solid, $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. my $too_narrow = diff( $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, ); diff --git a/lib/Slic3r/Print/SupportMaterial.pm b/lib/Slic3r/Print/SupportMaterial.pm index 9dbfe4003..b4caffc7d 100644 --- a/lib/Slic3r/Print/SupportMaterial.pm +++ b/lib/Slic3r/Print/SupportMaterial.pm @@ -8,7 +8,7 @@ use Slic3r::ExtrusionPath ':roles'; use Slic3r::Flow ':roles'; 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 - 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'; has 'print_config' => (is => 'rw', required => 1); @@ -299,9 +299,8 @@ sub contact_area { offset( $diff, $_, - CLIPPER_OFFSET_SCALE, JT_ROUND, - scale(0.05)*CLIPPER_OFFSET_SCALE), + scale(0.05)), $slices_margin ); } @@ -584,9 +583,8 @@ sub generate_base_layers { $fillet_radius_scaled, -$fillet_radius_scaled, # Use a geometric offsetting for filleting. - CLIPPER_OFFSET_SCALE, JT_ROUND, - 0.2*$fillet_radius_scaled*CLIPPER_OFFSET_SCALE), + 0.2*$fillet_radius_scaled), $trim_polygons, 0); # don't apply the safety offset. } diff --git a/xs/src/libslic3r/ClipperUtils.cpp b/xs/src/libslic3r/ClipperUtils.cpp index f2cc7eb38..ebb80cd51 100644 --- a/xs/src/libslic3r/ClipperUtils.cpp +++ b/xs/src/libslic3r/ClipperUtils.cpp @@ -9,8 +9,51 @@ #include +// 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 { +#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 void AddOuterPolyNodeToExPolygons(ClipperLib::PolyNode& polynode, Slic3r::ExPolygons* expolygons) @@ -120,37 +163,51 @@ Slic3rMultiPoints_to_ClipperPaths(const T &input, ClipperLib::Paths* output) } } -void -scaleClipperPolygon(ClipperLib::Path &polygon, const double scale) +void scaleClipperPolygon(ClipperLib::Path &polygon) { PROFILE_FUNC(); - for (ClipperLib::Path::iterator pit = polygon.begin(); pit != polygon.end(); ++pit) { - //FIXME multiplication of int64_t by double! - // Replace by bit shifts? - (*pit).X *= scale; - (*pit).Y *= scale; + pit->X <<= CLIPPER_OFFSET_POWER_OF_2; + pit->Y <<= CLIPPER_OFFSET_POWER_OF_2; } } -void -scaleClipperPolygons(ClipperLib::Paths &polygons, const double scale) +void scaleClipperPolygons(ClipperLib::Paths &polygons) { 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) { - //FIXME multiplication of int64_t by double! - // Replace by bit shifts? - (*pit).X *= scale; - (*pit).Y *= scale; + pit->X <<= CLIPPER_OFFSET_POWER_OF_2; + pit->Y <<= CLIPPER_OFFSET_POWER_OF_2; } +} + +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 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(); // read input @@ -158,12 +215,12 @@ offset(const Slic3r::Polygons &polygons, ClipperLib::Paths* retval, const float Slic3rMultiPoints_to_ClipperPaths(polygons, &input); // scale input - scaleClipperPolygons(input, scale); + scaleClipperPolygons(input); // perform offset ClipperLib::ClipperOffset co; if (joinType == jtRound) { - co.ArcTolerance = miterLimit; + co.ArcTolerance = miterLimit * double(CLIPPER_OFFSET_SCALE); } else { co.MiterLimit = miterLimit; } @@ -173,20 +230,20 @@ offset(const Slic3r::Polygons &polygons, ClipperLib::Paths* retval, const float } { PROFILE_BLOCK(offset_Execute); - co.Execute(*retval, (delta*scale)); + co.Execute(*retval, delta * float(CLIPPER_OFFSET_SCALE)); } // unscale output - scaleClipperPolygons(*retval, 1/scale); + unscaleClipperPolygons(*retval); } void 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 ClipperLib::Paths output; - offset(polygons, &output, delta, scale, joinType, miterLimit); + offset(polygons, &output, delta, joinType, miterLimit); // convert into ExPolygons ClipperPaths_to_Slic3rMultiPoints(output, retval); @@ -194,45 +251,45 @@ offset(const Slic3r::Polygons &polygons, Slic3r::Polygons* retval, const float d Slic3r::Polygons offset(const Slic3r::Polygons &polygons, const float delta, - double scale, ClipperLib::JoinType joinType, double miterLimit) + ClipperLib::JoinType joinType, double miterLimit) { Slic3r::Polygons pp; - offset(polygons, &pp, delta, scale, joinType, miterLimit); + offset(polygons, &pp, delta, joinType, miterLimit); return pp; } void 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 ClipperLib::Paths input; Slic3rMultiPoints_to_ClipperPaths(polylines, &input); // scale input - scaleClipperPolygons(input, scale); + scaleClipperPolygons(input); // perform offset ClipperLib::ClipperOffset co; if (joinType == jtRound) { - co.ArcTolerance = miterLimit; + co.ArcTolerance = miterLimit * double(CLIPPER_OFFSET_SCALE); } else { co.MiterLimit = miterLimit; } co.AddPaths(input, joinType, ClipperLib::etOpenButt); - co.Execute(*retval, (delta*scale)); + co.Execute(*retval, delta * float(CLIPPER_OFFSET_SCALE)); // unscale output - scaleClipperPolygons(*retval, 1/scale); + unscaleClipperPolygons(*retval); } void 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 ClipperLib::Paths output; - offset(polylines, &output, delta, scale, joinType, miterLimit); + offset(polylines, &output, delta, joinType, miterLimit); // convert into ExPolygons ClipperPaths_to_Slic3rMultiPoints(output, retval); @@ -240,11 +297,11 @@ offset(const Slic3r::Polylines &polylines, Slic3r::Polygons* retval, const float void 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 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 retval->clear(); @@ -258,11 +315,11 @@ offset(const Slic3r::Surface &surface, Slic3r::Surfaces* retval, const float del void 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 ClipperLib::Paths output; - offset(polygons, &output, delta, scale, joinType, miterLimit); + offset(polygons, &output, delta, joinType, miterLimit); // convert into ExPolygons 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. // 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, - double scale, ClipperLib::JoinType joinType, double miterLimit) + ClipperLib::JoinType joinType, double miterLimit) { // printf("new ExPolygon offset\n"); // 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::Path input; Slic3rMultiPoint_to_ClipperPath(expolygon.contour, &input); - scaleClipperPolygon(input, scale); + scaleClipperPolygon(input); ClipperLib::ClipperOffset co; if (joinType == jtRound) - co.ArcTolerance = miterLimit; + co.ArcTolerance = miterLimit * double(CLIPPER_OFFSET_SCALE); else co.MiterLimit = miterLimit; 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) { ClipperLib::Path input; Slic3rMultiPoint_to_ClipperPath_reversed(*it_hole, &input); - scaleClipperPolygon(input, scale); + scaleClipperPolygon(input); ClipperLib::ClipperOffset co; if (joinType == jtRound) - co.ArcTolerance = miterLimit; + co.ArcTolerance = miterLimit * double(CLIPPER_OFFSET_SCALE); else co.MiterLimit = miterLimit; co.AddPath(input, joinType, ClipperLib::etClosedPolygon); @@ -322,15 +379,15 @@ void offset(const Slic3r::ExPolygon &expolygon, ClipperLib::Paths* retval, const } // 4) Unscale the output. - scaleClipperPolygons(*retval, 1/scale); + unscaleClipperPolygons(*retval); } Slic3r::Polygons offset(const Slic3r::ExPolygon &expolygon, const float delta, - double scale, ClipperLib::JoinType joinType, double miterLimit) + ClipperLib::JoinType joinType, double miterLimit) { // perform offset ClipperLib::Paths output; - offset(expolygon, &output, delta, scale, joinType, miterLimit); + offset(expolygon, &output, delta, joinType, miterLimit); // convert into ExPolygons 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, - double scale, ClipperLib::JoinType joinType, double miterLimit) + ClipperLib::JoinType joinType, double miterLimit) { // perform offset ClipperLib::Paths output; - offset(expolygon, &output, delta, scale, joinType, miterLimit); + offset(expolygon, &output, delta, joinType, miterLimit); // convert into ExPolygons 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. // 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, - double scale, ClipperLib::JoinType joinType, double miterLimit) + ClipperLib::JoinType joinType, double miterLimit) { // 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 holes; contours.reserve(expolygons.size()); @@ -374,10 +431,10 @@ void offset(const Slic3r::ExPolygons &expolygons, ClipperLib::Paths* retval, con { ClipperLib::Path input; Slic3rMultiPoint_to_ClipperPath(it_expoly->contour, &input); - scaleClipperPolygon(input, scale); + scaleClipperPolygon(input); ClipperLib::ClipperOffset co; if (joinType == jtRound) - co.ArcTolerance = miterLimit; + co.ArcTolerance = miterLimit * double(CLIPPER_OFFSET_SCALE); else co.MiterLimit = miterLimit; 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) { ClipperLib::Path input; Slic3rMultiPoint_to_ClipperPath_reversed(*it_hole, &input); - scaleClipperPolygon(input, scale); + scaleClipperPolygon(input); ClipperLib::ClipperOffset co; if (joinType == jtRound) - co.ArcTolerance = miterLimit; + co.ArcTolerance = miterLimit * double(CLIPPER_OFFSET_SCALE); else co.MiterLimit = miterLimit; co.AddPath(input, joinType, ClipperLib::etClosedPolygon); @@ -416,15 +473,15 @@ void offset(const Slic3r::ExPolygons &expolygons, ClipperLib::Paths* retval, con } // 4) Unscale the output. - scaleClipperPolygons(*retval, 1/scale); + unscaleClipperPolygons(*retval); } Slic3r::Polygons offset(const Slic3r::ExPolygons &expolygons, const float delta, - double scale, ClipperLib::JoinType joinType, double miterLimit) + ClipperLib::JoinType joinType, double miterLimit) { // perform offset ClipperLib::Paths output; - offset(expolygons, &output, delta, scale, joinType, miterLimit); + offset(expolygons, &output, delta, joinType, miterLimit); // convert into ExPolygons 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, - double scale, ClipperLib::JoinType joinType, double miterLimit) + ClipperLib::JoinType joinType, double miterLimit) { // perform offset ClipperLib::Paths output; - offset(expolygons, &output, delta, scale, joinType, miterLimit); + offset(expolygons, &output, delta, joinType, miterLimit); // convert into ExPolygons Slic3r::ExPolygons retval; @@ -447,20 +504,20 @@ Slic3r::ExPolygons offset_ex(const Slic3r::ExPolygons &expolygons, const float d Slic3r::ExPolygons offset_ex(const Slic3r::Polygons &polygons, const float delta, - double scale, ClipperLib::JoinType joinType, double miterLimit) + ClipperLib::JoinType joinType, double miterLimit) { Slic3r::ExPolygons expp; - offset(polygons, &expp, delta, scale, joinType, miterLimit); + offset(polygons, &expp, delta, joinType, miterLimit); return expp; } void 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) { // Both deltas are the same signum - offset(polygons, retval, delta1 + delta2, scale, joinType, miterLimit); + offset(polygons, retval, delta1 + delta2, joinType, miterLimit); return; } #ifdef CLIPPER_UTILS_DEBUG @@ -479,12 +536,12 @@ offset2(const Slic3r::Polygons &polygons, ClipperLib::Paths* retval, const float Slic3rMultiPoints_to_ClipperPaths(polygons, &input); // scale input - scaleClipperPolygons(input, scale); + scaleClipperPolygons(input); // prepare ClipperOffset object ClipperLib::ClipperOffset co; if (joinType == jtRound) { - co.ArcTolerance = miterLimit; + co.ArcTolerance = miterLimit * double(CLIPPER_OFFSET_SCALE); } else { co.MiterLimit = miterLimit; } @@ -492,30 +549,30 @@ offset2(const Slic3r::Polygons &polygons, ClipperLib::Paths* retval, const float // perform first offset ClipperLib::Paths output1; co.AddPaths(input, joinType, ClipperLib::etClosedPolygon); - co.Execute(output1, (delta1*scale)); + co.Execute(output1, delta1 * float(CLIPPER_OFFSET_SCALE)); #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 */ // perform second offset co.Clear(); co.AddPaths(output1, joinType, ClipperLib::etClosedPolygon); - co.Execute(*retval, (delta2*scale)); + co.Execute(*retval, delta2 * float(CLIPPER_OFFSET_SCALE)); #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 */ // unscale output - scaleClipperPolygons(*retval, 1/scale); + unscaleClipperPolygons(*retval); } void 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 ClipperLib::Paths output; - offset2(polygons, &output, delta1, delta2, scale, joinType, miterLimit); + offset2(polygons, &output, delta1, delta2, joinType, miterLimit); // convert into ExPolygons ClipperPaths_to_Slic3rMultiPoints(output, retval); @@ -523,20 +580,20 @@ offset2(const Slic3r::Polygons &polygons, Slic3r::Polygons* retval, const float Slic3r::Polygons 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; - offset2(polygons, &pp, delta1, delta2, scale, joinType, miterLimit); + offset2(polygons, &pp, delta1, delta2, joinType, miterLimit); return pp; } void 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 ClipperLib::Paths output; - offset2(polygons, &output, delta1, delta2, scale, joinType, miterLimit); + offset2(polygons, &output, delta1, delta2, joinType, miterLimit); // convert into ExPolygons ClipperPaths_to_Slic3rExPolygons(output, retval); @@ -544,10 +601,10 @@ offset2(const Slic3r::Polygons &polygons, Slic3r::ExPolygons* retval, const floa Slic3r::ExPolygons 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; - offset2(polygons, &expp, delta1, delta2, scale, joinType, miterLimit); + offset2(polygons, &expp, delta1, delta2, joinType, miterLimit); return expp; } @@ -580,6 +637,13 @@ void _clipper_do(const ClipperLib::ClipType clipType, const Slic3r::Polygons &su PROFILE_BLOCK(_clipper_do_polygons_AddPaths); clipper.AddPaths(input_subject, ClipperLib::ptSubject, 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 @@ -986,22 +1050,39 @@ void safety_offset(ClipperLib::Paths* paths) PROFILE_FUNC(); // scale input - scaleClipperPolygons(*paths, CLIPPER_OFFSET_SCALE); + scaleClipperPolygons(*paths); // perform offset (delta = scale 1e-05) ClipperLib::ClipperOffset co; - co.MiterLimit = 2; - { - PROFILE_BLOCK(safety_offset_AddPaths); - co.AddPaths(*paths, ClipperLib::jtMiter, ClipperLib::etClosedPolygon); - } - { - PROFILE_BLOCK(safety_offset_Execute); - co.Execute(*paths, 10.0 * CLIPPER_OFFSET_SCALE); +#ifdef CLIPPER_UTILS_DEBUG + if (clipper_export_enabled) { + static int iRun = 0; + export_clipper_input_polygons_bin(debug_out_path("safety_offset-polygons-%d", ++iRun).c_str(), *paths, ClipperLib::Paths()); + } +#endif /* CLIPPER_UTILS_DEBUG */ + ClipperLib::Paths out; + 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 - scaleClipperPolygons(*paths, 1.0/CLIPPER_OFFSET_SCALE); + unscaleClipperPolygons(*paths); } Polygons top_level_islands(const Slic3r::Polygons &polygons) diff --git a/xs/src/libslic3r/ClipperUtils.hpp b/xs/src/libslic3r/ClipperUtils.hpp index 188867fe5..783453807 100644 --- a/xs/src/libslic3r/ClipperUtils.hpp +++ b/xs/src/libslic3r/ClipperUtils.hpp @@ -14,13 +14,6 @@ using ClipperLib::jtSquare; 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 void AddOuterPolyNodeToExPolygons(ClipperLib::PolyNode& polynode, Slic3r::ExPolygons& expolygons); @@ -40,29 +33,29 @@ void scaleClipperPolygons(ClipperLib::Paths &polygons, const double scale); // offset Polygons 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); 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); 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); // This is a safe variant of the polygon offset, tailored for a single ExPolygon: // a single polygon with multiple non-overlapping holes. // 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, - double scale = CLIPPER_OFFSET_SCALE, ClipperLib::JoinType joinType = ClipperLib::jtMiter, + ClipperLib::JoinType joinType = ClipperLib::jtMiter, double miterLimit = 3); 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); 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); 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); Slic3r::ExPolygons offset_ex(const Slic3r::ExPolygon &expolygon, const float delta, double scale, ClipperLib::JoinType joinType, double miterLimit); @@ -71,36 +64,36 @@ Slic3r::ExPolygons offset_ex(const Slic3r::ExPolygons &expolygons, const float d // offset Polylines 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); template diff --git a/xs/src/libslic3r/Fill/FillRectilinear2.cpp b/xs/src/libslic3r/Fill/FillRectilinear2.cpp index 766f389b0..3f7232e06 100644 --- a/xs/src/libslic3r/Fill/FillRectilinear2.cpp +++ b/xs/src/libslic3r/Fill/FillRectilinear2.cpp @@ -372,11 +372,9 @@ public: bool sticks_removed = remove_sticks(polygons_src); // if (sticks_removed) printf("Sticks removed!\n"); polygons_outer = offset(polygons_src, aoffset1, - CLIPPER_OFFSET_SCALE, ClipperLib::jtMiter, mitterLimit); polygons_inner = offset(polygons_outer, aoffset2 - aoffset1, - CLIPPER_OFFSET_SCALE, ClipperLib::jtMiter, mitterLimit); // Filter out contours with zero area or small area, contours with 2 points only. diff --git a/xs/src/libslic3r/LayerRegion.cpp b/xs/src/libslic3r/LayerRegion.cpp index 7c84629e2..52e384adf 100644 --- a/xs/src/libslic3r/LayerRegion.cpp +++ b/xs/src/libslic3r/LayerRegion.cpp @@ -91,9 +91,9 @@ LayerRegion::make_perimeters(const SurfaceCollection &slices, SurfaceCollection* g.process(); } -//#define EXTERNAL_SURFACES_OFFSET_PARAMETERS CLIPPER_OFFSET_SCALE, ClipperLib::jtMiter, 3. -//#define EXTERNAL_SURFACES_OFFSET_PARAMETERS CLIPPER_OFFSET_SCALE, ClipperLib::jtMiter, 1.5 -#define EXTERNAL_SURFACES_OFFSET_PARAMETERS CLIPPER_OFFSET_SCALE, ClipperLib::jtSquare, 0. +//#define EXTERNAL_SURFACES_OFFSET_PARAMETERS ClipperLib::jtMiter, 3. +//#define EXTERNAL_SURFACES_OFFSET_PARAMETERS ClipperLib::jtMiter, 1.5 +#define EXTERNAL_SURFACES_OFFSET_PARAMETERS ClipperLib::jtSquare, 0. void LayerRegion::process_external_surfaces(const Layer* lower_layer) @@ -194,7 +194,7 @@ LayerRegion::process_external_surfaces(const Layer* lower_layer) break; } // 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) { printf("Bridge did not fall into the source region!\r\n"); } else { diff --git a/xs/src/libslic3r/Print.cpp b/xs/src/libslic3r/Print.cpp index 3ef964339..f396409e7 100644 --- a/xs/src/libslic3r/Print.cpp +++ b/xs/src/libslic3r/Print.cpp @@ -610,7 +610,7 @@ Print::validate() const // grow convex hull with the clearance margin { 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(); } diff --git a/xs/src/libslic3r/PrintObject.cpp b/xs/src/libslic3r/PrintObject.cpp index 3808a545e..84891d2df 100644 --- a/xs/src/libslic3r/PrintObject.cpp +++ b/xs/src/libslic3r/PrintObject.cpp @@ -692,8 +692,7 @@ PrintObject::discover_vertical_shells() #if 1 // 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). - shell = offset2(shell, - 0.5f * min_perimeter_infill_spacing, 0.8f * min_perimeter_infill_spacing, - CLIPPER_OFFSET_SCALE, ClipperLib::jtSquare); + shell = offset2(shell, - 0.5f * min_perimeter_infill_spacing, 0.8f * min_perimeter_infill_spacing, ClipperLib::jtSquare); if (shell.empty()) continue; #else @@ -705,7 +704,7 @@ PrintObject::discover_vertical_shells() // 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 // 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()) { // 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 diff --git a/xs/xsp/Clipper.xsp b/xs/xsp/Clipper.xsp index 7a33ea0c4..6a28ea3ca 100644 --- a/xs/xsp/Clipper.xsp +++ b/xs/xsp/Clipper.xsp @@ -16,58 +16,53 @@ _constant() JT_MITER = jtMiter JT_ROUND = jtRound JT_SQUARE = jtSquare - CLIPPER_OFFSET_SCALE = CLIPPER_OFFSET_SCALE CODE: RETVAL = ix; OUTPUT: RETVAL Polygons -offset(polygons, delta, scale = CLIPPER_OFFSET_SCALE, joinType = ClipperLib::jtMiter, miterLimit = 3) +offset(polygons, delta, joinType = ClipperLib::jtMiter, miterLimit = 3) Polygons polygons const float delta - double scale ClipperLib::JoinType joinType double miterLimit CODE: - offset(polygons, &RETVAL, delta, scale, joinType, miterLimit); + offset(polygons, &RETVAL, delta, joinType, miterLimit); OUTPUT: RETVAL 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 const float delta - double scale ClipperLib::JoinType joinType double miterLimit CODE: - offset(polygons, &RETVAL, delta, scale, joinType, miterLimit); + offset(polygons, &RETVAL, delta, joinType, miterLimit); OUTPUT: RETVAL 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 const float delta1 const float delta2 - double scale ClipperLib::JoinType joinType double miterLimit CODE: - offset2(polygons, &RETVAL, delta1, delta2, scale, joinType, miterLimit); + offset2(polygons, &RETVAL, delta1, delta2, joinType, miterLimit); OUTPUT: RETVAL 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 const float delta1 const float delta2 - double scale ClipperLib::JoinType joinType double miterLimit CODE: - offset2(polygons, &RETVAL, delta1, delta2, scale, joinType, miterLimit); + offset2(polygons, &RETVAL, delta1, delta2, joinType, miterLimit); OUTPUT: RETVAL diff --git a/xs/xsp/Polyline.xsp b/xs/xsp/Polyline.xsp index 31bd4045e..176826290 100644 --- a/xs/xsp/Polyline.xsp +++ b/xs/xsp/Polyline.xsp @@ -80,13 +80,12 @@ Polyline::rotate(angle, center_sv) THIS->rotate(angle, center); Polygons -Polyline::grow(delta, scale = CLIPPER_OFFSET_SCALE, joinType = ClipperLib::jtSquare, miterLimit = 3) +Polyline::grow(delta, joinType = ClipperLib::jtSquare, miterLimit = 3) const float delta - double scale ClipperLib::JoinType joinType double miterLimit CODE: - offset(*THIS, &RETVAL, delta, scale, joinType, miterLimit); + offset(*THIS, &RETVAL, delta, joinType, miterLimit); OUTPUT: RETVAL diff --git a/xs/xsp/Surface.xsp b/xs/xsp/Surface.xsp index 597ed1b5d..4e3bbbb69 100644 --- a/xs/xsp/Surface.xsp +++ b/xs/xsp/Surface.xsp @@ -83,13 +83,12 @@ Surface::polygons() RETVAL Surfaces -Surface::offset(delta, scale = CLIPPER_OFFSET_SCALE, joinType = ClipperLib::jtMiter, miterLimit = 3) +Surface::offset(delta, joinType = ClipperLib::jtMiter, miterLimit = 3) const float delta - double scale ClipperLib::JoinType joinType double miterLimit CODE: - offset(*THIS, &RETVAL, delta, scale, joinType, miterLimit); + offset(*THIS, &RETVAL, delta, joinType, miterLimit); OUTPUT: RETVAL