Clean medial axis code and gap fill
This commit is contained in:
parent
98ad345e42
commit
9a51964e98
@ -105,10 +105,8 @@ sub medial_axis {
|
|||||||
my $self = shift;
|
my $self = shift;
|
||||||
my ($width) = @_;
|
my ($width) = @_;
|
||||||
|
|
||||||
my @self_lines = map $_->lines, @$self;
|
|
||||||
my $expolygon = $self->clone;
|
|
||||||
my @points = ();
|
my @points = ();
|
||||||
foreach my $polygon (@$expolygon) {
|
foreach my $polygon (@$self) {
|
||||||
{
|
{
|
||||||
my $p = $polygon->pp;
|
my $p = $polygon->pp;
|
||||||
Slic3r::Geometry::polyline_remove_short_segments($p, $width / 2);
|
Slic3r::Geometry::polyline_remove_short_segments($p, $width / 2);
|
||||||
@ -117,9 +115,9 @@ sub medial_axis {
|
|||||||
|
|
||||||
# subdivide polygon segments so that we don't have anyone of them
|
# subdivide polygon segments so that we don't have anyone of them
|
||||||
# being longer than $width / 2
|
# being longer than $width / 2
|
||||||
$polygon->subdivide($width/2);
|
$polygon = $polygon->subdivide($width/2);
|
||||||
|
|
||||||
push @points, @$polygon;
|
push @points, map $_->clone, @$polygon;
|
||||||
}
|
}
|
||||||
|
|
||||||
my $voronoi = Math::Geometry::Voronoi->new(points => [ map $_->pp, @points ]);
|
my $voronoi = Math::Geometry::Voronoi->new(points => [ map $_->pp, @points ]);
|
||||||
@ -136,67 +134,34 @@ sub medial_axis {
|
|||||||
my ($a, $b);
|
my ($a, $b);
|
||||||
$a = Slic3r::Point->new(@{$vertices->[$edge->[1]]});
|
$a = Slic3r::Point->new(@{$vertices->[$edge->[1]]});
|
||||||
$b = Slic3r::Point->new(@{$vertices->[$edge->[2]]});
|
$b = Slic3r::Point->new(@{$vertices->[$edge->[2]]});
|
||||||
|
|
||||||
next if !$self->encloses_point_quick($a) || !$self->encloses_point_quick($b);
|
next if !$self->encloses_point_quick($a) || !$self->encloses_point_quick($b);
|
||||||
|
|
||||||
push @skeleton_lines, [$edge->[1], $edge->[2]];
|
push @skeleton_lines, [$edge->[1], $edge->[2]];
|
||||||
}
|
}
|
||||||
|
|
||||||
# remove leafs (lines not connected to other lines at one of their endpoints)
|
|
||||||
{
|
|
||||||
my %pointmap = ();
|
|
||||||
$pointmap{$_}++ for map @$_, @skeleton_lines;
|
|
||||||
@skeleton_lines = grep {
|
|
||||||
$pointmap{$_->[A]} >= 2 && $pointmap{$_->[B]} >= 2
|
|
||||||
} @skeleton_lines;
|
|
||||||
}
|
|
||||||
return () if !@skeleton_lines;
|
return () if !@skeleton_lines;
|
||||||
|
|
||||||
# now walk along the medial axis and build continuos polylines or polygons
|
# now walk along the medial axis and build continuos polylines or polygons
|
||||||
my @polylines = ();
|
my @polylines = ();
|
||||||
{
|
{
|
||||||
# build a map of line endpoints
|
my @lines = @skeleton_lines;
|
||||||
my %pointmap = (); # point_idx => [line_idx, line_idx ...]
|
push @polylines, [ map @$_, shift @lines ];
|
||||||
for my $line_idx (0 .. $#skeleton_lines) {
|
CYCLE: while (@lines) {
|
||||||
for my $point_idx (@{$skeleton_lines[$line_idx]}) {
|
for my $i (0..$#lines) {
|
||||||
$pointmap{$point_idx} ||= [];
|
if ($lines[$i][0] == $polylines[-1][-1]) {
|
||||||
push @{$pointmap{$point_idx}}, $line_idx;
|
push @{$polylines[-1]}, $lines[$i][1];
|
||||||
}
|
} elsif ($lines[$i][1] == $polylines[-1][-1]) {
|
||||||
}
|
push @{$polylines[-1]}, $lines[$i][0];
|
||||||
|
} elsif ($lines[$i][1] == $polylines[-1][0]) {
|
||||||
# build the list of available lines
|
unshift @{$polylines[-1]}, $lines[$i][0];
|
||||||
my %spare_lines = map {$_ => 1} (0 .. $#skeleton_lines);
|
} elsif ($lines[$i][0] == $polylines[-1][0]) {
|
||||||
|
unshift @{$polylines[-1]}, $lines[$i][1];
|
||||||
CYCLE: while (%spare_lines) {
|
} else {
|
||||||
push @polylines, [];
|
next;
|
||||||
my $polyline = $polylines[-1];
|
|
||||||
|
|
||||||
# start from a random line
|
|
||||||
my $first_line_idx = +(keys %spare_lines)[0];
|
|
||||||
delete $spare_lines{$first_line_idx};
|
|
||||||
push @$polyline, @{ $skeleton_lines[$first_line_idx] };
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
my $last_point_id = $polyline->[-1];
|
|
||||||
my $lines_starting_here = $pointmap{$last_point_id};
|
|
||||||
|
|
||||||
# remove all the visited lines from the array
|
|
||||||
shift @$lines_starting_here
|
|
||||||
while @$lines_starting_here && !$spare_lines{$lines_starting_here->[0]};
|
|
||||||
|
|
||||||
# do we have a line starting here?
|
|
||||||
my $next_line_idx = shift @$lines_starting_here;
|
|
||||||
if (!defined $next_line_idx) {
|
|
||||||
delete $pointmap{$last_point_id};
|
|
||||||
next CYCLE;
|
|
||||||
}
|
}
|
||||||
|
splice @lines, $i, 1;
|
||||||
# line is not available anymore
|
next CYCLE;
|
||||||
delete $spare_lines{$next_line_idx};
|
|
||||||
|
|
||||||
# add the other point to our polyline and continue walking
|
|
||||||
push @$polyline, grep $_ ne $last_point_id, @{$skeleton_lines[$next_line_idx]};
|
|
||||||
}
|
}
|
||||||
|
push @polylines, [ map @$_, shift @lines ];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -209,9 +174,8 @@ sub medial_axis {
|
|||||||
|
|
||||||
# cleanup
|
# cleanup
|
||||||
$polyline = Slic3r::Geometry::douglas_peucker($polyline, $width / 7);
|
$polyline = Slic3r::Geometry::douglas_peucker($polyline, $width / 7);
|
||||||
$polyline = Slic3r::Polyline->new(@$polyline);
|
|
||||||
|
|
||||||
if (Slic3r::Geometry::same_point($polyline->first_point, $polyline->last_point)) {
|
if (Slic3r::Geometry::same_point($polyline->[0], $polyline->[-1])) {
|
||||||
next if @$polyline == 2;
|
next if @$polyline == 2;
|
||||||
push @result, Slic3r::Polygon->new(@$polyline[0..$#$polyline-1]);
|
push @result, Slic3r::Polygon->new(@$polyline[0..$#$polyline-1]);
|
||||||
} else {
|
} else {
|
||||||
|
@ -28,10 +28,6 @@ has 'overhang_width' => (is => 'lazy');
|
|||||||
# divided by type top/bottom/internal
|
# divided by type top/bottom/internal
|
||||||
has 'slices' => (is => 'rw', default => sub { Slic3r::Surface::Collection->new });
|
has 'slices' => (is => 'rw', default => sub { Slic3r::Surface::Collection->new });
|
||||||
|
|
||||||
# collection of polygons or polylines representing thin walls contained
|
|
||||||
# in the original geometry
|
|
||||||
has 'thin_walls' => (is => 'rw', default => sub { Slic3r::ExtrusionPath::Collection->new });
|
|
||||||
|
|
||||||
# collection of extrusion paths/loops filling gaps
|
# collection of extrusion paths/loops filling gaps
|
||||||
has 'thin_fills' => (is => 'rw', default => sub { Slic3r::ExtrusionPath::Collection->new });
|
has 'thin_fills' => (is => 'rw', default => sub { Slic3r::ExtrusionPath::Collection->new });
|
||||||
|
|
||||||
@ -101,26 +97,6 @@ sub make_surfaces {
|
|||||||
expolygons => [ map $_->expolygon, @{$self->slices} ],
|
expolygons => [ map $_->expolygon, @{$self->slices} ],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
# detect thin walls by offsetting slices by half extrusion inwards
|
|
||||||
if ($self->config->thin_walls) {
|
|
||||||
$self->thin_walls([]);
|
|
||||||
# we use spacing here because there could be a case where
|
|
||||||
# the slice collapses with width but doesn't collapse with spacing,
|
|
||||||
# thus causing both perimeters and medial axis to be generated
|
|
||||||
my $width = $self->perimeter_flow->scaled_spacing;
|
|
||||||
my $diff = diff_ex(
|
|
||||||
[ map $_->p, @{$self->slices} ],
|
|
||||||
offset2([ map $_->p, @{$self->slices} ], -$width*0.5, +$width*0.5),
|
|
||||||
1,
|
|
||||||
);
|
|
||||||
|
|
||||||
my $area_threshold = $width ** 2;
|
|
||||||
if (@$diff = grep { $_->area > $area_threshold } @$diff) {
|
|
||||||
@{$self->thin_walls} = map $_->medial_axis($width), @$diff;
|
|
||||||
Slic3r::debugf " %d thin walls detected\n", scalar(@{$self->thin_walls});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sub _merge_loops {
|
sub _merge_loops {
|
||||||
@ -177,7 +153,7 @@ sub make_perimeters {
|
|||||||
|
|
||||||
my @contours = (); # array of Polygons with ccw orientation
|
my @contours = (); # array of Polygons with ccw orientation
|
||||||
my @holes = (); # array of Polygons with cw orientation
|
my @holes = (); # array of Polygons with cw orientation
|
||||||
my @gaps = (); # array of ExPolygons
|
my @gaps = (); # array of Polygons
|
||||||
|
|
||||||
# we need to process each island separately because we might have different
|
# we need to process each island separately because we might have different
|
||||||
# extra perimeters for each one
|
# extra perimeters for each one
|
||||||
@ -205,13 +181,13 @@ sub make_perimeters {
|
|||||||
# where offset2() collapses the expolygon, then there's no room for an inner loop
|
# where offset2() collapses the expolygon, then there's no room for an inner loop
|
||||||
# and we can extract the gap for later processing
|
# and we can extract the gap for later processing
|
||||||
if ($Slic3r::Config->gap_fill_speed > 0 && $self->object->config->fill_density > 0) {
|
if ($Slic3r::Config->gap_fill_speed > 0 && $self->object->config->fill_density > 0) {
|
||||||
my $diff = diff_ex(
|
my $diff = diff(
|
||||||
offset(\@last, -0.5*$spacing),
|
offset(\@last, -0.5*$spacing),
|
||||||
# +2 on the offset here makes sure that Clipper float truncation
|
# +2 on the offset here makes sure that Clipper float truncation
|
||||||
# won't shrink the clip polygon to be smaller than intended.
|
# 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, (@this_gaps = grep $_->area >= $gap_area_threshold, @$diff);
|
push @gaps, (@this_gaps = grep abs($_->area) >= $gap_area_threshold, @$diff);
|
||||||
}
|
}
|
||||||
|
|
||||||
last if !@offsets || $i == $loop_number;
|
last if !@offsets || $i == $loop_number;
|
||||||
@ -222,7 +198,7 @@ sub make_perimeters {
|
|||||||
|
|
||||||
# make sure we don't infill narrow parts that are already gap-filled
|
# make sure we don't infill narrow parts that are already gap-filled
|
||||||
# (we only consider this surface's gaps to reduce the diff() complexity)
|
# (we only consider this surface's gaps to reduce the diff() complexity)
|
||||||
@last = @{diff(\@last, [ map @$_, @this_gaps ])};
|
@last = @{diff(\@last, \@this_gaps)};
|
||||||
|
|
||||||
# create one more offset to be used as boundary for fill
|
# create one more offset to be used as boundary for fill
|
||||||
# we offset by half the perimeter spacing (to get to the actual infill boundary)
|
# we offset by half the perimeter spacing (to get to the actual infill boundary)
|
||||||
@ -237,8 +213,6 @@ sub make_perimeters {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
$self->_fill_gaps(\@gaps);
|
|
||||||
|
|
||||||
# find nesting hierarchies separately for contours and holes
|
# find nesting hierarchies separately for contours and holes
|
||||||
my $contours_pt = union_pt(\@contours);
|
my $contours_pt = union_pt(\@contours);
|
||||||
my $holes_pt = union_pt(\@holes);
|
my $holes_pt = union_pt(\@holes);
|
||||||
@ -302,14 +276,49 @@ sub make_perimeters {
|
|||||||
# append perimeters
|
# append perimeters
|
||||||
$self->perimeters->append(@loops);
|
$self->perimeters->append(@loops);
|
||||||
|
|
||||||
# add thin walls as perimeters
|
# detect thin walls by offsetting slices by half extrusion inwards
|
||||||
push @{ $self->perimeters }, @{Slic3r::ExtrusionPath::Collection->new(
|
# and add them as perimeters
|
||||||
map Slic3r::ExtrusionPath->new(
|
if ($self->config->thin_walls) {
|
||||||
polyline => ($_->isa('Slic3r::Polygon') ? $_->split_at_first_point : $_->clone),
|
# we use spacing here because there could be a case where
|
||||||
role => EXTR_ROLE_EXTERNAL_PERIMETER,
|
# the slice collapses with width but doesn't collapse with spacing,
|
||||||
flow_spacing => $self->perimeter_flow->spacing,
|
# thus causing both perimeters and medial axis to be generated
|
||||||
), @{ $self->thin_walls }
|
my $width = $self->perimeter_flow->scaled_spacing;
|
||||||
)->chained_path(0)};
|
my $diff = diff_ex(
|
||||||
|
[ map $_->p, @{$self->slices} ],
|
||||||
|
offset2([ map $_->p, @{$self->slices} ], -$width*0.5, +$width*0.5),
|
||||||
|
1,
|
||||||
|
);
|
||||||
|
|
||||||
|
my $area_threshold = $width ** 2;
|
||||||
|
if (@$diff = grep { $_->area > $area_threshold } @$diff) {
|
||||||
|
my @p = map $_->medial_axis($width), @$diff;
|
||||||
|
my @paths = ();
|
||||||
|
for my $p (@p) {
|
||||||
|
my %params = (
|
||||||
|
role => EXTR_ROLE_EXTERNAL_PERIMETER,
|
||||||
|
flow_spacing => $self->perimeter_flow->spacing,
|
||||||
|
);
|
||||||
|
push @paths, $p->isa('Slic3r::Polygon')
|
||||||
|
? Slic3r::ExtrusionLoop->new(polygon => $p, %params)
|
||||||
|
: Slic3r::ExtrusionPath->new(polyline => $p, %params);
|
||||||
|
}
|
||||||
|
|
||||||
|
$self->perimeters->append(
|
||||||
|
map $_->clone, @{Slic3r::ExtrusionPath::Collection->new(@paths)->chained_path(0)}
|
||||||
|
);
|
||||||
|
Slic3r::debugf " %d thin walls detected\n", scalar(@paths) if $Slic3r::debug;
|
||||||
|
|
||||||
|
# in the mean time we subtract thin walls from the detected gaps so that we don't
|
||||||
|
# reprocess them, causing overlapping thin walls and zigzag.
|
||||||
|
@gaps = @{diff(
|
||||||
|
\@gaps,
|
||||||
|
[ map $_->grow($self->perimeter_flow->scaled_width), @p ],
|
||||||
|
1,
|
||||||
|
)};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$self->_fill_gaps(\@gaps);
|
||||||
}
|
}
|
||||||
|
|
||||||
sub _fill_gaps {
|
sub _fill_gaps {
|
||||||
@ -318,19 +327,15 @@ sub _fill_gaps {
|
|||||||
|
|
||||||
return unless @$gaps;
|
return unless @$gaps;
|
||||||
|
|
||||||
|
# turn gaps into ExPolygons
|
||||||
|
$gaps = union_ex($gaps);
|
||||||
|
|
||||||
my $filler = $self->layer->object->fill_maker->filler('rectilinear');
|
my $filler = $self->layer->object->fill_maker->filler('rectilinear');
|
||||||
$filler->layer_id($self->layer->id);
|
$filler->layer_id($self->layer->id);
|
||||||
|
|
||||||
# we should probably use this code to handle thin walls and remove that logic from
|
# we should probably use this code to handle thin walls and remove that logic from
|
||||||
# make_surfaces(), but we need to enable dynamic extrusion width before as we can't
|
# make_surfaces(), but we need to enable dynamic extrusion width before as we can't
|
||||||
# use zigzag for thin walls.
|
# use zigzag for thin walls.
|
||||||
# in the mean time we subtract thin walls from the detected gaps so that we don't
|
|
||||||
# reprocess them, causing overlapping thin walls and zigzag.
|
|
||||||
@$gaps = @{diff_ex(
|
|
||||||
[ map @$_, @$gaps ],
|
|
||||||
[ map $_->grow($self->perimeter_flow->scaled_width), @{$self->{thin_walls}} ],
|
|
||||||
1,
|
|
||||||
)};
|
|
||||||
|
|
||||||
# medial axis-based gap fill should benefit from detection of larger gaps too, so
|
# medial axis-based gap fill should benefit from detection of larger gaps too, so
|
||||||
# we could try with 1.5*$w for example, but that doesn't work well for zigzag fill
|
# we could try with 1.5*$w for example, but that doesn't work well for zigzag fill
|
||||||
@ -375,29 +380,27 @@ sub _fill_gaps {
|
|||||||
flow_spacing => $flow->spacing,
|
flow_spacing => $flow->spacing,
|
||||||
);
|
);
|
||||||
|
|
||||||
push @{ $self->thin_fills },
|
# Split polylines into lines so that the chained_path() search
|
||||||
map {
|
# at the final stage has more freedom and will choose starting
|
||||||
$_->simplify($flow->scaled_width/3);
|
# points closer than last positions. OTOH, this will make such
|
||||||
$_;
|
# search slower. Probably, ExtrusionPath objects should support
|
||||||
}
|
# splitting nearby a given position so that we can choose the right
|
||||||
map Slic3r::ExtrusionPath->new(
|
# entry point even in the middle of the path without needing a
|
||||||
polyline => Slic3r::Polyline->new(@$_),
|
# complex, slow, chained_path() search on all segments. TODO.
|
||||||
role => EXTR_ROLE_GAPFILL,
|
# Such logic will also avoid all the small travel moves that this
|
||||||
height => $self->height,
|
# line-splitting causes, and it will be applicable to other things
|
||||||
flow_spacing => $params->{flow_spacing},
|
# too.
|
||||||
),
|
my @lines = map @{Slic3r::Polyline->new(@$_)->lines}, @paths;
|
||||||
# Split polylines into lines so that the chained_path() search
|
|
||||||
# at the final stage has more freedom and will choose starting
|
@paths = map Slic3r::ExtrusionPath->new(
|
||||||
# points closer than last positions. OTOH, this will make such
|
polyline => Slic3r::Polyline->new(@$_),
|
||||||
# search slower. Probably, ExtrusionPath objects should support
|
role => EXTR_ROLE_GAPFILL,
|
||||||
# splitting nearby a given position so that we can choose the right
|
height => $self->height,
|
||||||
# entry point even in the middle of the path without needing a
|
flow_spacing => $params->{flow_spacing},
|
||||||
# complex, slow, chained_path() search on all segments. TODO.
|
), @lines;
|
||||||
# Such logic will also avoid all the small travel moves that this
|
$_->simplify($flow->scaled_width/3) for @paths;
|
||||||
# line-splitting causes, and it will be applicable to other things
|
|
||||||
# too.
|
$self->thin_fills->append(@paths);
|
||||||
map Slic3r::Polyline->new(@$_)->lines,
|
|
||||||
@paths;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,21 +51,18 @@ sub subdivide {
|
|||||||
my $self = shift;
|
my $self = shift;
|
||||||
my ($max_length) = @_;
|
my ($max_length) = @_;
|
||||||
|
|
||||||
for (my $i = 0; $i <= $#$self; $i++) {
|
my @points = @$self;
|
||||||
my $len = Slic3r::Geometry::line_length([ $self->[$i-1], $self->[$i] ]);
|
push @points, $points[0]; # append first point as this is a polygon
|
||||||
my $num_points = int($len / $max_length) - 1;
|
my @new_points = shift @points;
|
||||||
$num_points++ if $len % $max_length;
|
while (@points) {
|
||||||
|
while ($new_points[-1]->distance_to($points[0]) > $max_length) {
|
||||||
# $num_points is the number of points to add between $i-1 and $i
|
push @new_points, map Slic3r::Point->new(@$_),
|
||||||
next if $num_points == -1;
|
Slic3r::Geometry::point_along_segment($new_points[-1], $points[0], $max_length);
|
||||||
my $spacing = $len / ($num_points + 1);
|
}
|
||||||
my @new_points = map Slic3r::Point->new($_),
|
push @new_points, shift @points;
|
||||||
map Slic3r::Geometry::point_along_segment($self->[$i-1], $self->[$i], $spacing * $_),
|
|
||||||
1..$num_points;
|
|
||||||
|
|
||||||
splice @$self, $i, 0, @new_points;
|
|
||||||
$i += @new_points;
|
|
||||||
}
|
}
|
||||||
|
pop @new_points; # remove last point as it coincides with first one
|
||||||
|
return Slic3r::Polygon->new(@new_points);
|
||||||
}
|
}
|
||||||
|
|
||||||
# for cw polygons this will return convex points!
|
# for cw polygons this will return convex points!
|
||||||
|
@ -571,7 +571,6 @@ sub make_skirt {
|
|||||||
my @layers = map $object->layers->[$_], 0..min($Slic3r::Config->skirt_height-1, $#{$object->layers});
|
my @layers = map $object->layers->[$_], 0..min($Slic3r::Config->skirt_height-1, $#{$object->layers});
|
||||||
my @layer_points = (
|
my @layer_points = (
|
||||||
(map @$_, map @$_, map @{$_->slices}, @layers),
|
(map @$_, map @$_, map @{$_->slices}, @layers),
|
||||||
(map @$_, map @{$_->thin_walls}, map @{$_->regions}, @layers),
|
|
||||||
);
|
);
|
||||||
if (@{ $object->support_layers }) {
|
if (@{ $object->support_layers }) {
|
||||||
my @support_layers = map $object->support_layers->[$_], 0..min($Slic3r::Config->skirt_height-1, $#{$object->support_layers});
|
my @support_layers = map $object->support_layers->[$_], 0..min($Slic3r::Config->skirt_height-1, $#{$object->support_layers});
|
||||||
@ -637,7 +636,6 @@ sub make_brim {
|
|||||||
my $layer0 = $object->layers->[0];
|
my $layer0 = $object->layers->[0];
|
||||||
my @object_islands = (
|
my @object_islands = (
|
||||||
(map $_->contour, @{$layer0->slices}),
|
(map $_->contour, @{$layer0->slices}),
|
||||||
(map { $_->isa('Slic3r::Polygon') ? $_ : $_->grow($grow_distance) } map @{$_->thin_walls}, @{$layer0->regions}),
|
|
||||||
);
|
);
|
||||||
if (@{ $object->support_layers }) {
|
if (@{ $object->support_layers }) {
|
||||||
my $support_layer0 = $object->support_layers->[0];
|
my $support_layer0 = $object->support_layers->[0];
|
||||||
|
@ -46,7 +46,7 @@ sub output {
|
|||||||
$arrows = 0;
|
$arrows = 0;
|
||||||
} elsif ($type =~ /^(?:(.+?)_)?expolygons$/) {
|
} elsif ($type =~ /^(?:(.+?)_)?expolygons$/) {
|
||||||
my $colour = $1;
|
my $colour = $1;
|
||||||
@$value = map $_->pp, @$value;
|
$value = [ map $_->pp, @$value ];
|
||||||
|
|
||||||
my $g = $svg->group(
|
my $g = $svg->group(
|
||||||
style => {
|
style => {
|
||||||
@ -64,7 +64,7 @@ sub output {
|
|||||||
}
|
}
|
||||||
} elsif ($type =~ /^(?:(.+?)_)?(polygon|polyline)s$/) {
|
} elsif ($type =~ /^(?:(.+?)_)?(polygon|polyline)s$/) {
|
||||||
my ($colour, $method) = ($1, $2);
|
my ($colour, $method) = ($1, $2);
|
||||||
@$value = map $_->pp, @$value;
|
$value = [ map $_->pp, @$value ];
|
||||||
|
|
||||||
my $g = $svg->group(
|
my $g = $svg->group(
|
||||||
style => {
|
style => {
|
||||||
@ -86,8 +86,8 @@ sub output {
|
|||||||
}
|
}
|
||||||
} elsif ($type =~ /^(?:(.+?)_)?points$/) {
|
} elsif ($type =~ /^(?:(.+?)_)?points$/) {
|
||||||
my $colour = $1 // 'black';
|
my $colour = $1 // 'black';
|
||||||
my $r = $colour eq 'black' ? 5 : 3;
|
my $r = $colour eq 'black' ? 1 : 3;
|
||||||
@$value = map $_->pp, @$value;
|
$value = [ map $_->pp, @$value ];
|
||||||
|
|
||||||
my $g = $svg->group(
|
my $g = $svg->group(
|
||||||
style => {
|
style => {
|
||||||
@ -105,7 +105,7 @@ sub output {
|
|||||||
}
|
}
|
||||||
} elsif ($type =~ /^(?:(.+?)_)?lines$/) {
|
} elsif ($type =~ /^(?:(.+?)_)?lines$/) {
|
||||||
my $colour = $1;
|
my $colour = $1;
|
||||||
@$value = map $_->pp, @$value;
|
$value = [ map $_->pp, @$value ];
|
||||||
|
|
||||||
my $g = $svg->group(
|
my $g = $svg->group(
|
||||||
style => {
|
style => {
|
||||||
|
Loading…
Reference in New Issue
Block a user