Fix integration of XS containers
This commit is contained in:
parent
9b582a11ff
commit
9458c7db97
@ -87,9 +87,9 @@ sub encloses_line {
|
|||||||
my $clip = $self->clip_line($line);
|
my $clip = $self->clip_line($line);
|
||||||
if (!defined $tolerance) {
|
if (!defined $tolerance) {
|
||||||
# optimization
|
# optimization
|
||||||
return @$clip == 1 && same_line($clip->[0], $line);
|
return @$clip == 1 && same_line($clip->[0]->pp, $line->pp);
|
||||||
} else {
|
} else {
|
||||||
return @$clip == 1 && abs(Boost::Geometry::Utils::linestring_length($clip->[0]) - $line->length) < $tolerance;
|
return @$clip == 1 && abs(Boost::Geometry::Utils::linestring_length($clip->[0]->pp) - $line->length) < $tolerance;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,7 +102,10 @@ sub clip_line {
|
|||||||
my $self = shift;
|
my $self = shift;
|
||||||
my ($line) = @_; # line must be a Slic3r::Line object
|
my ($line) = @_; # line must be a Slic3r::Line object
|
||||||
|
|
||||||
return Boost::Geometry::Utils::polygon_multi_linestring_intersection($self->pp, [$line->pp]);
|
return [
|
||||||
|
map Slic3r::Line->new(@$_),
|
||||||
|
@{Boost::Geometry::Utils::polygon_multi_linestring_intersection($self->pp, [$line->pp])}
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
sub simplify {
|
sub simplify {
|
||||||
|
@ -18,4 +18,13 @@ sub first_point {
|
|||||||
return $self->polygon->[0];
|
return $self->polygon->[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub make_counter_clockwise {
|
||||||
|
my $self = shift;
|
||||||
|
if (!$self->polygon->is_counter_clockwise) {
|
||||||
|
$self->reverse;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
@ -32,7 +32,7 @@ sub intersect_expolygons {
|
|||||||
my ($expolygons) = @_;
|
my ($expolygons) = @_;
|
||||||
|
|
||||||
return map $self->clone(polyline => Slic3r::Polyline->new(@$_)),
|
return map $self->clone(polyline => Slic3r::Polyline->new(@$_)),
|
||||||
@{Boost::Geometry::Utils::multi_polygon_multi_linestring_intersection($expolygons, [$self->arrayref])};
|
@{Boost::Geometry::Utils::multi_polygon_multi_linestring_intersection([ map $_->pp, @$expolygons ], [$self->pp])};
|
||||||
}
|
}
|
||||||
|
|
||||||
sub subtract_expolygons {
|
sub subtract_expolygons {
|
||||||
@ -40,12 +40,24 @@ sub subtract_expolygons {
|
|||||||
my ($expolygons) = @_;
|
my ($expolygons) = @_;
|
||||||
|
|
||||||
return map $self->clone(polyline => Slic3r::Polyline->new(@$_)),
|
return map $self->clone(polyline => Slic3r::Polyline->new(@$_)),
|
||||||
@{Boost::Geometry::Utils::multi_linestring_multi_polygon_difference([$self->arrayref], $expolygons)};
|
@{Boost::Geometry::Utils::multi_linestring_multi_polygon_difference([$self->pp], [ map $_->pp, @$expolygons ])};
|
||||||
}
|
}
|
||||||
|
|
||||||
sub simplify {
|
sub simplify {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
$self->set_polyline($self->polyline->simplify(@_));
|
$self->polyline($self->polyline->simplify(@_));
|
||||||
|
}
|
||||||
|
|
||||||
|
sub clip_end {
|
||||||
|
my $self = shift;
|
||||||
|
my $polyline = $self->polyline;
|
||||||
|
$polyline->clip_end(@_);
|
||||||
|
$self->polyline($polyline);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub length {
|
||||||
|
my $self = shift;
|
||||||
|
return $self->polyline->length;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub points {
|
sub points {
|
||||||
|
@ -1,14 +1,21 @@
|
|||||||
package Slic3r::ExtrusionPath::Arc;
|
package Slic3r::ExtrusionPath::Arc;
|
||||||
use Moo;
|
use Moo;
|
||||||
|
|
||||||
extends 'Slic3r::ExtrusionPath';
|
has 'polyline' => (is => 'rw', required => 1);
|
||||||
|
has 'role' => (is => 'rw', required => 1);
|
||||||
|
has 'height' => (is => 'rw');
|
||||||
|
has 'flow_spacing' => (is => 'rw');
|
||||||
has 'center' => (is => 'ro', required => 1);
|
has 'center' => (is => 'ro', required => 1);
|
||||||
has 'radius' => (is => 'ro', required => 1);
|
has 'radius' => (is => 'ro', required => 1);
|
||||||
has 'orientation' => (is => 'ro', required => 1); # cw/ccw
|
has 'orientation' => (is => 'ro', required => 1); # cw/ccw
|
||||||
|
|
||||||
use Slic3r::Geometry qw(PI angle3points);
|
use Slic3r::Geometry qw(PI angle3points);
|
||||||
|
|
||||||
|
sub points {
|
||||||
|
my $self = shift;
|
||||||
|
return $self->polyline;
|
||||||
|
}
|
||||||
|
|
||||||
sub angle {
|
sub angle {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
return angle3points($self->center, @{$self->points});
|
return angle3points($self->center, @{$self->points});
|
||||||
|
@ -12,21 +12,35 @@ sub first_point {
|
|||||||
return $self->paths->[0]->polyline->[0];
|
return $self->paths->[0]->polyline->[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Note that our paths will be reversed in place when necessary.
|
||||||
|
# (Same algorithm as Polyline::Collection)
|
||||||
sub chained_path {
|
sub chained_path {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my ($start_near, $no_reverse) = @_;
|
my ($start_near, $no_reverse) = @_;
|
||||||
|
|
||||||
return @{$self->paths} if $self->no_sort;
|
return @{$self->paths} if $self->no_sort;
|
||||||
|
my @my_paths = @{$self->paths};
|
||||||
|
|
||||||
# make sure we pass the same path objects to the Collection constructor
|
my @paths = ();
|
||||||
# and the ->chained_path() method because the latter will reverse the
|
my $start_at;
|
||||||
# paths in-place when needed and we need to return them that way
|
my $endpoints = $no_reverse
|
||||||
my @paths = @{$self->paths};
|
? [ map { @$_[0,0] } @my_paths ]
|
||||||
my $collection = Slic3r::Polyline::Collection->new(
|
: [ map { @$_[0,-1] } @my_paths ];
|
||||||
polylines => [ map $_->polyline, @paths ],
|
while (@my_paths) {
|
||||||
);
|
# find nearest point
|
||||||
|
my $start_index = defined $start_near
|
||||||
|
? Slic3r::Geometry::nearest_point_index($start_near, $endpoints)
|
||||||
|
: 0;
|
||||||
|
|
||||||
return $collection->chained_path($start_near, \@paths, $no_reverse);
|
my $path_index = int($start_index/2);
|
||||||
|
if ($start_index % 2 && !$no_reverse) { # index is end so reverse to make it the start
|
||||||
|
$my_paths[$path_index]->reverse;
|
||||||
|
}
|
||||||
|
push @paths, splice @my_paths, $path_index, 1;
|
||||||
|
splice @$endpoints, $path_index*2, 2;
|
||||||
|
$start_near = $paths[-1][-1];
|
||||||
|
}
|
||||||
|
return @paths;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub cleanup {
|
sub cleanup {
|
||||||
|
@ -157,24 +157,20 @@ sub make_fill {
|
|||||||
next SURFACE unless $density > 0;
|
next SURFACE unless $density > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
my @paths;
|
my $f = $self->filler($filler);
|
||||||
{
|
$f->layer_id($layerm->id);
|
||||||
my $f = $self->filler($filler);
|
my ($params, @polylines) = $f->fill_surface(
|
||||||
$f->layer_id($layerm->id);
|
$surface,
|
||||||
@paths = $f->fill_surface(
|
density => $density,
|
||||||
$surface,
|
flow_spacing => $flow_spacing,
|
||||||
density => $density,
|
dont_adjust => $is_bridge,
|
||||||
flow_spacing => $flow_spacing,
|
);
|
||||||
dont_adjust => $is_bridge,
|
next unless @polylines;
|
||||||
);
|
|
||||||
}
|
|
||||||
my $params = shift @paths;
|
|
||||||
|
|
||||||
# ugly hack(tm) to get the right amount of flow (GCode.pm should be fixed)
|
# ugly hack(tm) to get the right amount of flow (GCode.pm should be fixed)
|
||||||
$params->{flow_spacing} = $layerm->extruders->{infill}->bridge_flow->width if $is_bridge;
|
$params->{flow_spacing} = $layerm->extruders->{infill}->bridge_flow->width if $is_bridge;
|
||||||
|
|
||||||
# save into layer
|
# save into layer
|
||||||
next unless @paths;
|
|
||||||
push @fills, Slic3r::ExtrusionPath::Collection->new(
|
push @fills, Slic3r::ExtrusionPath::Collection->new(
|
||||||
no_sort => $params->{no_sort},
|
no_sort => $params->{no_sort},
|
||||||
paths => [
|
paths => [
|
||||||
@ -189,10 +185,10 @@ sub make_fill {
|
|||||||
: EXTR_ROLE_FILL),
|
: EXTR_ROLE_FILL),
|
||||||
height => $surface->thickness,
|
height => $surface->thickness,
|
||||||
flow_spacing => $params->{flow_spacing} || (warn "Warning: no flow_spacing was returned by the infill engine, please report this to the developer\n"),
|
flow_spacing => $params->{flow_spacing} || (warn "Warning: no flow_spacing was returned by the infill engine, please report this to the developer\n"),
|
||||||
), @paths,
|
), @polylines,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
push @fills_ordering_points, $paths[0][0];
|
push @fills_ordering_points, $polylines[0][0];
|
||||||
}
|
}
|
||||||
|
|
||||||
# add thin fill regions
|
# add thin fill regions
|
||||||
|
@ -52,8 +52,8 @@ sub rotate_points_back {
|
|||||||
my @rotate = (-$rotate_vector->[0][0], $rotate_vector->[0][1]);
|
my @rotate = (-$rotate_vector->[0][0], $rotate_vector->[0][1]);
|
||||||
my $shift = [ map -$_, @{$rotate_vector->[1]} ];
|
my $shift = [ map -$_, @{$rotate_vector->[1]} ];
|
||||||
|
|
||||||
@$paths = map [ Slic3r::Geometry::rotate_points(@rotate, @$_) ],
|
$_->translate(@$shift) for @$paths;
|
||||||
map [ Slic3r::Geometry::move_points($shift, @$_) ], @$paths;
|
$_->rotate(@rotate) for @$paths;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub adjust_solid_spacing {
|
sub adjust_solid_spacing {
|
||||||
|
@ -91,7 +91,7 @@ sub fill_surface {
|
|||||||
@paths = map Slic3r::Polyline->new(@$_),
|
@paths = map Slic3r::Polyline->new(@$_),
|
||||||
@{ Boost::Geometry::Utils::polygon_multi_linestring_intersection(
|
@{ Boost::Geometry::Utils::polygon_multi_linestring_intersection(
|
||||||
$surface->expolygon->pp,
|
$surface->expolygon->pp,
|
||||||
\@polygons,
|
[ map $_->pp, @polygons ],
|
||||||
) };
|
) };
|
||||||
|
|
||||||
# connect paths
|
# connect paths
|
||||||
@ -104,7 +104,7 @@ sub fill_surface {
|
|||||||
my $distance = $paths[-1][-1]->distance_to($path->[0]);
|
my $distance = $paths[-1][-1]->distance_to($path->[0]);
|
||||||
|
|
||||||
if ($distance <= $m->{hex_width}) {
|
if ($distance <= $m->{hex_width}) {
|
||||||
push @{$paths[-1]}, @$path;
|
$paths[-1]->append(@$path);
|
||||||
next;
|
next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -115,8 +115,8 @@ sub fill_surface {
|
|||||||
# clip paths again to prevent connection segments from crossing the expolygon boundaries
|
# clip paths again to prevent connection segments from crossing the expolygon boundaries
|
||||||
@paths = map Slic3r::Polyline->new(@$_),
|
@paths = map Slic3r::Polyline->new(@$_),
|
||||||
@{ Boost::Geometry::Utils::multi_polygon_multi_linestring_intersection(
|
@{ Boost::Geometry::Utils::multi_polygon_multi_linestring_intersection(
|
||||||
[ map $_->arrayref, $surface->expolygon->offset_ex(scaled_epsilon) ],
|
[ map $_->pp, $surface->expolygon->offset_ex(scaled_epsilon) ],
|
||||||
[ @paths ],
|
[ map $_->pp, @paths ],
|
||||||
) } if @paths; # this temporary check is a workaround for the multilinestring bug in B::G::U
|
) } if @paths; # this temporary check is a workaround for the multilinestring bug in B::G::U
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,17 +65,18 @@ sub fill_surface {
|
|||||||
|
|
||||||
# clip paths against a slightly offsetted expolygon, so that the first and last paths
|
# clip paths against a slightly offsetted expolygon, so that the first and last paths
|
||||||
# are kept even if the expolygon has vertical sides
|
# are kept even if the expolygon has vertical sides
|
||||||
my @paths = @{ Boost::Geometry::Utils::polygon_multi_linestring_intersection(
|
my @polylines = map Slic3r::Polyline->new(@$_),
|
||||||
+($expolygon->offset_ex(scaled_epsilon))[0]->pp, # TODO: we should use all the resulting expolygons and clip the linestrings to a multipolygon object
|
@{ Boost::Geometry::Utils::multi_polygon_multi_linestring_intersection(
|
||||||
[ map $_->pp, @{ $self->cache->{$cache_id} } ],
|
[ map $_->pp, $expolygon->offset_ex(scaled_epsilon) ],
|
||||||
) };
|
[ map $_->pp, @{ $self->cache->{$cache_id} } ],
|
||||||
|
) };
|
||||||
|
|
||||||
# connect lines
|
# connect lines
|
||||||
unless ($params{dont_connect}) {
|
unless ($params{dont_connect}) {
|
||||||
my $collection = Slic3r::Polyline::Collection->new(
|
my $collection = Slic3r::Polyline::Collection->new(
|
||||||
polylines => [ map Slic3r::Polyline->new(@$_), @paths ],
|
polylines => [ @polylines ],
|
||||||
);
|
);
|
||||||
@paths = ();
|
@polylines = ();
|
||||||
|
|
||||||
my $tolerance = 10 * scaled_epsilon;
|
my $tolerance = 10 * scaled_epsilon;
|
||||||
my $diagonal_distance = $distance_between_lines * 2;
|
my $diagonal_distance = $distance_between_lines * 2;
|
||||||
@ -86,26 +87,26 @@ sub fill_surface {
|
|||||||
}
|
}
|
||||||
: sub { $_[X] <= $diagonal_distance && $_[Y] <= $diagonal_distance };
|
: sub { $_[X] <= $diagonal_distance && $_[Y] <= $diagonal_distance };
|
||||||
|
|
||||||
foreach my $path ($collection->chained_path) {
|
foreach my $polyline ($collection->chained_path) {
|
||||||
if (@paths) {
|
if (@polylines) {
|
||||||
my @distance = map abs($path->[0][$_] - $paths[-1][-1][$_]), (X,Y);
|
my $last_point = $polylines[-1][-1]->pp;
|
||||||
|
my @distance = map abs($polyline->[0][$_] - $last_point->[$_]), (X,Y);
|
||||||
|
|
||||||
# TODO: we should also check that both points are on a fill_boundary to avoid
|
# TODO: we should also check that both points are on a fill_boundary to avoid
|
||||||
# connecting paths on the boundaries of internal regions
|
# connecting paths on the boundaries of internal regions
|
||||||
if ($can_connect->(@distance)
|
if ($can_connect->(@distance) && $expolygon_off->encloses_line(Slic3r::Line->new($last_point, $polyline->[0]), $tolerance)) {
|
||||||
&& $expolygon_off->encloses_line(Slic3r::Line->new($paths[-1][-1], $path->[0]), $tolerance)) {
|
$polylines[-1]->append(@$polyline);
|
||||||
push @{$paths[-1]}, @$path;
|
|
||||||
next;
|
next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
push @paths, $path;
|
push @polylines, $polyline;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# paths must be rotated back
|
# paths must be rotated back
|
||||||
$self->rotate_points_back(\@paths, $rotate_vector);
|
$self->rotate_points_back(\@polylines, $rotate_vector);
|
||||||
|
|
||||||
return { flow_spacing => $flow_spacing }, @paths;
|
return { flow_spacing => $flow_spacing }, @polylines;
|
||||||
}
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
@ -100,7 +100,7 @@ sub change_layer {
|
|||||||
# avoid computing overhangs if they're not needed
|
# avoid computing overhangs if they're not needed
|
||||||
$self->_layer_overhangs(
|
$self->_layer_overhangs(
|
||||||
$layer->id > 0 && ($Slic3r::Config->overhangs || $Slic3r::Config->start_perimeters_at_non_overhang)
|
$layer->id > 0 && ($Slic3r::Config->overhangs || $Slic3r::Config->start_perimeters_at_non_overhang)
|
||||||
? [ map $_->expolygon->arrayref, grep $_->surface_type == S_TYPE_BOTTOM, map @{$_->slices}, @{$layer->regions} ]
|
? [ map $_->expolygon, grep $_->surface_type == S_TYPE_BOTTOM, map @{$_->slices}, @{$layer->regions} ]
|
||||||
: []
|
: []
|
||||||
);
|
);
|
||||||
if ($self->config->avoid_crossing_perimeters) {
|
if ($self->config->avoid_crossing_perimeters) {
|
||||||
@ -152,8 +152,8 @@ sub extrude_loop {
|
|||||||
my ($loop, $description) = @_;
|
my ($loop, $description) = @_;
|
||||||
|
|
||||||
# extrude all loops ccw
|
# extrude all loops ccw
|
||||||
|
my $was_clockwise = $loop->make_counter_clockwise;
|
||||||
my $polygon = $loop->polygon;
|
my $polygon = $loop->polygon;
|
||||||
my $was_clockwise = $polygon->make_counter_clockwise;
|
|
||||||
|
|
||||||
# find candidate starting points
|
# find candidate starting points
|
||||||
# start looking for concave vertices not being overhangs
|
# start looking for concave vertices not being overhangs
|
||||||
@ -310,8 +310,8 @@ sub extrude_path {
|
|||||||
$path->center, $e * unscale $path_length, $description);
|
$path->center, $e * unscale $path_length, $description);
|
||||||
$self->wipe_path(undef);
|
$self->wipe_path(undef);
|
||||||
} else {
|
} else {
|
||||||
foreach my $line ($path->lines) {
|
foreach my $line (@{$path->lines}) {
|
||||||
my $line_length = unscale $line->length;
|
my $line_length = unscale($line->length);
|
||||||
$path_length += $line_length;
|
$path_length += $line_length;
|
||||||
$gcode .= $self->G1($line->[B], undef, $e * $line_length, $description);
|
$gcode .= $self->G1($line->[B], undef, $e * $line_length, $description);
|
||||||
}
|
}
|
||||||
@ -341,8 +341,7 @@ sub travel_to {
|
|||||||
my ($point, $role, $comment) = @_;
|
my ($point, $role, $comment) = @_;
|
||||||
|
|
||||||
my $gcode = "";
|
my $gcode = "";
|
||||||
|
my $travel = Slic3r::Line->new($self->last_pos, $point);
|
||||||
my $travel = Slic3r::Line->new($self->last_pos->clone, $point->clone);
|
|
||||||
|
|
||||||
# move travel back to original layer coordinates for the island check.
|
# move travel back to original layer coordinates for the island check.
|
||||||
# note that we're only considering the current object's islands, while we should
|
# note that we're only considering the current object's islands, while we should
|
||||||
|
@ -37,7 +37,7 @@ sub parse {
|
|||||||
$info{"new_$axis"} = $self->$axis;
|
$info{"new_$axis"} = $self->$axis;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$info{dist_XY} = Slic3r::Line->new([0,0], [@info{qw(dist_X dist_Y)}])->length;
|
$info{dist_XY} = Slic3r::Geometry::unscale(Slic3r::Line->new_scale([0,0], [@info{qw(dist_X dist_Y)}])->length);
|
||||||
if (exists $args{E}) {
|
if (exists $args{E}) {
|
||||||
if ($info{dist_E} > 0) {
|
if ($info{dist_E} > 0) {
|
||||||
$info{extruding} = 1;
|
$info{extruding} = 1;
|
||||||
|
@ -195,21 +195,22 @@ sub point_in_segment {
|
|||||||
my ($point, $line) = @_;
|
my ($point, $line) = @_;
|
||||||
|
|
||||||
my ($x, $y) = @$point;
|
my ($x, $y) = @$point;
|
||||||
my @line_x = sort { $a <=> $b } $line->[A][X], $line->[B][X];
|
my $line_p = $line->pp;
|
||||||
my @line_y = sort { $a <=> $b } $line->[A][Y], $line->[B][Y];
|
my @line_x = sort { $a <=> $b } $line_p->[A][X], $line_p->[B][X];
|
||||||
|
my @line_y = sort { $a <=> $b } $line_p->[A][Y], $line_p->[B][Y];
|
||||||
|
|
||||||
# check whether the point is in the segment bounding box
|
# check whether the point is in the segment bounding box
|
||||||
return 0 unless $x >= ($line_x[0] - epsilon) && $x <= ($line_x[1] + epsilon)
|
return 0 unless $x >= ($line_x[0] - epsilon) && $x <= ($line_x[1] + epsilon)
|
||||||
&& $y >= ($line_y[0] - epsilon) && $y <= ($line_y[1] + epsilon);
|
&& $y >= ($line_y[0] - epsilon) && $y <= ($line_y[1] + epsilon);
|
||||||
|
|
||||||
# if line is vertical, check whether point's X is the same as the line
|
# if line is vertical, check whether point's X is the same as the line
|
||||||
if ($line->[A][X] == $line->[B][X]) {
|
if ($line_p->[A][X] == $line_p->[B][X]) {
|
||||||
return abs($x - $line->[A][X]) < epsilon ? 1 : 0;
|
return abs($x - $line_p->[A][X]) < epsilon ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
# calculate the Y in line at X of the point
|
# calculate the Y in line at X of the point
|
||||||
my $y3 = $line->[A][Y] + ($line->[B][Y] - $line->[A][Y])
|
my $y3 = $line_p->[A][Y] + ($line_p->[B][Y] - $line_p->[A][Y])
|
||||||
* ($x - $line->[A][X]) / ($line->[B][X] - $line->[A][X]);
|
* ($x - $line_p->[A][X]) / ($line_p->[B][X] - $line_p->[A][X]);
|
||||||
return abs($y3 - $y) < epsilon ? 1 : 0;
|
return abs($y3 - $y) < epsilon ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -250,18 +251,18 @@ sub nearest_point_index {
|
|||||||
|
|
||||||
my ($nearest_point_index, $distance) = ();
|
my ($nearest_point_index, $distance) = ();
|
||||||
|
|
||||||
my $point_x = $point->[X];
|
my ($point_x, $point_y) = @$point;
|
||||||
my $point_y = $point->[Y];
|
my @points_pp = map $_->pp, @$points;
|
||||||
|
|
||||||
for my $i (0..$#$points) {
|
for my $i (0..$#$points) {
|
||||||
my $d = ($point_x - $points->[$i]->[X])**2;
|
my $d = ($point_x - $points_pp[$i][X])**2;
|
||||||
# If the X distance of the candidate is > than the total distance of the
|
# If the X distance of the candidate is > than the total distance of the
|
||||||
# best previous candidate, we know we don't want it
|
# best previous candidate, we know we don't want it
|
||||||
next if (defined $distance && $d > $distance);
|
next if (defined $distance && $d > $distance);
|
||||||
|
|
||||||
# If the total distance of the candidate is > than the total distance of the
|
# If the total distance of the candidate is > than the total distance of the
|
||||||
# best previous candidate, we know we don't want it
|
# best previous candidate, we know we don't want it
|
||||||
$d += ($point_y - $points->[$i]->[Y])**2;
|
$d += ($point_y - $points_pp[$i][Y])**2;
|
||||||
next if (defined $distance && $d > $distance);
|
next if (defined $distance && $d > $distance);
|
||||||
|
|
||||||
$nearest_point_index = $i;
|
$nearest_point_index = $i;
|
||||||
@ -286,14 +287,14 @@ sub point_along_segment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $point;
|
return Slic3r::Point->new(@$point);
|
||||||
}
|
}
|
||||||
|
|
||||||
# given a $polygon, return the (first) segment having $point
|
# given a $polygon, return the (first) segment having $point
|
||||||
sub polygon_segment_having_point {
|
sub polygon_segment_having_point {
|
||||||
my ($polygon, $point) = @_;
|
my ($polygon, $point) = @_;
|
||||||
|
|
||||||
foreach my $line (polygon_lines($polygon)) {
|
foreach my $line (@{ $polygon->lines }) {
|
||||||
return $line if point_in_segment($point, $line);
|
return $line if point_in_segment($point, $line);
|
||||||
}
|
}
|
||||||
return undef;
|
return undef;
|
||||||
|
@ -181,7 +181,7 @@ sub traverse_pt {
|
|||||||
sub _convert {
|
sub _convert {
|
||||||
my $p = shift;
|
my $p = shift;
|
||||||
$p = $p->pp if ref($p) ne 'ARRAY' && $p->can('pp');
|
$p = $p->pp if ref($p) ne 'ARRAY' && $p->can('pp');
|
||||||
return [ map { ref($_) ne 'ARRAY' && $_->can('pp') ? $_->pp : $_ } @$p ];
|
return [ map { (ref($_) ne 'ARRAY' && $_->can('pp')) ? $_->pp : $_ } @$p ];
|
||||||
}
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
@ -31,8 +31,7 @@ has 'slices' => (is => 'rw', default => sub { Slic3r::Surface::Collection->new }
|
|||||||
# in the original geometry
|
# in the original geometry
|
||||||
has 'thin_walls' => (is => 'rw', default => sub { [] });
|
has 'thin_walls' => (is => 'rw', default => sub { [] });
|
||||||
|
|
||||||
# collection of polygons or polylines representing thin infill regions that
|
# collection of extrusion paths/loops filling gaps
|
||||||
# need to be filled with a medial axis
|
|
||||||
has 'thin_fills' => (is => 'rw', default => sub { [] });
|
has 'thin_fills' => (is => 'rw', default => sub { [] });
|
||||||
|
|
||||||
# collection of surfaces for infill generation
|
# collection of surfaces for infill generation
|
||||||
@ -234,7 +233,7 @@ sub make_perimeters {
|
|||||||
# use a nearest neighbor search to order these children
|
# use a nearest neighbor search to order these children
|
||||||
# TODO: supply second argument to chained_path_items() too?
|
# TODO: supply second argument to chained_path_items() too?
|
||||||
my @nodes = @{Slic3r::Geometry::chained_path_items(
|
my @nodes = @{Slic3r::Geometry::chained_path_items(
|
||||||
[ map [ ($_->{outer} ? $_->{outer}[0] : $_->{hole}[0]), $_ ], @$polynodes ],
|
[ map [ Slic3r::Point->new(@{$_->{outer} ? $_->{outer}[0] : $_->{hole}[0]}), $_ ], @$polynodes ],
|
||||||
)};
|
)};
|
||||||
|
|
||||||
my @loops = ();
|
my @loops = ();
|
||||||
|
@ -2,6 +2,11 @@ package Slic3r::Point;
|
|||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
|
||||||
|
sub new_scale {
|
||||||
|
my $class = shift;
|
||||||
|
return $class->new(map Slic3r::Geometry::scale($_), @_);
|
||||||
|
}
|
||||||
|
|
||||||
sub distance_to {
|
sub distance_to {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my ($point) = @_;
|
my ($point) = @_;
|
||||||
|
@ -54,7 +54,7 @@ sub remove_acute_vertices {
|
|||||||
sub encloses_point {
|
sub encloses_point {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my ($point) = @_;
|
my ($point) = @_;
|
||||||
return Boost::Geometry::Utils::point_covered_by_polygon($point->arrayref, [$self->pp]);
|
return Boost::Geometry::Utils::point_covered_by_polygon($point->pp, [$self->pp]);
|
||||||
}
|
}
|
||||||
|
|
||||||
sub area {
|
sub area {
|
||||||
@ -138,9 +138,10 @@ sub split_at {
|
|||||||
sub concave_points {
|
sub concave_points {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
|
|
||||||
|
my @points = @{$self->pp};
|
||||||
return map $self->[$_],
|
return map $self->[$_],
|
||||||
grep Slic3r::Geometry::angle3points(@$self[$_, $_-1, $_+1]) < PI - epsilon,
|
grep Slic3r::Geometry::angle3points(@points[$_, $_-1, $_+1]) < PI - epsilon,
|
||||||
-1 .. ($#$self-1);
|
-1 .. ($#points-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
1;
|
1;
|
@ -6,6 +6,12 @@ use Slic3r::Geometry qw(A B X Y X1 X2 Y1 Y2 polyline_remove_parallel_continuous_
|
|||||||
use Slic3r::Geometry::Clipper qw(JT_SQUARE);
|
use Slic3r::Geometry::Clipper qw(JT_SQUARE);
|
||||||
use Storable qw();
|
use Storable qw();
|
||||||
|
|
||||||
|
sub new_scale {
|
||||||
|
my $class = shift;
|
||||||
|
my @points = map { ref($_) eq 'Slic3r::Point' ? $_->pp : $_ } @_;
|
||||||
|
return $class->new(map [ Slic3r::Geometry::scale($_->[X]), Slic3r::Geometry::scale($_->[Y]) ], @points);
|
||||||
|
}
|
||||||
|
|
||||||
sub wkt {
|
sub wkt {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
return sprintf "LINESTRING((%s))", join ',', map "$_->[0] $_->[1]", @$self;
|
return sprintf "LINESTRING((%s))", join ',', map "$_->[0] $_->[1]", @$self;
|
||||||
@ -39,9 +45,10 @@ sub grow {
|
|||||||
my ($distance, $scale, $joinType, $miterLimit) = @_;
|
my ($distance, $scale, $joinType, $miterLimit) = @_;
|
||||||
$joinType //= JT_SQUARE;
|
$joinType //= JT_SQUARE;
|
||||||
|
|
||||||
|
my @points = @$self;
|
||||||
return map Slic3r::Polygon->new(@$_),
|
return map Slic3r::Polygon->new(@$_),
|
||||||
Slic3r::Geometry::Clipper::offset(
|
Slic3r::Geometry::Clipper::offset(
|
||||||
[ [ @$self, CORE::reverse @$self[1..($#$self-1)] ] ],
|
[ Slic3r::Polygon->new(@points, CORE::reverse @points[1..($#points-1)]) ],
|
||||||
$distance, $scale, $joinType, $miterLimit,
|
$distance, $scale, $joinType, $miterLimit,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -72,7 +79,7 @@ sub clip_with_expolygon {
|
|||||||
my ($expolygon) = @_;
|
my ($expolygon) = @_;
|
||||||
|
|
||||||
my $result = Boost::Geometry::Utils::polygon_multi_linestring_intersection($expolygon->pp, [$self->pp]);
|
my $result = Boost::Geometry::Utils::polygon_multi_linestring_intersection($expolygon->pp, [$self->pp]);
|
||||||
return @$result;
|
return map { (ref $self)->new(@$_) } @$result;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub bounding_box {
|
sub bounding_box {
|
||||||
@ -108,7 +115,7 @@ sub clip_end {
|
|||||||
}
|
}
|
||||||
|
|
||||||
my $new_point = Slic3r::Geometry::point_along_segment($last_point, $self->[-1], $distance);
|
my $new_point = Slic3r::Geometry::point_along_segment($last_point, $self->[-1], $distance);
|
||||||
$self->append(Slic3r::Point->new($new_point));
|
$self->append($new_point);
|
||||||
$distance = 0;
|
$distance = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -142,22 +149,18 @@ use Moo;
|
|||||||
|
|
||||||
has 'polylines' => (is => 'ro', default => sub { [] });
|
has 'polylines' => (is => 'ro', default => sub { [] });
|
||||||
|
|
||||||
# If the second argument is provided, this method will return its items sorted
|
|
||||||
# instead of returning the actual sorted polylines.
|
|
||||||
# Note that our polylines will be reversed in place when necessary.
|
# Note that our polylines will be reversed in place when necessary.
|
||||||
sub chained_path {
|
sub chained_path {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my ($start_near, $items, $no_reverse) = @_;
|
my ($start_near, $no_reverse) = @_;
|
||||||
|
|
||||||
$items ||= $self->polylines;
|
|
||||||
my %items_map = map { $self->polylines->[$_] => $items->[$_] } 0 .. $#{$self->polylines};
|
|
||||||
my @my_paths = @{$self->polylines};
|
my @my_paths = @{$self->polylines};
|
||||||
|
|
||||||
my @paths = ();
|
my @paths = ();
|
||||||
my $start_at;
|
my $start_at;
|
||||||
my $endpoints = $no_reverse
|
my $endpoints = $no_reverse
|
||||||
? [ map { $_->[0], $_->[0] } @my_paths ]
|
? [ map { @$_[0,0] } @my_paths ]
|
||||||
: [ map { $_->[0], $_->[-1] } @my_paths ];
|
: [ map { @$_[0,-1] } @my_paths ];
|
||||||
while (@my_paths) {
|
while (@my_paths) {
|
||||||
# find nearest point
|
# find nearest point
|
||||||
my $start_index = defined $start_near
|
my $start_index = defined $start_near
|
||||||
@ -172,7 +175,7 @@ sub chained_path {
|
|||||||
splice @$endpoints, $path_index*2, 2;
|
splice @$endpoints, $path_index*2, 2;
|
||||||
$start_near = $paths[-1][-1];
|
$start_near = $paths[-1][-1];
|
||||||
}
|
}
|
||||||
return map $items_map{"$_"}, @paths;
|
return @paths;
|
||||||
}
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
@ -833,7 +833,7 @@ sub write_gcode {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
# order objects using a nearest neighbor search
|
# order objects using a nearest neighbor search
|
||||||
my @obj_idx = chained_path([ map $_->copies->[0], @{$self->objects} ]);
|
my @obj_idx = chained_path([ map Slic3r::Point->new(@{$_->copies->[0]}), @{$self->objects} ]);
|
||||||
|
|
||||||
# sort layers by Z
|
# sort layers by Z
|
||||||
my %layers = (); # print_z => [ layer, layer, layer ] by obj_idx
|
my %layers = (); # print_z => [ layer, layer, layer ] by obj_idx
|
||||||
|
25
t/geometry.t
25
t/geometry.t
@ -29,37 +29,38 @@ isnt Slic3r::Geometry::line_intersection($line1, $line2, 1), undef, 'line_inters
|
|||||||
#==========================================================
|
#==========================================================
|
||||||
|
|
||||||
{
|
{
|
||||||
my $polyline = [
|
my $polygon = Slic3r::Polygon->new(
|
||||||
[459190000, 5152739000], [147261000, 4612464000], [147261000, 3487535000], [339887000, 3153898000],
|
[459190000, 5152739000], [147261000, 4612464000], [147261000, 3487535000], [339887000, 3153898000],
|
||||||
[437497000, 3438430000], [454223000, 3522515000], [523621000, 3626378000], [627484000, 3695776000],
|
[437497000, 3438430000], [454223000, 3522515000], [523621000, 3626378000], [627484000, 3695776000],
|
||||||
[750000000, 3720147000], [872515000, 3695776000], [976378000, 3626378000], [1045776000, 3522515000],
|
[750000000, 3720147000], [872515000, 3695776000], [976378000, 3626378000], [1045776000, 3522515000],
|
||||||
[1070147000, 3400000000], [1045776000, 3277484000], [976378000, 3173621000], [872515000, 3104223000],
|
[1070147000, 3400000000], [1045776000, 3277484000], [976378000, 3173621000], [872515000, 3104223000],
|
||||||
[827892000, 3095347000], [698461000, 2947261000], [2540810000, 2947261000], [2852739000, 3487535000],
|
[827892000, 3095347000], [698461000, 2947261000], [2540810000, 2947261000], [2852739000, 3487535000],
|
||||||
[2852739000, 4612464000], [2540810000, 5152739000],
|
[2852739000, 4612464000], [2540810000, 5152739000],
|
||||||
];
|
);
|
||||||
|
|
||||||
# this points belongs to $polyline
|
# this points belongs to $polyline
|
||||||
my $point = [2797980957.103410,3392691792.513960];
|
# note: it's actually a vertex, while we should better check an intermediate point
|
||||||
|
my $point = Slic3r::Point->new(1045776000, 3277484000);
|
||||||
|
|
||||||
local $Slic3r::Geometry::epsilon = 1E-5;
|
local $Slic3r::Geometry::epsilon = 1E-5;
|
||||||
is_deeply Slic3r::Geometry::polygon_segment_having_point($polyline, $point),
|
is_deeply Slic3r::Geometry::polygon_segment_having_point($polygon, $point)->pp,
|
||||||
[ [2540810000, 2947261000], [2852739000, 3487535000] ],
|
[ [1070147000, 3400000000], [1045776000, 3277484000] ],
|
||||||
'polygon_segment_having_point';
|
'polygon_segment_having_point';
|
||||||
}
|
}
|
||||||
|
|
||||||
#==========================================================
|
#==========================================================
|
||||||
|
|
||||||
{
|
{
|
||||||
my $point = [ 736310778.185108, 5017423926.8924 ];
|
my $point = Slic3r::Point->new(736310778.185108, 5017423926.8924);
|
||||||
my $line = [ [627484000, 3695776000], [750000000, 3720147000] ];
|
my $line = Slic3r::Line->new([627484000, 3695776000], [750000000, 3720147000]);
|
||||||
is Slic3r::Geometry::point_in_segment($point, $line), 0, 'point_in_segment';
|
is Slic3r::Geometry::point_in_segment($point, $line), 0, 'point_in_segment';
|
||||||
}
|
}
|
||||||
|
|
||||||
#==========================================================
|
#==========================================================
|
||||||
|
|
||||||
{
|
{
|
||||||
my $point = [ 736310778.185108, 5017423926.8924 ];
|
my $point = Slic3r::Point->new(736310778.185108, 5017423926.8924);
|
||||||
my $line = [ [627484000, 3695776000], [750000000, 3720147000] ];
|
my $line = Slic3r::Line->new([627484000, 3695776000], [750000000, 3720147000]);
|
||||||
is Slic3r::Geometry::point_in_segment($point, $line), 0, 'point_in_segment';
|
is Slic3r::Geometry::point_in_segment($point, $line), 0, 'point_in_segment';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -158,7 +159,7 @@ is Slic3r::Geometry::can_connect_points(@$points, $polygons), 0, 'can_connect_po
|
|||||||
|
|
||||||
{
|
{
|
||||||
my $polyline = Slic3r::Polyline->new([0, 0], [10, 0], [20, 0]);
|
my $polyline = Slic3r::Polyline->new([0, 0], [10, 0], [20, 0]);
|
||||||
is_deeply [ map $_->pp, $polyline->lines ], [
|
is_deeply [ map $_->pp, @{$polyline->lines} ], [
|
||||||
[ [0, 0], [10, 0] ],
|
[ [0, 0], [10, 0] ],
|
||||||
[ [10, 0], [20, 0] ],
|
[ [10, 0], [20, 0] ],
|
||||||
], 'polyline_lines';
|
], 'polyline_lines';
|
||||||
@ -167,8 +168,8 @@ is Slic3r::Geometry::can_connect_points(@$points, $polygons), 0, 'can_connect_po
|
|||||||
#==========================================================
|
#==========================================================
|
||||||
|
|
||||||
{
|
{
|
||||||
my $polyline = Slic3r::Polygon->new([0, 0], [10, 0], [5, 5]);
|
my $polygon = Slic3r::Polygon->new([0, 0], [10, 0], [5, 5]);
|
||||||
my $result = $polyline->split_at_index(1);
|
my $result = $polygon->split_at_index(1);
|
||||||
is ref($result), 'Slic3r::Polyline', 'split_at_index returns polyline';
|
is ref($result), 'Slic3r::Polyline', 'split_at_index returns polyline';
|
||||||
is_deeply $result->pp, [ [10, 0], [5, 5], [0, 0], [10, 0] ], 'split_at_index';
|
is_deeply $result->pp, [ [10, 0], [5, 5], [0, 0], [10, 0] ], 'split_at_index';
|
||||||
}
|
}
|
||||||
|
@ -57,10 +57,10 @@ use Slic3r::Test;
|
|||||||
if ($cur_loop) {
|
if ($cur_loop) {
|
||||||
$has_cw_loops = 1 if !Slic3r::Geometry::Clipper::is_counter_clockwise($cur_loop);
|
$has_cw_loops = 1 if !Slic3r::Geometry::Clipper::is_counter_clockwise($cur_loop);
|
||||||
if ($self->F == $config->external_perimeter_speed*60) {
|
if ($self->F == $config->external_perimeter_speed*60) {
|
||||||
my $move_dest = [ @$info{qw(new_X new_Y)} ];
|
my $move_dest = Slic3r::Point->new_scale(@$info{qw(new_X new_Y)});
|
||||||
$external_loops{$self->Z}++;
|
$external_loops{$self->Z}++;
|
||||||
$has_outwards_move = 1
|
$has_outwards_move = 1
|
||||||
if !Slic3r::Polygon->new(@$cur_loop)->encloses_point($move_dest)
|
if !Slic3r::Polygon->new_scale(@$cur_loop)->encloses_point($move_dest)
|
||||||
? ($external_loops{$self->Z} == 2) # contour should include destination
|
? ($external_loops{$self->Z} == 2) # contour should include destination
|
||||||
: ($external_loops{$self->Z} == 1); # hole should not
|
: ($external_loops{$self->Z} == 1); # hole should not
|
||||||
}
|
}
|
||||||
|
42
t/polyclip.t
42
t/polyclip.t
@ -14,21 +14,21 @@ use Slic3r;
|
|||||||
|
|
||||||
#==========================================================
|
#==========================================================
|
||||||
|
|
||||||
is Slic3r::Geometry::point_in_segment([10, 10], [ [5, 10], [20, 10] ]), 1, 'point in horizontal segment';
|
is Slic3r::Geometry::point_in_segment(Slic3r::Point->new(10, 10), Slic3r::Line->new([5, 10], [20, 10])), 1, 'point in horizontal segment';
|
||||||
is Slic3r::Geometry::point_in_segment([30, 10], [ [5, 10], [20, 10] ]), 0, 'point not in horizontal segment';
|
is Slic3r::Geometry::point_in_segment(Slic3r::Point->new(30, 10), Slic3r::Line->new([5, 10], [20, 10])), 0, 'point not in horizontal segment';
|
||||||
is Slic3r::Geometry::point_in_segment([10, 10], [ [10, 5], [10, 20] ]), 1, 'point in vertical segment';
|
is Slic3r::Geometry::point_in_segment(Slic3r::Point->new(10, 10), Slic3r::Line->new([10, 5], [10, 20])), 1, 'point in vertical segment';
|
||||||
is Slic3r::Geometry::point_in_segment([10, 30], [ [10, 5], [10, 20] ]), 0, 'point not in vertical segment';
|
is Slic3r::Geometry::point_in_segment(Slic3r::Point->new(10, 30), Slic3r::Line->new([10, 5], [10, 20])), 0, 'point not in vertical segment';
|
||||||
is Slic3r::Geometry::point_in_segment([15, 15], [ [10, 10], [20, 20] ]), 1, 'point in diagonal segment';
|
is Slic3r::Geometry::point_in_segment(Slic3r::Point->new(15, 15), Slic3r::Line->new([10, 10], [20, 20])), 1, 'point in diagonal segment';
|
||||||
is Slic3r::Geometry::point_in_segment([20, 15], [ [10, 10], [20, 20] ]), 0, 'point not in diagonal segment';
|
is Slic3r::Geometry::point_in_segment(Slic3r::Point->new(20, 15), Slic3r::Line->new([10, 10], [20, 20])), 0, 'point not in diagonal segment';
|
||||||
|
|
||||||
#==========================================================
|
#==========================================================
|
||||||
|
|
||||||
my $square = [ # ccw
|
my $square = Slic3r::Polygon->new( # ccw
|
||||||
[100, 100],
|
[100, 100],
|
||||||
[200, 100],
|
[200, 100],
|
||||||
[200, 200],
|
[200, 200],
|
||||||
[100, 200],
|
[100, 200],
|
||||||
];
|
);
|
||||||
|
|
||||||
my $line = Slic3r::Line->new([50, 150], [300, 150]);
|
my $line = Slic3r::Line->new([50, 150], [300, 150]);
|
||||||
|
|
||||||
@ -37,17 +37,17 @@ is_deeply $intersection, [ [100, 150], [200, 150] ], 'line is clipped to square'
|
|||||||
|
|
||||||
#==========================================================
|
#==========================================================
|
||||||
|
|
||||||
$intersection = Slic3r::Geometry::clip_segment_polygon([ [0, 150], [80, 150] ], $square);
|
$intersection = Slic3r::Geometry::clip_segment_polygon(Slic3r::Line->new([0, 150], [80, 150]), $square);
|
||||||
is $intersection, undef, 'external lines are ignored 1';
|
is $intersection, undef, 'external lines are ignored 1';
|
||||||
|
|
||||||
#==========================================================
|
#==========================================================
|
||||||
|
|
||||||
$intersection = Slic3r::Geometry::clip_segment_polygon([ [300, 150], [400, 150] ], $square);
|
$intersection = Slic3r::Geometry::clip_segment_polygon(Slic3r::Line->new([300, 150], [400, 150]), $square);
|
||||||
is $intersection, undef, 'external lines are ignored 2';
|
is $intersection, undef, 'external lines are ignored 2';
|
||||||
|
|
||||||
#==========================================================
|
#==========================================================
|
||||||
|
|
||||||
$intersection = Slic3r::Geometry::clip_segment_polygon([ [120, 120], [180, 160] ], $square);
|
$intersection = Slic3r::Geometry::clip_segment_polygon(Slic3r::Line->new([120, 120], [180, 160]), $square);
|
||||||
is_deeply $intersection, [ [120, 120], [180, 160] ], 'internal lines are preserved';
|
is_deeply $intersection, [ [120, 120], [180, 160] ], 'internal lines are preserved';
|
||||||
|
|
||||||
#==========================================================
|
#==========================================================
|
||||||
@ -66,45 +66,45 @@ is_deeply $intersection, [ [120, 120], [180, 160] ], 'internal lines are preserv
|
|||||||
is $expolygon->encloses_point(Slic3r::Point->new(140, 140)), 1, 'point on hole corner is recognized';
|
is $expolygon->encloses_point(Slic3r::Point->new(140, 140)), 1, 'point on hole corner is recognized';
|
||||||
{
|
{
|
||||||
my $intersections = $expolygon->clip_line(Slic3r::Line->new([150,180], [150,150]));
|
my $intersections = $expolygon->clip_line(Slic3r::Line->new([150,180], [150,150]));
|
||||||
is_deeply $intersections, [
|
is_deeply [ map $_->pp, @$intersections ], [
|
||||||
[ [150, 180], [150, 160] ],
|
[ [150, 180], [150, 160] ],
|
||||||
], 'line is clipped to square with hole';
|
], 'line is clipped to square with hole';
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
my $intersections = $expolygon->clip_line(Slic3r::Line->new([150,150], [150,120]));
|
my $intersections = $expolygon->clip_line(Slic3r::Line->new([150,150], [150,120]));
|
||||||
is_deeply $intersections, [
|
is_deeply [ map $_->pp, @$intersections ], [
|
||||||
[ [150, 140], [150, 120] ],
|
[ [150, 140], [150, 120] ],
|
||||||
], 'line is clipped to square with hole';
|
], 'line is clipped to square with hole';
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
my $intersections = $expolygon->clip_line(Slic3r::Line->new([120,180], [180,180]));
|
my $intersections = $expolygon->clip_line(Slic3r::Line->new([120,180], [180,180]));
|
||||||
is_deeply $intersections, [
|
is_deeply [ map $_->pp, @$intersections ], [
|
||||||
[ [120,180], [180,180] ],
|
[ [120,180], [180,180] ],
|
||||||
], 'line is clipped to square with hole';
|
], 'line is clipped to square with hole';
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
my $intersections = $expolygon->clip_line($line);
|
my $intersections = $expolygon->clip_line($line);
|
||||||
is_deeply $intersections, [
|
is_deeply [ map $_->pp, @$intersections ], [
|
||||||
[ [100, 150], [140, 150] ],
|
[ [100, 150], [140, 150] ],
|
||||||
[ [160, 150], [200, 150] ],
|
[ [160, 150], [200, 150] ],
|
||||||
], 'line is clipped to square with hole';
|
], 'line is clipped to square with hole';
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
my $intersections = $expolygon->clip_line(Slic3r::Line->new(reverse @$line));
|
my $intersections = $expolygon->clip_line(Slic3r::Line->new(reverse @$line));
|
||||||
is_deeply $intersections, [
|
is_deeply [ map $_->pp, @$intersections ], [
|
||||||
[ [200, 150], [160, 150] ],
|
[ [200, 150], [160, 150] ],
|
||||||
[ [140, 150], [100, 150] ],
|
[ [140, 150], [100, 150] ],
|
||||||
], 'reverse line is clipped to square with hole';
|
], 'reverse line is clipped to square with hole';
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
my $intersections = $expolygon->clip_line(Slic3r::Line->new([100,180], [200,180]));
|
my $intersections = $expolygon->clip_line(Slic3r::Line->new([100,180], [200,180]));
|
||||||
is_deeply $intersections, [
|
is_deeply [ map $_->pp, @$intersections ], [
|
||||||
[ [100, 180], [200, 180] ],
|
[ [100, 180], [200, 180] ],
|
||||||
], 'tangent line is clipped to square with hole';
|
], 'tangent line is clipped to square with hole';
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
my $polyline = Slic3r::Polyline->new([50, 180], [250, 180], [250, 150], [150, 150], [150, 120], [120, 120], [120, 50]);
|
my $polyline = Slic3r::Polyline->new([50, 180], [250, 180], [250, 150], [150, 150], [150, 120], [120, 120], [120, 50]);
|
||||||
is_deeply [ map $_, $polyline->clip_with_expolygon($expolygon) ], [
|
is_deeply [ map $_->pp, $polyline->clip_with_expolygon($expolygon) ], [
|
||||||
[ [100, 180], [200, 180] ],
|
[ [100, 180], [200, 180] ],
|
||||||
[ [200, 150], [160, 150] ],
|
[ [200, 150], [160, 150] ],
|
||||||
[ [150, 140], [150, 120], [120, 120], [120, 100] ],
|
[ [150, 140], [150, 120], [120, 120], [120, 100] ],
|
||||||
@ -143,9 +143,9 @@ is_deeply $intersection, [ [120, 120], [180, 160] ], 'internal lines are preserv
|
|||||||
$line = Slic3r::Line->new([152.742,288.086671142818], [152.742,34.166466971035]);
|
$line = Slic3r::Line->new([152.742,288.086671142818], [152.742,34.166466971035]);
|
||||||
|
|
||||||
my $intersections = $expolygon->clip_line($line);
|
my $intersections = $expolygon->clip_line($line);
|
||||||
is_deeply $intersections, [
|
is_deeply [ map $_->pp, @$intersections ], [
|
||||||
[ [152.742, 287.908315789474], [152.742, 214.522], ],
|
[ [152, 287], [152, 214], ],
|
||||||
[ [152.742, 107.478], [152.742, 35] ],
|
[ [152, 107], [152, 35] ],
|
||||||
], 'line is clipped to square with hole';
|
], 'line is clipped to square with hole';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,26 +7,36 @@ our $VERSION = '0.01';
|
|||||||
use XSLoader;
|
use XSLoader;
|
||||||
XSLoader::load(__PACKAGE__, $VERSION);
|
XSLoader::load(__PACKAGE__, $VERSION);
|
||||||
|
|
||||||
package Slic3r::Point;
|
package Slic3r::Line;
|
||||||
use overload
|
|
||||||
'@{}' => sub { $_[0]->arrayref };
|
|
||||||
|
|
||||||
package Slic3r::ExPolygon;
|
|
||||||
use overload
|
|
||||||
'@{}' => sub { $_[0]->arrayref };
|
|
||||||
|
|
||||||
package Slic3r::Polyline;
|
|
||||||
use overload
|
use overload
|
||||||
'@{}' => sub { $_[0]->arrayref },
|
'@{}' => sub { $_[0]->arrayref },
|
||||||
'fallback' => 1;
|
'fallback' => 1;
|
||||||
|
|
||||||
|
package Slic3r::Point;
|
||||||
|
use overload
|
||||||
|
'@{}' => sub { $_[0]->arrayref },
|
||||||
|
'fallback' => 1;
|
||||||
|
|
||||||
|
package Slic3r::ExPolygon;
|
||||||
|
use overload
|
||||||
|
'@{}' => sub { $_[0]->arrayref },
|
||||||
|
'fallback' => 1;
|
||||||
|
|
||||||
|
package Slic3r::Polyline;
|
||||||
|
use overload
|
||||||
|
'@{}' => sub { $_[0]->arrayref },
|
||||||
|
'fallback' => 1,
|
||||||
|
'fallback' => 1;
|
||||||
|
|
||||||
package Slic3r::Polygon;
|
package Slic3r::Polygon;
|
||||||
use overload
|
use overload
|
||||||
'@{}' => sub { $_[0]->arrayref };
|
'@{}' => sub { $_[0]->arrayref },
|
||||||
|
'fallback' => 1;
|
||||||
|
|
||||||
package Slic3r::ExPolygon::Collection;
|
package Slic3r::ExPolygon::Collection;
|
||||||
use overload
|
use overload
|
||||||
'@{}' => sub { $_[0]->arrayref };
|
'@{}' => sub { $_[0]->arrayref },
|
||||||
|
'fallback' => 1;
|
||||||
|
|
||||||
package Slic3r::ExtrusionLoop;
|
package Slic3r::ExtrusionLoop;
|
||||||
use overload
|
use overload
|
||||||
@ -116,6 +126,7 @@ sub clone {
|
|||||||
|
|
||||||
package Slic3r::Surface::Collection;
|
package Slic3r::Surface::Collection;
|
||||||
use overload
|
use overload
|
||||||
'@{}' => sub { $_[0]->arrayref };
|
'@{}' => sub { $_[0]->arrayref },
|
||||||
|
'fallback' => 1;
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
@ -72,8 +72,8 @@ void
|
|||||||
Point::from_SV(SV* point_sv)
|
Point::from_SV(SV* point_sv)
|
||||||
{
|
{
|
||||||
AV* point_av = (AV*)SvRV(point_sv);
|
AV* point_av = (AV*)SvRV(point_sv);
|
||||||
this->x = (unsigned long)SvIV(*av_fetch(point_av, 0, 0));
|
this->x = (long)SvIV(*av_fetch(point_av, 0, 0));
|
||||||
this->y = (unsigned long)SvIV(*av_fetch(point_av, 1, 0));
|
this->y = (long)SvIV(*av_fetch(point_av, 1, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -40,7 +40,7 @@ Polygon::split_at_index(int index)
|
|||||||
for (int i = index; i < this->points.size(); i++) {
|
for (int i = index; i < this->points.size(); i++) {
|
||||||
poly->points.push_back( this->points[i] );
|
poly->points.push_back( this->points[i] );
|
||||||
}
|
}
|
||||||
for (int i = 0; i < index; i++) {
|
for (int i = 0; i <= index; i++) {
|
||||||
poly->points.push_back( this->points[i] );
|
poly->points.push_back( this->points[i] );
|
||||||
}
|
}
|
||||||
return poly;
|
return poly;
|
||||||
|
@ -4,7 +4,7 @@ use strict;
|
|||||||
use warnings;
|
use warnings;
|
||||||
|
|
||||||
use Slic3r::XS;
|
use Slic3r::XS;
|
||||||
use Test::More tests => 5;
|
use Test::More tests => 7;
|
||||||
|
|
||||||
my $point = Slic3r::Point->new(10, 15);
|
my $point = Slic3r::Point->new(10, 15);
|
||||||
is_deeply [ @$point ], [10, 15], 'point roundtrip';
|
is_deeply [ @$point ], [10, 15], 'point roundtrip';
|
||||||
@ -19,4 +19,10 @@ is_deeply [ @$point2 ], [30, 15], 'translate';
|
|||||||
ok $point->coincides_with($point->clone), 'coincides_with';
|
ok $point->coincides_with($point->clone), 'coincides_with';
|
||||||
ok !$point->coincides_with($point2), 'coincides_with';
|
ok !$point->coincides_with($point2), 'coincides_with';
|
||||||
|
|
||||||
|
{
|
||||||
|
my $point3 = Slic3r::Point->new(4300000, -9880845);
|
||||||
|
is $point->[0], $point->x, 'x accessor';
|
||||||
|
is $point->[1], $point->y, 'y accessor';
|
||||||
|
}
|
||||||
|
|
||||||
__END__
|
__END__
|
||||||
|
@ -27,7 +27,7 @@ is_deeply [ map $_->pp, @$lines ], [
|
|||||||
[ [100, 200], [100, 100] ],
|
[ [100, 200], [100, 100] ],
|
||||||
], 'polygon lines';
|
], 'polygon lines';
|
||||||
|
|
||||||
is_deeply $polygon->split_at_first_point->pp, $square, 'split_at_first_point';
|
is_deeply $polygon->split_at_first_point->pp, [ @$square[0,1,2,3,0] ], 'split_at_first_point';
|
||||||
is_deeply $polygon->split_at_index(2)->pp, [ @$square[2,3,0,1] ], 'split_at_index';
|
is_deeply $polygon->split_at_index(2)->pp, [ @$square[2,3,0,1,2] ], 'split_at_index';
|
||||||
|
|
||||||
__END__
|
__END__
|
||||||
|
@ -28,10 +28,10 @@ is $loop->role, Slic3r::ExtrusionPath::EXTR_ROLE_FILL, 'modify role';
|
|||||||
|
|
||||||
{
|
{
|
||||||
my $path = $loop->split_at_first_point;
|
my $path = $loop->split_at_first_point;
|
||||||
is_deeply $path->polyline->pp, $square, 'split_at_first_point';
|
is_deeply $path->polyline->pp, [ @$square[0,1,2,3,0] ], 'split_at_first_point';
|
||||||
is $path->role, $loop->role, 'role preserved after split';
|
is $path->role, $loop->role, 'role preserved after split';
|
||||||
|
|
||||||
is_deeply $loop->split_at_index(2)->polyline->pp, [ @$square[2,3,0,1] ], 'split_at_index';
|
is_deeply $loop->split_at_index(2)->polyline->pp, [ @$square[2,3,0,1,2] ], 'split_at_index';
|
||||||
}
|
}
|
||||||
|
|
||||||
__END__
|
__END__
|
||||||
|
40
xs/t/10_line.t
Normal file
40
xs/t/10_line.t
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#!/usr/bin/perl
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use Slic3r::XS;
|
||||||
|
use Test::More tests => 6;
|
||||||
|
|
||||||
|
my $points = [
|
||||||
|
[100, 100],
|
||||||
|
[200, 100],
|
||||||
|
];
|
||||||
|
|
||||||
|
my $line = Slic3r::Line->new(@$points);
|
||||||
|
is_deeply $line->pp, $points, 'line roundtrip';
|
||||||
|
|
||||||
|
is ref($line->arrayref), 'ARRAY', 'line arrayref is unblessed';
|
||||||
|
isa_ok $line->[0], 'Slic3r::Point', 'line point is blessed';
|
||||||
|
|
||||||
|
{
|
||||||
|
my $clone = $line->clone;
|
||||||
|
$clone->reverse;
|
||||||
|
is_deeply $clone->pp, [ reverse @$points ], 'reverse';
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
my $line2 = Slic3r::Line->new($line->a->clone, $line->b->clone);
|
||||||
|
is_deeply $line2->pp, $points, 'line roundtrip with cloned points';
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
my $clone = $line->clone;
|
||||||
|
$clone->translate(10, -5);
|
||||||
|
is_deeply $clone->pp, [
|
||||||
|
[110, 95],
|
||||||
|
[210, 95],
|
||||||
|
], 'translate';
|
||||||
|
}
|
||||||
|
|
||||||
|
__END__
|
@ -11,6 +11,8 @@
|
|||||||
%code{% RETVAL = THIS->polygon.to_SV(); %};
|
%code{% RETVAL = THIS->polygon.to_SV(); %};
|
||||||
SV* pp()
|
SV* pp()
|
||||||
%code{% RETVAL = THIS->polygon.to_SV_pureperl(); %};
|
%code{% RETVAL = THIS->polygon.to_SV_pureperl(); %};
|
||||||
|
void reverse()
|
||||||
|
%code{% THIS->polygon.reverse(); %};
|
||||||
ExtrusionPath* split_at_index(int index)
|
ExtrusionPath* split_at_index(int index)
|
||||||
%code{% const char* CLASS = "Slic3r::ExtrusionPath"; RETVAL = THIS->split_at_index(index); %};
|
%code{% const char* CLASS = "Slic3r::ExtrusionPath"; RETVAL = THIS->split_at_index(index); %};
|
||||||
ExtrusionPath* split_at_first_point()
|
ExtrusionPath* split_at_first_point()
|
||||||
|
@ -14,6 +14,8 @@
|
|||||||
void pop_back()
|
void pop_back()
|
||||||
%code{% THIS->polyline.points.pop_back(); %};
|
%code{% THIS->polyline.points.pop_back(); %};
|
||||||
void reverse();
|
void reverse();
|
||||||
|
Lines lines()
|
||||||
|
%code{% RETVAL = THIS->polyline.lines(); %};
|
||||||
%{
|
%{
|
||||||
|
|
||||||
ExtrusionPath*
|
ExtrusionPath*
|
||||||
|
@ -18,6 +18,8 @@
|
|||||||
Point* b()
|
Point* b()
|
||||||
%code{% const char* CLASS = "Slic3r::Point"; RETVAL = new Point(THIS->b); %};
|
%code{% const char* CLASS = "Slic3r::Point"; RETVAL = new Point(THIS->b); %};
|
||||||
void reverse();
|
void reverse();
|
||||||
|
void scale(double factor);
|
||||||
|
void translate(double x, double y);
|
||||||
%{
|
%{
|
||||||
|
|
||||||
Line*
|
Line*
|
||||||
@ -29,6 +31,16 @@ Line::new(...)
|
|||||||
RETVAL->b.from_SV_check( ST(2) );
|
RETVAL->b.from_SV_check( ST(2) );
|
||||||
OUTPUT:
|
OUTPUT:
|
||||||
RETVAL
|
RETVAL
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Line::rotate(angle, center_sv)
|
||||||
|
double angle;
|
||||||
|
SV* center_sv;
|
||||||
|
CODE:
|
||||||
|
Point center;
|
||||||
|
center.from_SV_check(center_sv);
|
||||||
|
THIS->rotate(angle, ¢er);
|
||||||
|
|
||||||
%}
|
%}
|
||||||
};
|
};
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
%}
|
%}
|
||||||
|
|
||||||
%name{Slic3r::Point} class Point {
|
%name{Slic3r::Point} class Point {
|
||||||
Point(unsigned long _x = 0, unsigned long _y = 0);
|
Point(long _x = 0, long _y = 0);
|
||||||
~Point();
|
~Point();
|
||||||
Point* clone()
|
Point* clone()
|
||||||
%code{% const char* CLASS = "Slic3r::Point"; RETVAL = new Point(*THIS); %};
|
%code{% const char* CLASS = "Slic3r::Point"; RETVAL = new Point(*THIS); %};
|
||||||
@ -14,9 +14,11 @@
|
|||||||
void translate(double x, double y);
|
void translate(double x, double y);
|
||||||
SV* arrayref()
|
SV* arrayref()
|
||||||
%code{% RETVAL = THIS->to_SV_pureperl(); %};
|
%code{% RETVAL = THIS->to_SV_pureperl(); %};
|
||||||
unsigned long x()
|
SV* pp()
|
||||||
|
%code{% RETVAL = THIS->to_SV_pureperl(); %};
|
||||||
|
long x()
|
||||||
%code{% RETVAL = THIS->x; %};
|
%code{% RETVAL = THIS->x; %};
|
||||||
unsigned long y()
|
long y()
|
||||||
%code{% RETVAL = THIS->y; %};
|
%code{% RETVAL = THIS->y; %};
|
||||||
|
|
||||||
%{
|
%{
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
%code{% RETVAL = THIS->to_SV_pureperl(); %};
|
%code{% RETVAL = THIS->to_SV_pureperl(); %};
|
||||||
void scale(double factor);
|
void scale(double factor);
|
||||||
void translate(double x, double y);
|
void translate(double x, double y);
|
||||||
|
void reverse();
|
||||||
Lines lines();
|
Lines lines();
|
||||||
Polyline* split_at_index(int index)
|
Polyline* split_at_index(int index)
|
||||||
%code{% const char* CLASS = "Slic3r::Polyline"; RETVAL = THIS->split_at_index(index); %};
|
%code{% const char* CLASS = "Slic3r::Polyline"; RETVAL = THIS->split_at_index(index); %};
|
||||||
|
@ -38,7 +38,7 @@ Polyline::append(...)
|
|||||||
CODE:
|
CODE:
|
||||||
for (unsigned int i = 1; i < items; i++) {
|
for (unsigned int i = 1; i < items; i++) {
|
||||||
Point p;
|
Point p;
|
||||||
p.from_SV_check( ST(1) );
|
p.from_SV_check( ST(i) );
|
||||||
THIS->points.push_back(p);
|
THIS->points.push_back(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user