Ported offset() and offset2()

This commit is contained in:
Alessandro Ranellucci 2013-07-17 00:48:29 +02:00
parent bf8c799685
commit c7b6818ccf
15 changed files with 152 additions and 81 deletions

View File

@ -35,7 +35,7 @@ sub is_printable {
# try to get an inwards offset
# for a distance equal to half of the extrusion width;
# if no offset is possible, then expolygon is not printable.
return Slic3r::Geometry::Clipper::offset($self, -$width / 2) ? 1 : 0;
return @{Slic3r::Geometry::Clipper::offset($self, -$width / 2)} ? 1 : 0;
}
sub wkt {
@ -46,7 +46,7 @@ sub wkt {
sub offset {
my $self = shift;
return Slic3r::Geometry::Clipper::offset($self, @_);
return Slic3r::Geometry::Clipper::offset(\@$self, @_);
}
sub offset_ex {

View File

@ -105,17 +105,17 @@ sub make_fill {
{
my $collapsed = diff(
[ map @{$_->expolygon}, @surfaces ],
[ offset(
[ offset([ map @{$_->expolygon}, @surfaces ], -$distance_between_surfaces/2) ],
offset(
offset([ map @{$_->expolygon}, @surfaces ], -$distance_between_surfaces/2),
+$distance_between_surfaces/2
) ],
),
1,
);
push @surfaces, map Slic3r::Surface->new(
expolygon => $_,
surface_type => S_TYPE_INTERNALSOLID,
), @{intersection_ex(
[ offset($collapsed, $distance_between_surfaces) ],
offset($collapsed, $distance_between_surfaces),
[
(map @{$_->expolygon}, grep $_->surface_type == S_TYPE_INTERNALVOID, @surfaces),
(@$collapsed),
@ -125,7 +125,7 @@ sub make_fill {
}
# add spacing between surfaces
@surfaces = map $_->offset(-$distance_between_surfaces / 2 * &Slic3r::INFILL_OVERLAP_OVER_SPACING), @surfaces;
@surfaces = map @{$_->offset(-$distance_between_surfaces / 2 * &Slic3r::INFILL_OVERLAP_OVER_SPACING)}, @surfaces;
my @fills = ();
my @fills_ordering_points = ();

View File

@ -29,9 +29,9 @@ sub fill_surface {
# compensate the overlap which is good for rectilinear but harmful for concentric
# where the perimeter/infill spacing should be equal to any other loop spacing
my @loops = my @last = offset($expolygon, -&Slic3r::INFILL_OVERLAP_OVER_SPACING * $min_spacing / 2);
my @loops = my @last = @{offset($expolygon, -&Slic3r::INFILL_OVERLAP_OVER_SPACING * $min_spacing / 2)};
while (@last) {
push @loops, @last = offset2(\@last, -1.5*$distance, +0.5*$distance);
push @loops, @last = @{offset2(\@last, -1.5*$distance, +0.5*$distance)};
}
# generate paths from the outermost to the innermost, to avoid

View File

@ -52,7 +52,7 @@ sub BUILD {
: $self->islands->[$i]->offset_ex(-$self->_inner_margin);
# offset the island outwards to make the boundaries for external movements
$self->_outer->[$i] = [ offset([ $self->islands->[$i]->contour], $self->_outer_margin) ];
$self->_outer->[$i] = offset([ $self->islands->[$i]->contour], $self->_outer_margin);
# if internal motion is enabled, build a set of utility expolygons representing
# the outer boundaries (as contours) and the inner boundaries (as holes). whenever

View File

@ -25,26 +25,6 @@ sub safety_offset_ex {
@{Math::Clipper::ex_int_offset(_convert($polygons), $factor // (scale 1e-05), 100000, JT_MITER, 2)};
}
sub offset {
my ($polygons, $distance, $scale, $joinType, $miterLimit) = @_;
$scale ||= 100000;
$joinType //= JT_MITER;
$miterLimit //= 3;
my $offsets = Math::Clipper::int_offset(_convert($polygons), $distance, $scale, $joinType, $miterLimit);
return @$offsets;
}
sub offset2 {
my ($polygons, $distance1, $distance2, $scale, $joinType, $miterLimit) = @_;
$scale ||= 100000;
$joinType //= JT_MITER;
$miterLimit //= 3;
my $offsets = Math::Clipper::int_offset2(_convert($polygons), $distance1, $distance2, $scale, $joinType, $miterLimit);
return @$offsets;
}
sub diff {
my ($subject, $clip, $safety_offset) = @_;

View File

@ -96,7 +96,7 @@ sub make_surfaces {
my $width = $self->perimeter_flow->scaled_width;
my $diff = diff_ex(
[ map $_->p, @{$self->slices} ],
[ offset2([ map @$_, map $_->expolygon, @{$self->slices} ], -$width, +$width) ],
offset2([ map @$_, map $_->expolygon, @{$self->slices} ], -$width, +$width),
1,
);
@ -189,10 +189,10 @@ sub make_perimeters {
# and we can extract the gap for later processing
if ($Slic3r::Config->gap_fill_speed > 0 && $Slic3r::Config->fill_density > 0) {
my $diff = diff_ex(
[ offset(\@last, -0.5*$spacing) ],
offset(\@last, -0.5*$spacing),
# +2 on the offset here makes sure that Clipper float truncation
# won't shrink the clip polygon to be smaller than intended.
[ offset(\@offsets, +0.5*$spacing + 2) ],
offset(\@offsets, +0.5*$spacing + 2),
);
push @gaps, grep $_->area >= $gap_area_threshold, @$diff;
}
@ -416,12 +416,12 @@ sub process_external_surfaces {
# offset them and intersect the results with the actual fill boundaries
my $margin = scale 3; # TODO: ensure this is greater than the total thickness of the perimeters
@top = @{intersection_ex(
[ Slic3r::Geometry::Clipper::offset([ map $_->p, @top ], +$margin) ],
Slic3r::Geometry::Clipper::offset([ map $_->p, @top ], +$margin),
[ map $_->p, @fill_boundaries ],
1, # to ensure adjacent expolygons are unified
)};
@bottom = @{intersection_ex(
[ Slic3r::Geometry::Clipper::offset([ map $_->p, @bottom ], +$margin) ],
Slic3r::Geometry::Clipper::offset([ map $_->p, @bottom ], +$margin),
[ map $_->p, @fill_boundaries ],
1, # to ensure adjacent expolygons are unified
)};

View File

@ -86,7 +86,7 @@ sub is_printable {
# detect them and we would be discarding them.
my $p = $self->clone;
$p->make_counter_clockwise;
return Slic3r::Geometry::Clipper::offset([$p], -$width / 2) ? 1 : 0;
return @{Slic3r::Geometry::Clipper::offset([$p], -$width / 2)} ? 1 : 0;
}
sub is_valid {

View File

@ -47,10 +47,10 @@ sub grow {
my @points = @$self;
return map Slic3r::Polygon->new(@$_),
Slic3r::Geometry::Clipper::offset(
@{Slic3r::Geometry::Clipper::offset(
[ Slic3r::Polygon->new(@points, CORE::reverse @points[1..($#points-1)]) ],
$distance, $scale, $joinType, $miterLimit,
);
)};
}
sub nearest_point_to {

View File

@ -172,8 +172,8 @@ sub validate {
my @points = map [ @$_[X,Y] ], map @{$_->vertices}, @{$self->objects->[$obj_idx]->meshes};
my $convex_hull = Slic3r::Polygon->new(@{convex_hull(\@points)});
($clearance) = map Slic3r::Polygon->new(@$_),
Slic3r::Geometry::Clipper::offset(
[$convex_hull], scale $Slic3r::Config->extruder_clearance_radius / 2, 1, JT_ROUND);
@{Slic3r::Geometry::Clipper::offset(
[$convex_hull], scale $Slic3r::Config->extruder_clearance_radius / 2, 1, JT_ROUND)};
}
for my $copy (@{$self->objects->[$obj_idx]->copies}) {
my $copy_clearance = $clearance->clone;
@ -610,7 +610,7 @@ sub make_skirt {
my $distance = scale $Slic3r::Config->skirt_distance;
for (my $i = $Slic3r::Config->skirts; $i > 0; $i--) {
$distance += scale $spacing;
my ($loop) = Slic3r::Geometry::Clipper::offset([$convex_hull], $distance, 0.0001, JT_ROUND);
my $loop = Slic3r::Geometry::Clipper::offset([$convex_hull], $distance, 0.0001, JT_ROUND)->[0];
push @{$self->skirt}, Slic3r::ExtrusionLoop->new(
polygon => Slic3r::Polygon->new(@$loop),
role => EXTR_ROLE_SKIRT,
@ -666,7 +666,7 @@ sub make_brim {
# JT_SQUARE ensures no vertex is outside the given offset distance
# -0.5 because islands are not represented by their centerlines
# TODO: we need the offset inwards/offset outwards logic to avoid overlapping extrusions
push @loops, offset2(\@islands, ($i - 1.5) * $flow->scaled_spacing, +1.0 * $flow->scaled_spacing, undef, JT_SQUARE);
push @loops, @{offset2(\@islands, ($i - 1.5) * $flow->scaled_spacing, +1.0 * $flow->scaled_spacing, undef, JT_SQUARE)};
}
@{$self->brim} = map Slic3r::ExtrusionLoop->new(

View File

@ -274,15 +274,15 @@ sub make_perimeters {
my $overlap = $perimeter_spacing; # one perimeter
my $diff = diff(
[ offset([ map @{$_->expolygon}, @{$layerm->slices} ], -($Slic3r::Config->perimeters * $perimeter_spacing)) ],
[ offset([ map @{$_->expolygon}, @{$upper_layerm->slices} ], -$overlap) ],
offset([ map @{$_->expolygon}, @{$layerm->slices} ], -($Slic3r::Config->perimeters * $perimeter_spacing)),
offset([ map @{$_->expolygon}, @{$upper_layerm->slices} ], -$overlap),
);
next if !@$diff;
# if we need more perimeters, $diff should contain a narrow region that we can collapse
$diff = diff(
$diff,
[ offset2($diff, -$perimeter_spacing, +$perimeter_spacing) ],
offset2($diff, -$perimeter_spacing, +$perimeter_spacing),
1,
);
next if !@$diff;
@ -295,8 +295,8 @@ sub make_perimeters {
# of our slice
$extra_perimeters++;
my $hypothetical_perimeter = diff(
[ offset($slice->expolygon->arrayref, -($perimeter_spacing * ($Slic3r::Config->perimeters + $extra_perimeters-1))) ],
[ offset($slice->expolygon->arrayref, -($perimeter_spacing * ($Slic3r::Config->perimeters + $extra_perimeters))) ],
offset($slice->expolygon->arrayref, -($perimeter_spacing * ($Slic3r::Config->perimeters + $extra_perimeters-1))),
offset($slice->expolygon->arrayref, -($perimeter_spacing * ($Slic3r::Config->perimeters + $extra_perimeters))),
);
last CYCLE if !@$hypothetical_perimeter; # no extra perimeter is possible
@ -620,7 +620,7 @@ sub discover_horizontal_shells {
my $margin = 3 * $layerm->solid_infill_flow->scaled_width; # require at least this size
my $too_narrow = diff_ex(
[ map @$_, @$new_internal_solid ],
[ offset([ offset([ map @$_, @$new_internal_solid ], -$margin) ], +$margin) ],
offset(offset([ map @$_, @$new_internal_solid ], -$margin), +$margin),
1,
);
@ -634,7 +634,7 @@ sub discover_horizontal_shells {
# make sure our grown surfaces don't exceed the fill area
my @grown = map @$_, @{intersection_ex(
[ offset([ map @$_, @$too_narrow ], +$margin) ],
offset([ map @$_, @$too_narrow ], +$margin),
[ map $_->p, @fill_boundaries ],
)};
$new_internal_solid = union_ex([ @grown, (map @$_, @$new_internal_solid) ]);
@ -745,7 +745,7 @@ sub combine_infill {
# $intersection now contains the regions that can be combined across the full amount of layers
# so let's remove those areas from all layers
my @intersection_with_clearance = map $_->offset(
my @intersection_with_clearance = map @{$_->offset(
$layerms[-1]->solid_infill_flow->scaled_width / 2
+ $layerms[-1]->perimeter_flow->scaled_width / 2
# Because fill areas for rectilinear and honeycomb are grown
@ -753,7 +753,7 @@ sub combine_infill {
+ (($type == S_TYPE_INTERNALSOLID || $Slic3r::Config->fill_pattern =~ /(rectilinear|honeycomb)/)
? $layerms[-1]->solid_infill_flow->scaled_width * &Slic3r::INFILL_OVERLAP_OVER_SPACING
: 0)
), @$intersection;
)}, @$intersection;
foreach my $layerm (@layerms) {

View File

@ -35,7 +35,7 @@ sub group {
sub offset {
my $self = shift;
return map $self->clone(expolygon => $_), @{$self->expolygon->offset_ex(@_)};
return [ map $self->clone(expolygon => $_), @{$self->expolygon->offset_ex(@_)} ];
}
sub simplify {

View File

@ -550,7 +550,7 @@ sub horizontal_projection {
my $scale_vector = Math::Clipper::integerize_coordinate_sets({ bits => 32 }, @f);
$_->make_counter_clockwise for @f; # do this after scaling, as winding order might change while doing that
my $union = union_ex([ Slic3r::Geometry::Clipper::offset(\@f, 10000) ]);
my $union = union_ex(Slic3r::Geometry::Clipper::offset(\@f, 10000));
$union = [ map $_->arrayref, @$union ];
Math::Clipper::unscale_coordinate_sets($scale_vector, $_) for @$union;
return $union;

View File

@ -2,15 +2,6 @@
namespace Slic3r {
void
ClipperPolygon_to_Slic3rPolygon(ClipperLib::Polygon &input, Slic3r::Polygon &output)
{
output.points.clear();
for (ClipperLib::Polygon::iterator pit = input.begin(); pit != input.end(); ++pit) {
output.points.push_back(Slic3r::Point( (*pit).X, (*pit).Y ));
}
}
//-----------------------------------------------------------
// legacy code from Clipper documentation
void AddOuterPolyNodeToExPolygons(ClipperLib::PolyNode& polynode, Slic3r::ExPolygons& expolygons)
@ -37,21 +28,21 @@ void PolyTreeToExPolygons(ClipperLib::PolyTree& polytree, Slic3r::ExPolygons& ex
//-----------------------------------------------------------
void
Slic3rPolygon_to_ClipperPolygon(Slic3r::Polygon &input, ClipperLib::Polygon &output)
ClipperPolygon_to_Slic3rPolygon(ClipperLib::Polygon &input, Slic3r::Polygon &output)
{
output.clear();
for (Slic3r::Points::iterator pit = input.points.begin(); pit != input.points.end(); ++pit) {
output.push_back(ClipperLib::IntPoint( (*pit).x, (*pit).y ));
output.points.clear();
for (ClipperLib::Polygon::iterator pit = input.begin(); pit != input.end(); ++pit) {
output.points.push_back(Slic3r::Point( (*pit).X, (*pit).Y ));
}
}
void
Slic3rPolygons_to_ClipperPolygons(Slic3r::Polygons &input, ClipperLib::Polygons &output)
ClipperPolygons_to_Slic3rPolygons(ClipperLib::Polygons &input, Slic3r::Polygons &output)
{
output.clear();
for (Slic3r::Polygons::iterator it = input.begin(); it != input.end(); ++it) {
ClipperLib::Polygon p;
Slic3rPolygon_to_ClipperPolygon(*it, p);
for (ClipperLib::Polygons::iterator it = input.begin(); it != input.end(); ++it) {
Slic3r::Polygon p;
ClipperPolygon_to_Slic3rPolygon(*it, p);
output.push_back(p);
}
}
@ -75,6 +66,26 @@ ClipperPolygons_to_Slic3rExPolygons(ClipperLib::Polygons &input, Slic3r::ExPolyg
delete polytree;
}
void
Slic3rPolygon_to_ClipperPolygon(Slic3r::Polygon &input, ClipperLib::Polygon &output)
{
output.clear();
for (Slic3r::Points::iterator pit = input.points.begin(); pit != input.points.end(); ++pit) {
output.push_back(ClipperLib::IntPoint( (*pit).x, (*pit).y ));
}
}
void
Slic3rPolygons_to_ClipperPolygons(Slic3r::Polygons &input, ClipperLib::Polygons &output)
{
output.clear();
for (Slic3r::Polygons::iterator it = input.begin(); it != input.end(); ++it) {
ClipperLib::Polygon p;
Slic3rPolygon_to_ClipperPolygon(*it, p);
output.push_back(p);
}
}
void
scaleClipperPolygons(ClipperLib::Polygons &polygons, const double scale)
{
@ -87,7 +98,7 @@ scaleClipperPolygons(ClipperLib::Polygons &polygons, const double scale)
}
void
offset_ex(Slic3r::Polygons &polygons, Slic3r::ExPolygons &retval, const float delta,
offset(Slic3r::Polygons &polygons, ClipperLib::Polygons &retval, const float delta,
double scale, ClipperLib::JoinType joinType, double miterLimit)
{
// read input
@ -98,12 +109,33 @@ offset_ex(Slic3r::Polygons &polygons, Slic3r::ExPolygons &retval, const float de
scaleClipperPolygons(*input, scale);
// perform offset
ClipperLib::Polygons* output = new ClipperLib::Polygons();
ClipperLib::OffsetPolygons(*input, *output, (delta*scale), joinType, miterLimit);
ClipperLib::OffsetPolygons(*input, retval, (delta*scale), joinType, miterLimit);
delete input;
// unscale output
scaleClipperPolygons(*output, 1/scale);
scaleClipperPolygons(retval, 1/scale);
}
void
offset(Slic3r::Polygons &polygons, Slic3r::Polygons &retval, const float delta,
double scale, ClipperLib::JoinType joinType, double miterLimit)
{
// perform offset
ClipperLib::Polygons* output = new ClipperLib::Polygons();
offset(polygons, *output, delta, scale, joinType, miterLimit);
// convert into ExPolygons
ClipperPolygons_to_Slic3rPolygons(*output, retval);
delete output;
}
void
offset_ex(Slic3r::Polygons &polygons, Slic3r::ExPolygons &retval, const float delta,
double scale, ClipperLib::JoinType joinType, double miterLimit)
{
// perform offset
ClipperLib::Polygons* output = new ClipperLib::Polygons();
offset(polygons, *output, delta, scale, joinType, miterLimit);
// convert into ExPolygons
ClipperPolygons_to_Slic3rExPolygons(*output, retval);
@ -111,7 +143,7 @@ offset_ex(Slic3r::Polygons &polygons, Slic3r::ExPolygons &retval, const float de
}
void
offset2_ex(Slic3r::Polygons &polygons, Slic3r::ExPolygons &retval, const float delta1,
offset2(Slic3r::Polygons &polygons, ClipperLib::Polygons &retval, const float delta1,
const float delta2, double scale, ClipperLib::JoinType joinType, double miterLimit)
{
// read input
@ -127,16 +159,37 @@ offset2_ex(Slic3r::Polygons &polygons, Slic3r::ExPolygons &retval, const float d
delete input;
// perform second offset
ClipperLib::Polygons* output2 = new ClipperLib::Polygons();
ClipperLib::OffsetPolygons(*output1, *output2, (delta2*scale), joinType, miterLimit);
ClipperLib::OffsetPolygons(*output1, retval, (delta2*scale), joinType, miterLimit);
delete output1;
// unscale output
scaleClipperPolygons(*output2, 1/scale);
scaleClipperPolygons(retval, 1/scale);
}
void
offset2(Slic3r::Polygons &polygons, Slic3r::Polygons &retval, const float delta1,
const float delta2, double scale, ClipperLib::JoinType joinType, double miterLimit)
{
// perform offset
ClipperLib::Polygons* output = new ClipperLib::Polygons();
offset2(polygons, *output, delta1, delta2, scale, joinType, miterLimit);
// convert into ExPolygons
ClipperPolygons_to_Slic3rExPolygons(*output2, retval);
delete output2;
ClipperPolygons_to_Slic3rPolygons(*output, retval);
delete output;
}
void
offset2_ex(Slic3r::Polygons &polygons, Slic3r::ExPolygons &retval, const float delta1,
const float delta2, double scale, ClipperLib::JoinType joinType, double miterLimit)
{
// perform offset
ClipperLib::Polygons* output = new ClipperLib::Polygons();
offset2(polygons, *output, delta1, delta2, scale, joinType, miterLimit);
// convert into ExPolygons
ClipperPolygons_to_Slic3rExPolygons(*output, retval);
delete output;
}
inline void _clipper_ex(ClipperLib::ClipType clipType, Slic3r::Polygons &subject,

View File

@ -8,7 +8,6 @@
namespace Slic3r {
void ClipperPolygon_to_Slic3rPolygon(ClipperLib::Polygon &input, Slic3r::Polygon &output);
//-----------------------------------------------------------
// legacy code from Clipper documentation
@ -18,14 +17,28 @@ void PolyTreeToExPolygons(ClipperLib::PolyTree& polytree, Slic3r::ExPolygons& ex
void Slic3rPolygon_to_ClipperPolygon(Slic3r::Polygon &input, ClipperLib::Polygon &output);
void Slic3rPolygons_to_ClipperPolygons(Slic3r::Polygons &input, ClipperLib::Polygons &output);
void ClipperPolygon_to_Slic3rPolygon(ClipperLib::Polygon &input, Slic3r::Polygon &output);
void ClipperPolygons_to_Slic3rPolygons(ClipperLib::Polygons &input, Slic3r::Polygons &output);
void ClipperPolygons_to_Slic3rExPolygons(ClipperLib::Polygons &input, Slic3r::ExPolygons &output);
void scaleClipperPolygons(ClipperLib::Polygons &polygons, const double scale);
void offset(Slic3r::Polygons &polygons, ClipperLib::Polygons &retval, const float delta,
double scale = 100000, ClipperLib::JoinType joinType = ClipperLib::jtMiter,
double miterLimit = 3);
void offset(Slic3r::Polygons &polygons, Slic3r::Polygons &retval, const float delta,
double scale = 100000, ClipperLib::JoinType joinType = ClipperLib::jtMiter,
double miterLimit = 3);
void offset_ex(Slic3r::Polygons &polygons, Slic3r::ExPolygons &retval, const float delta,
double scale = 100000, ClipperLib::JoinType joinType = ClipperLib::jtMiter,
double miterLimit = 3);
void offset2(Slic3r::Polygons &polygons, ClipperLib::Polygons &retval, const float delta1,
const float delta2, double scale = 100000, ClipperLib::JoinType joinType = ClipperLib::jtMiter,
double miterLimit = 3);
void offset2(Slic3r::Polygons &polygons, Slic3r::Polygons &retval, const float delta1,
const float delta2, double scale = 100000, ClipperLib::JoinType joinType = ClipperLib::jtMiter,
double miterLimit = 3);
void offset2_ex(Slic3r::Polygons &polygons, Slic3r::ExPolygons &retval, const float delta1,
const float delta2, double scale = 100000, ClipperLib::JoinType joinType = ClipperLib::jtMiter,
double miterLimit = 3);

View File

@ -10,6 +10,18 @@
%{
Polygons
offset(polygons, delta, scale = 100000, 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);
OUTPUT:
RETVAL
ExPolygons
offset_ex(polygons, delta, scale = 100000, joinType = ClipperLib::jtMiter, miterLimit = 3)
Polygons polygons
@ -22,6 +34,19 @@ offset_ex(polygons, delta, scale = 100000, joinType = ClipperLib::jtMiter, miter
OUTPUT:
RETVAL
Polygons
offset2(polygons, delta1, delta2, scale = 100000, 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);
OUTPUT:
RETVAL
ExPolygons
offset2_ex(polygons, delta1, delta2, scale = 100000, joinType = ClipperLib::jtMiter, miterLimit = 3)
Polygons polygons