Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/prusa3d/PrusaSlicer.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlessandro Ranellucci <aar@cpan.org>2011-11-13 21:14:02 +0400
committerAlessandro Ranellucci <aar@cpan.org>2011-11-13 21:14:02 +0400
commit038caddcdae26a44bb0b68c952570319cd0ab42c (patch)
tree8cac8bb3336223d24bb931b376f0e1b1f5b52010
parent041e9877a3838e8441618901dc20e89311de428c (diff)
New fill types (hilbertcurve, archimedeanchords, octagramspiral) and ability to use different patterns for solid layers. #20
-rw-r--r--Build.PL1
-rw-r--r--README.markdown11
-rw-r--r--lib/Slic3r.pm3
-rw-r--r--lib/Slic3r/Config.pm20
-rw-r--r--lib/Slic3r/ExPolygon.pm77
-rw-r--r--lib/Slic3r/Fill.pm20
-rw-r--r--lib/Slic3r/Fill/ArchimedeanChords.pm7
-rw-r--r--lib/Slic3r/Fill/Base.pm11
-rw-r--r--lib/Slic3r/Fill/Flowsnake.pm18
-rw-r--r--lib/Slic3r/Fill/HilbertCurve.pm7
-rw-r--r--lib/Slic3r/Fill/OctagramSpiral.pm9
-rw-r--r--lib/Slic3r/Fill/PlanePath.pm62
-rw-r--r--lib/Slic3r/Fill/Rectilinear.pm17
-rw-r--r--lib/Slic3r/Fill/Rectilinear2.pm10
-rw-r--r--lib/Slic3r/GUI/OptionsGroup.pm10
-rw-r--r--lib/Slic3r/GUI/SkeinPanel.pm2
-rw-r--r--lib/Slic3r/Geometry.pm37
-rw-r--r--lib/Slic3r/Line.pm12
-rw-r--r--lib/Slic3r/Polygon.pm29
-rw-r--r--lib/Slic3r/Polyline.pm49
-rwxr-xr-xslic3r.pl5
-rw-r--r--t/polyclip.t67
22 files changed, 391 insertions, 93 deletions
diff --git a/Build.PL b/Build.PL
index 288e152ff..01314e924 100644
--- a/Build.PL
+++ b/Build.PL
@@ -11,6 +11,7 @@ my $build = Module::Build->new(
'Getopt::Long' => '0',
'Math::Clipper' => '1.02',
'Math::ConvexHull' => '1.0.4',
+ 'Math::PlanePath' => '53',
'Moo' => '0',
'Time::HiRes' => '0',
'XXX' => '0',
diff --git a/README.markdown b/README.markdown
index c1e9a50a5..94972b5f2 100644
--- a/README.markdown
+++ b/README.markdown
@@ -94,9 +94,11 @@ The author is Alessandro Ranellucci (me).
Use relative distances for extrusion in GCODE output
--z-offset Additional height in mm to add to vertical coordinates
(+/-, default: 0)
+ --gcode-arcs Use G2/G3 commands for native arcs (experimental, not supported
+ by all firmwares)
Filament options:
- --filament-diameter Diameter of your raw filament (default: 3)
+ --filament-diameter Diameter in mm of your raw filament (default: 3)
--filament-packing-density
Ratio of the extruded volume over volume pushed
into the extruder (default: 1)
@@ -123,7 +125,9 @@ The author is Alessandro Ranellucci (me).
(range: 1+, default: 3)
--fill-density Infill density (range: 0-1, default: 0.4)
--fill-angle Infill angle in degrees (range: 0-90, default: 0)
- --start-gcode Load initial gcode from the supplied file. This will overwrite
+ --fill-pattern Pattern to use to fill non-solid layers (default: rectilinear)
+ --solid-fill-pattern Pattern to use to fill solid layers (default: rectilinear)
+ --start-gcode Load initial gcode from the supplied file. This will overwrite
the default command (home all axes [G28]).
--end-gcode Load final gcode from the supplied file. This will overwrite
the default commands (turn off temperature [M104 S0],
@@ -138,6 +142,7 @@ The author is Alessandro Ranellucci (me).
compensating retraction (default: 0)
--retract-before-travel
Only retract before travel moves of this length (default: 2)
+ --retract-lift Lift Z by the given distance in mm when retracting (default: 0)
Skirt options:
--skirts Number of skirts to draw (default: 1)
@@ -152,3 +157,5 @@ The author is Alessandro Ranellucci (me).
--duplicate-distance Distance in mm between copies (default: 6)
+
+
diff --git a/lib/Slic3r.pm b/lib/Slic3r.pm
index 380da3d94..790e5c5cf 100644
--- a/lib/Slic3r.pm
+++ b/lib/Slic3r.pm
@@ -60,7 +60,8 @@ our $flow_width;
our $perimeter_offsets = 3;
our $solid_layers = 3;
our $bridge_overlap = 3; # mm
-our $fill_type = 'rectilinear';
+our $fill_pattern = 'rectilinear';
+our $solid_fill_pattern = 'rectilinear';
our $fill_density = 0.4; # 1 = 100%
our $fill_angle = 0;
our $start_gcode = "G28 ; home all axes";
diff --git a/lib/Slic3r/Config.pm b/lib/Slic3r/Config.pm
index 632312bbf..1c20ca59b 100644
--- a/lib/Slic3r/Config.pm
+++ b/lib/Slic3r/Config.pm
@@ -78,6 +78,16 @@ our $Options = {
label => 'Solid layers',
type => 'i',
},
+ 'fill_pattern' => {
+ label => 'Fill pattern',
+ type => 'select',
+ values => [qw(rectilinear hilbertcurve archimedeanchords octagramspiral)],
+ },
+ 'solid_fill_pattern' => {
+ label => 'Solid fill pattern',
+ type => 'select',
+ values => [qw(rectilinear hilbertcurve archimedeanchords octagramspiral)],
+ },
'fill_density' => {
label => 'Fill density',
type => 'f',
@@ -266,9 +276,13 @@ sub validate {
$Slic3r::print_center = [ split /,/, $Slic3r::print_center ]
if !ref $Slic3r::print_center;
- # --fill-type
- die "Invalid value for --fill-type\n"
- if !exists $Slic3r::Fill::FillTypes{$Slic3r::fill_type};
+ # --fill-pattern
+ die "Invalid value for --fill-pattern\n"
+ if !exists $Slic3r::Fill::FillTypes{$Slic3r::fill_pattern};
+
+ # --solid-fill-pattern
+ die "Invalid value for --solid-fill-pattern\n"
+ if !exists $Slic3r::Fill::FillTypes{$Slic3r::solid_fill_pattern};
# --fill-density
die "Invalid value for --fill-density\n"
diff --git a/lib/Slic3r/ExPolygon.pm b/lib/Slic3r/ExPolygon.pm
index 593925952..7abaf6b48 100644
--- a/lib/Slic3r/ExPolygon.pm
+++ b/lib/Slic3r/ExPolygon.pm
@@ -5,6 +5,7 @@ use warnings;
# an ExPolygon is a polygon with holes
use Math::Clipper qw(CT_UNION PFT_NONZERO JT_MITER);
+use Slic3r::Geometry qw(point_in_polygon X Y A B);
use Slic3r::Geometry::Clipper qw(union_ex);
# the constructor accepts an array of polygons
@@ -24,14 +25,6 @@ sub new {
$self;
}
-# this class method accepts an array of polygons and returns
-# an array of expolygons with the right holes applied to the
-# right contours
-sub make {
- my $class = shift;
- return @{ union_ex(\@_) };
-}
-
sub contour {
my $self = shift;
return $self->[0];
@@ -60,7 +53,73 @@ sub offset {
my $offsets = Math::Clipper::offset($self, $distance, $scale, $joinType, $miterLimit);
# apply holes to the right contours
- return (ref $self)->make(@$offsets);
+ return @{ union_ex($offsets) };
+}
+
+sub encloses_point {
+ my $self = shift;
+ my ($point) = @_;
+ return $self->contour->encloses_point($point)
+ && (!grep($_->encloses_point($point), $self->holes)
+ || grep($_->point_on_segment($point), $self->holes));
+}
+
+sub point_on_segment {
+ my $self = shift;
+ my ($point) = @_;
+ for (@$self) {
+ my $line = $_->point_on_segment($point);
+ return $line if $line;
+ }
+ return undef;
+}
+
+sub bounding_box {
+ my $self = shift;
+ return Slic3r::Geometry::bounding_box($self->contour);
+}
+
+sub clip_line {
+ my $self = shift;
+ my ($line) = @_;
+ $line = Slic3r::Line->cast($line);
+
+ my @intersections = grep $_, map $_->intersection($line, 1), map $_->lines, @$self;
+ my @dir = (
+ $line->[B][X] <=> $line->[A][X],
+ $line->[B][Y] <=> $line->[A][Y],
+ );
+
+ @intersections = sort {
+ (($a->[X] <=> $b->[X]) == $dir[X]) && (($a->[Y] <=> $b->[Y]) == $dir[Y]) ? 1 : -1
+ } @intersections, @$line;
+
+ shift @intersections if $intersections[0]->coincides_with($intersections[1]);
+ pop @intersections if $intersections[-1]->coincides_with($intersections[-2]);
+
+ shift @intersections
+ if !$self->encloses_point($intersections[0])
+ && !$self->point_on_segment($intersections[0]);
+
+ my @lines = ();
+ while (@intersections) {
+ # skip tangent points
+ my @points = splice @intersections, 0, 2;
+ next if !$points[1];
+ next if $points[0]->coincides_with($points[1]);
+ push @lines, [ @points ];
+ }
+ return [@lines];
+}
+
+sub translate {
+ my $self = shift;
+ $_->translate(@_) for @$self;
+}
+
+sub rotate {
+ my $self = shift;
+ $_->rotate(@_) for @$self;
}
1;
diff --git a/lib/Slic3r/Fill.pm b/lib/Slic3r/Fill.pm
index 92e4d60af..35bd4e94e 100644
--- a/lib/Slic3r/Fill.pm
+++ b/lib/Slic3r/Fill.pm
@@ -1,7 +1,11 @@
package Slic3r::Fill;
use Moo;
+use Slic3r::Fill::ArchimedeanChords;
use Slic3r::Fill::Base;
+use Slic3r::Fill::Flowsnake;
+use Slic3r::Fill::HilbertCurve;
+use Slic3r::Fill::OctagramSpiral;
use Slic3r::Fill::Rectilinear;
use Slic3r::Fill::Rectilinear2;
@@ -11,14 +15,18 @@ has 'print' => (is => 'ro', required => 1);
has 'fillers' => (is => 'rw', default => sub { {} });
our %FillTypes = (
- rectilinear => 'Slic3r::Fill::Rectilinear',
- rectilinear2 => 'Slic3r::Fill::Rectilinear2',
+ archimedeanchords => 'Slic3r::Fill::ArchimedeanChords',
+ rectilinear => 'Slic3r::Fill::Rectilinear',
+ rectilinear2 => 'Slic3r::Fill::Rectilinear2',
+ flowsnake => 'Slic3r::Fill::Flowsnake',
+ octagramspiral => 'Slic3r::Fill::OctagramSpiral',
+ hilbertcurve => 'Slic3r::Fill::HilbertCurve',
);
sub BUILD {
my $self = shift;
$self->fillers->{$_} ||= $FillTypes{$_}->new(print => $self->print)
- for ('rectilinear', $Slic3r::fill_type);
+ for ('rectilinear', $Slic3r::fill_pattern, $Slic3r::solid_fill_pattern);
}
sub make_fill {
@@ -38,13 +46,15 @@ sub make_fill {
SURFACE: foreach my $surface (@$surfaces) {
Slic3r::debugf " Processing surface %s:\n", $surface->id;
- my $filler = $Slic3r::fill_type;
+ my $filler = $Slic3r::fill_pattern;
my $density = $Slic3r::fill_density;
# force 100% density and rectilinear fill for external surfaces
if ($surface->surface_type ne 'internal') {
$density = 1;
- $filler = 'rectilinear';
+ $filler = $surface->isa('Slic3r::Surface::Bridge')
+ ? 'rectilinear'
+ : $Slic3r::solid_fill_pattern;
} else {
next SURFACE unless $density > 0;
}
diff --git a/lib/Slic3r/Fill/ArchimedeanChords.pm b/lib/Slic3r/Fill/ArchimedeanChords.pm
new file mode 100644
index 000000000..3c71f0e36
--- /dev/null
+++ b/lib/Slic3r/Fill/ArchimedeanChords.pm
@@ -0,0 +1,7 @@
+package Slic3r::Fill::ArchimedeanChords;
+use Moo;
+
+extends 'Slic3r::Fill::PlanePath';
+use Math::PlanePath::ArchimedeanChords;
+
+1;
diff --git a/lib/Slic3r/Fill/Base.pm b/lib/Slic3r/Fill/Base.pm
index 30b49e6e9..45a8e49cc 100644
--- a/lib/Slic3r/Fill/Base.pm
+++ b/lib/Slic3r/Fill/Base.pm
@@ -35,14 +35,15 @@ sub infill_direction {
sub rotate_points {
my $self = shift;
- my ($polygons, $rotate_vector) = @_;
+ my ($expolygon, $rotate_vector) = @_;
my @rotate = @{$rotate_vector->[0]};
my @shift = @{$rotate_vector->[1]};
- # rotate surface as needed
- @$polygons = map [ Slic3r::Geometry::move_points(\@shift, @$_) ],
- map [ Slic3r::Geometry::rotate_points(@rotate, @$_) ], @$polygons if $rotate[0];
-
+ # rotate points as needed
+ if ($rotate[0]) {
+ $expolygon->rotate(@rotate);
+ $expolygon->translate(@shift);
+ }
}
sub rotate_points_back {
diff --git a/lib/Slic3r/Fill/Flowsnake.pm b/lib/Slic3r/Fill/Flowsnake.pm
new file mode 100644
index 000000000..79d7a1530
--- /dev/null
+++ b/lib/Slic3r/Fill/Flowsnake.pm
@@ -0,0 +1,18 @@
+package Slic3r::Fill::Flowsnake;
+use Moo;
+
+extends 'Slic3r::Fill::PlanePath';
+
+use Math::PlanePath::Flowsnake;
+use Slic3r::Geometry qw(X X1 X2);
+
+# Sorry, this fill is currently broken.
+
+sub process_polyline {
+ my $self = shift;
+ my ($polyline, $bounding_box) = @_;
+
+ $_->[X] += ($bounding_box->[X1] + $bounding_box->[X2]/2) for @{$polyline->points};
+}
+
+1;
diff --git a/lib/Slic3r/Fill/HilbertCurve.pm b/lib/Slic3r/Fill/HilbertCurve.pm
new file mode 100644
index 000000000..eff1a44ac
--- /dev/null
+++ b/lib/Slic3r/Fill/HilbertCurve.pm
@@ -0,0 +1,7 @@
+package Slic3r::Fill::HilbertCurve;
+use Moo;
+
+extends 'Slic3r::Fill::PlanePath';
+use Math::PlanePath::HilbertCurve;
+
+1;
diff --git a/lib/Slic3r/Fill/OctagramSpiral.pm b/lib/Slic3r/Fill/OctagramSpiral.pm
new file mode 100644
index 000000000..9c1272444
--- /dev/null
+++ b/lib/Slic3r/Fill/OctagramSpiral.pm
@@ -0,0 +1,9 @@
+package Slic3r::Fill::OctagramSpiral;
+use Moo;
+
+extends 'Slic3r::Fill::PlanePath';
+use Math::PlanePath::OctagramSpiral;
+
+sub multiplier () { sqrt(2) }
+
+1;
diff --git a/lib/Slic3r/Fill/PlanePath.pm b/lib/Slic3r/Fill/PlanePath.pm
new file mode 100644
index 000000000..45a00ceca
--- /dev/null
+++ b/lib/Slic3r/Fill/PlanePath.pm
@@ -0,0 +1,62 @@
+package Slic3r::Fill::PlanePath;
+use Moo;
+
+extends 'Slic3r::Fill::Base';
+
+use Slic3r::Geometry qw(bounding_box);
+use XXX;
+
+sub multiplier () { 1 }
+
+sub get_n {
+ my $self = shift;
+ my ($path, $bounding_box) = @_;
+
+ my ($n_lo, $n_hi) = $path->rect_to_n_range(@$bounding_box);
+ return ($n_lo .. $n_hi);
+}
+
+sub process_polyline {}
+
+sub fill_surface {
+ my $self = shift;
+ my ($surface, %params) = @_;
+
+ # rotate polygons
+ my $expolygon = $surface->expolygon;
+ my $rotate_vector = $self->infill_direction($surface);
+ $self->rotate_points($expolygon, $rotate_vector);
+
+ my $distance_between_lines = $Slic3r::flow_width / $Slic3r::resolution / $params{density} * $self->multiplier;
+ my $bounding_box = [ bounding_box(map @$_, $expolygon) ];
+
+ (ref $self) =~ /::([^:]+)$/;
+ my $path = "Math::PlanePath::$1"->new;
+ my @n = $self->get_n($path, [map +($_ / $distance_between_lines), @$bounding_box]);
+
+ my $polyline = Slic3r::Polyline->cast([
+ map [ map {$_*$distance_between_lines} $path->n_to_xy($_) ], @n,
+ ]);
+ return [] if !@{$polyline->points};
+
+ $self->process_polyline($polyline, $bounding_box);
+
+ my @paths = ($polyline->clip_with_expolygon($expolygon));
+
+ if (0) {
+ require "Slic3r/SVG.pm";
+ Slic3r::SVG::output(undef, "fill.svg",
+ polygons => $expolygon,
+ polylines => [map $_->p, @paths],
+ );
+ }
+
+ @paths = map $_->p, @paths;
+
+ # paths must be rotated back
+ $self->rotate_points_back(\@paths, $rotate_vector);
+
+ return @paths;
+}
+
+1;
diff --git a/lib/Slic3r/Fill/Rectilinear.pm b/lib/Slic3r/Fill/Rectilinear.pm
index ff8b7bba4..28fb884b7 100644
--- a/lib/Slic3r/Fill/Rectilinear.pm
+++ b/lib/Slic3r/Fill/Rectilinear.pm
@@ -3,11 +3,7 @@ use Moo;
extends 'Slic3r::Fill::Base';
-use constant X1 => 0;
-use constant Y1 => 1;
-use constant X2 => 2;
-use constant Y2 => 3;
-
+use Slic3r::Geometry qw(X1 Y1 X2 Y2);
use XXX;
sub fill_surface {
@@ -15,21 +11,18 @@ sub fill_surface {
my ($surface, %params) = @_;
# rotate polygons so that we can work with vertical lines here
- my $polygons = [ $surface->p ];
+ my $expolygon = $surface->expolygon;
my $rotate_vector = $self->infill_direction($surface);
- $self->rotate_points($polygons, $rotate_vector);
-
- my $bounding_box = [ Slic3r::Geometry::bounding_box(map @$_, $polygons) ];
- my $surface_width = $bounding_box->[X2] - $bounding_box->[X1];
- my $surface_height = $bounding_box->[Y2] - $bounding_box->[Y1];
+ $self->rotate_points($expolygon, $rotate_vector);
+ my $bounding_box = [ $expolygon->bounding_box ];
my $distance_between_lines = $Slic3r::flow_width / $Slic3r::resolution / $params{density};
my @paths = ();
my $x = $bounding_box->[X1];
while ($x < $bounding_box->[X2]) {
my $vertical_line = [ [$x, $bounding_box->[Y2]], [$x, $bounding_box->[Y1]] ];
- push @paths, @{ Slic3r::Geometry::clip_segment_complex_polygon($vertical_line, $polygons) };
+ push @paths, @{ $expolygon->clip_line($vertical_line) };
$x += int($distance_between_lines);
}
diff --git a/lib/Slic3r/Fill/Rectilinear2.pm b/lib/Slic3r/Fill/Rectilinear2.pm
index aee115a72..f2e210bf7 100644
--- a/lib/Slic3r/Fill/Rectilinear2.pm
+++ b/lib/Slic3r/Fill/Rectilinear2.pm
@@ -3,15 +3,7 @@ use Moo;
extends 'Slic3r::Fill::Base';
-use constant X1 => 0;
-use constant Y1 => 1;
-use constant X2 => 2;
-use constant Y2 => 3;
-use constant A => 0;
-use constant B => 1;
-use constant X => 0;
-use constant Y => 1;
-
+use Slic3r::Geometry qw(X1 Y1 X2 Y2 A B X Y);
use XXX;
sub fill_surface {
diff --git a/lib/Slic3r/GUI/OptionsGroup.pm b/lib/Slic3r/GUI/OptionsGroup.pm
index b5ad7797d..98fa53ed9 100644
--- a/lib/Slic3r/GUI/OptionsGroup.pm
+++ b/lib/Slic3r/GUI/OptionsGroup.pm
@@ -3,7 +3,7 @@ use strict;
use warnings;
use Wx qw(:sizer);
-use Wx::Event qw(EVT_TEXT EVT_CHECKBOX);
+use Wx::Event qw(EVT_TEXT EVT_CHECKBOX EVT_CHOICE);
use base 'Wx::StaticBoxSizer';
# not very elegant, but this solution is temporary waiting for a better GUI
@@ -55,6 +55,14 @@ sub new {
$x_field->SetValue($value->[0]);
$y_field->SetValue($value->[1]);
};
+ } elsif ($opt->{type} eq 'select') {
+ $field = Wx::Choice->new($parent, -1, Wx::wxDefaultPosition, Wx::wxDefaultSize, $opt->{values});
+ EVT_CHOICE($parent, $field, sub { Slic3r::Config->set($opt_key, $opt->{values}[$field->GetSelection]) });
+ push @reload_callbacks, sub {
+ my $value = Slic3r::Config->get($opt_key);
+ $field->SetSelection(grep $opt->{values}[$_] eq $value, 0..$#{$opt->{values}});
+ };
+ $reload_callbacks[-1]->();
} else {
die "Unsupported option type: " . $opt->{type};
}
diff --git a/lib/Slic3r/GUI/SkeinPanel.pm b/lib/Slic3r/GUI/SkeinPanel.pm
index ab338498d..878495da3 100644
--- a/lib/Slic3r/GUI/SkeinPanel.pm
+++ b/lib/Slic3r/GUI/SkeinPanel.pm
@@ -33,7 +33,7 @@ sub new {
),
print => Slic3r::GUI::OptionsGroup->new($self,
title => 'Print settings',
- options => [qw(perimeter_offsets solid_layers fill_density fill_angle)],
+ options => [qw(perimeter_offsets solid_layers fill_density fill_angle fill_pattern solid_fill_pattern)],
),
retract => Slic3r::GUI::OptionsGroup->new($self,
title => 'Retraction',
diff --git a/lib/Slic3r/Geometry.pm b/lib/Slic3r/Geometry.pm
index 39fdc0937..98ad804e2 100644
--- a/lib/Slic3r/Geometry.pm
+++ b/lib/Slic3r/Geometry.pm
@@ -5,7 +5,7 @@ use warnings;
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT_OK = qw(
- PI X Y Z A B epsilon slope line_atan lines_parallel three_points_aligned
+ PI X Y Z A B X1 Y1 X2 Y2 epsilon slope line_atan lines_parallel
line_point_belongs_to_segment points_coincide distance_between_points
line_length midpoint point_in_polygon point_in_segment segment_in_segment
point_is_on_left_of_segment polyline_lines polygon_lines nearest_point
@@ -14,7 +14,7 @@ our @EXPORT_OK = qw(
rotate_points move_points remove_coinciding_points clip_segment_polygon
sum_vectors multiply_vector subtract_vectors dot perp polygon_points_visibility
line_intersection bounding_box bounding_box_intersect
- clip_segment_complex_polygon longest_segment angle3points
+ longest_segment angle3points three_points_aligned
polyline_remove_parallel_continuous_edges polyline_remove_acute_vertices
polygon_remove_acute_vertices polygon_remove_parallel_continuous_edges
shortest_path collinear
@@ -29,6 +29,10 @@ use constant B => 1;
use constant X => 0;
use constant Y => 1;
use constant Z => 2;
+use constant X1 => 0;
+use constant Y1 => 1;
+use constant X2 => 2;
+use constant Y2 => 3;
our $parallel_degrees_limit = abs(deg2rad(3));
our $epsilon = 1E-4;
@@ -110,6 +114,7 @@ sub midpoint {
return [ ($line->[B][X] + $line->[A][X]) / 2, ($line->[B][Y] + $line->[A][Y]) / 2 ];
}
+# this will check whether a point is in a polygon regardless of polygon orientation
sub point_in_polygon {
my ($point, $polygon) = @_;
@@ -311,7 +316,7 @@ sub rotate_points {
sub move_points {
my ($shift, @points) = @_;
- return map [ $shift->[X] + $_->[X], $shift->[Y] + $_->[Y] ], @points;
+ return map Slic3r::Point->new($shift->[X] + $_->[X], $shift->[Y] + $_->[Y]), @points;
}
# preserves order
@@ -558,32 +563,6 @@ sub bounding_box_intersect {
return 1;
}
-sub clip_segment_complex_polygon {
- my ($line, $polygons) = @_;
-
- my @intersections = grep $_, map line_intersection($line, $_, 1),
- map polygon_lines($_), @$polygons or return ();
-
- # this is not very elegant, however it works
- @intersections = sort { sprintf("%020f,%020f", @$a) cmp sprintf("%020f,%020f", @$b) } @intersections;
-
- shift(@intersections) if !grep(point_in_polygon($intersections[0], $_), @$polygons)
- && !grep(polygon_segment_having_point($_, $intersections[0]), @$polygons);
-
- # defensive programming
- ###die "Invalid intersections" if @intersections % 2 != 0;
-
- my @lines = ();
- while (@intersections) {
- # skip tangent points
- my @points = map shift @intersections, 1..2;
- next if !$points[1];
- next if points_coincide(@points);
- push @lines, [ @points ];
- }
- return [@lines];
-}
-
sub angle3points {
my ($p1, $p2, $p3) = @_;
# p1 is the center
diff --git a/lib/Slic3r/Line.pm b/lib/Slic3r/Line.pm
index 0e192a400..6d395e50b 100644
--- a/lib/Slic3r/Line.pm
+++ b/lib/Slic3r/Line.pm
@@ -8,18 +8,26 @@ sub new {
my $class = shift;
my $self;
if (@_ == 2) {
- $self = [ map Slic3r::Point->new($_), @_ ];
+ $self = [ @_ ];
} elsif (ref $_[0] eq 'ARRAY') {
- $self = [ map Slic3r::Point->new($_), $_[0][0], $_[0][1] ];
+ $self = [ $_[0][0], $_[0][1] ];
} elsif ($_[0]->isa(__PACKAGE__)) {
return $_[0];
} else {
die "Invalid argument for $class->new";
}
bless $self, $class;
+ bless $_, 'Slic3r::Point' for @$self;
return $self;
}
+sub cast {
+ my $class = shift;
+ my ($line) = @_;
+ return $line if ref $line eq __PACKAGE__;
+ return $class->new($line);
+}
+
sub a { $_[0][0] }
sub b { $_[0][1] }
diff --git a/lib/Slic3r/Polygon.pm b/lib/Slic3r/Polygon.pm
index 734a8c9be..47e8ce51d 100644
--- a/lib/Slic3r/Polygon.pm
+++ b/lib/Slic3r/Polygon.pm
@@ -7,7 +7,8 @@ use warnings;
# as a Slic3r::Polyline::Closed you're right. I plan to
# ditch the latter and port everything to this class.
-use Slic3r::Geometry qw(polygon_lines polygon_remove_parallel_continuous_edges);
+use Slic3r::Geometry qw(polygon_lines polygon_remove_parallel_continuous_edges
+ polygon_segment_having_point point_in_polygon move_points rotate_points);
# the constructor accepts an array(ref) of points
sub new {
@@ -19,8 +20,8 @@ sub new {
$self = [ @_ ];
}
- @$self = map Slic3r::Point->cast($_), @$self;
bless $self, $class;
+ bless $_, 'Slic3r::Point' for @$self;
$self;
}
@@ -40,4 +41,28 @@ sub cleanup {
polygon_remove_parallel_continuous_edges($self);
}
+sub point_on_segment {
+ my $self = shift;
+ my ($point) = @_;
+ return polygon_segment_having_point($self, $point);
+}
+
+sub encloses_point {
+ my $self = shift;
+ my ($point) = @_;
+ return point_in_polygon($point, $self);
+}
+
+sub translate {
+ my $self = shift;
+ my ($x, $y) = @_;
+ @$self = move_points([$x, $y], @$self);
+}
+
+sub rotate {
+ my $self = shift;
+ my ($angle, $center) = @_;
+ @$self = rotate_points($angle, $center, @$self);
+}
+
1; \ No newline at end of file
diff --git a/lib/Slic3r/Polyline.pm b/lib/Slic3r/Polyline.pm
index e7e6dd27b..f85a45ba7 100644
--- a/lib/Slic3r/Polyline.pm
+++ b/lib/Slic3r/Polyline.pm
@@ -2,8 +2,8 @@ package Slic3r::Polyline;
use Moo;
use Math::Clipper qw();
-use Slic3r::Geometry qw(polyline_remove_parallel_continuous_edges polyline_remove_acute_vertices
- polygon_remove_acute_vertices polygon_remove_parallel_continuous_edges);
+use Slic3r::Geometry qw(A B polyline_remove_parallel_continuous_edges polyline_remove_acute_vertices
+ polygon_remove_acute_vertices polygon_remove_parallel_continuous_edges move_points);
use Sub::Quote;
use XXX;
@@ -118,4 +118,49 @@ sub has_segment {
return 0;
}
+sub clip_with_expolygon {
+ my $self = shift;
+ my ($expolygon) = @_;
+
+ my @polylines = ();
+ my $current_polyline = [];
+ foreach my $line ($self->lines) {
+ my ($first_line, @other_lines) = @{ $expolygon->clip_line($line) };
+ next unless $first_line;
+
+ if (!@$current_polyline) {
+ push @$current_polyline, @$first_line;
+ } elsif ($first_line->[A]->coincides_with($current_polyline->[-1])) {
+ push @$current_polyline, $first_line->[B];
+ } else {
+ push @polylines, $current_polyline;
+ $current_polyline = [ @$first_line ];
+ }
+
+ foreach my $other_line (@other_lines) {
+ if (@$current_polyline) {
+ push @polylines, $current_polyline;
+ $current_polyline = [];
+ }
+ push @polylines, [ @$other_line ];
+ }
+ }
+ if (@$current_polyline) {
+ push @polylines, $current_polyline;
+ }
+
+ return map Slic3r::Polyline->cast($_), @polylines;
+}
+
+sub bounding_box {
+ my $self = shift;
+ return Slic3r::Geometry::bounding_box($self->points);
+}
+
+sub translate {
+ my $self = shift;
+ my ($x, $y) = @_;
+ @{$self->points} = move_points([$x, $y], @{$self->points});
+}
+
1;
diff --git a/slic3r.pl b/slic3r.pl
index a711d6f1b..74eb88d46 100755
--- a/slic3r.pl
+++ b/slic3r.pl
@@ -47,7 +47,8 @@ GetOptions(
# print options
'perimeters=i' => \$Slic3r::perimeter_offsets,
'solid-layers=i' => \$Slic3r::solid_layers,
- 'fill-type=s' => \$Slic3r::fill_type,
+ 'fill-pattern=s' => \$Slic3r::fill_pattern,
+ 'solid-fill-pattern=s' => \$Slic3r::solid_fill_pattern,
'fill-density=f' => \$Slic3r::fill_density,
'fill-angle=i' => \$Slic3r::fill_angle,
'start-gcode=s' => \$opt{start_gcode},
@@ -161,6 +162,8 @@ Usage: slic3r.pl [ OPTIONS ] file.stl
(range: 1+, default: $Slic3r::solid_layers)
--fill-density Infill density (range: 0-1, default: $Slic3r::fill_density)
--fill-angle Infill angle in degrees (range: 0-90, default: $Slic3r::fill_angle)
+ --fill-pattern Pattern to use to fill non-solid layers (default: $Slic3r::fill_pattern)
+ --solid-fill-pattern Pattern to use to fill solid layers (default: $Slic3r::solid_fill_pattern)
--start-gcode Load initial gcode from the supplied file. This will overwrite
the default command (home all axes [G28]).
--end-gcode Load final gcode from the supplied file. This will overwrite
diff --git a/t/polyclip.t b/t/polyclip.t
index b7d4d58f6..205f036c8 100644
--- a/t/polyclip.t
+++ b/t/polyclip.t
@@ -2,7 +2,7 @@ use Test::More;
use strict;
use warnings;
-plan tests => 14;
+plan tests => 24;
BEGIN {
use FindBin;
@@ -59,11 +59,57 @@ is_deeply $intersection, [ [12, 12], [18, 16] ], 'internal lines are preserved';
[16, 16],
[16, 14],
];
- my $intersections = Slic3r::Geometry::clip_segment_complex_polygon($line, [ $square, $hole_in_square ]);
- is_deeply $intersections, [
- [ [10, 15], [14, 15] ],
- [ [16, 15], [20, 15] ],
- ], 'line is clipped to square with hole';
+ my $expolygon = Slic3r::ExPolygon->new($square, $hole_in_square);
+ is $expolygon->encloses_point([10, 10]), 1, 'corner point is recognized';
+ is $expolygon->encloses_point([10, 18]), 1, 'point on contour is recognized';
+ is $expolygon->encloses_point([14, 15]), 1, 'point on hole contour is recognized';
+ is $expolygon->encloses_point([14, 14]), 1, 'point on hole corner is recognized';
+ {
+ my $intersections = $expolygon->clip_line([ [15,18], [15,15] ]);
+ is_deeply $intersections, [
+ [ [15, 18], [15, 16] ],
+ ], 'line is clipped to square with hole';
+ }
+ {
+ my $intersections = $expolygon->clip_line([ [15,15], [15,12] ]);
+ is_deeply $intersections, [
+ [ [15, 14], [15, 12] ],
+ ], 'line is clipped to square with hole';
+ }
+ {
+ my $intersections = $expolygon->clip_line([ [12,18], [18,18] ]);
+ is_deeply $intersections, [
+ [ [12,18], [18,18] ],
+ ], 'line is clipped to square with hole';
+ }
+ {
+ my $intersections = $expolygon->clip_line($line);
+ is_deeply $intersections, [
+ [ [10, 15], [14, 15] ],
+ [ [16, 15], [20, 15] ],
+ ], 'line is clipped to square with hole';
+ }
+ {
+ my $intersections = $expolygon->clip_line([ reverse @$line ]);
+ is_deeply $intersections, [
+ [ [20, 15], [16, 15] ],
+ [ [14, 15], [10, 15] ],
+ ], 'reverse line is clipped to square with hole';
+ }
+ {
+ my $intersections = $expolygon->clip_line([ [10,18], [20,18] ]);
+ is_deeply $intersections, [
+ [ [10, 18], [20, 18] ],
+ ], 'tangent line is clipped to square with hole';
+ }
+ {
+ my $polyline = Slic3r::Polyline->cast([ [5, 18], [25, 18], [25, 15], [15, 15], [15, 12], [12, 12], [12, 5] ]);
+ is_deeply [ map $_->p, $polyline->clip_with_expolygon($expolygon) ], [
+ [ [10, 18], [20, 18] ],
+ [ [20, 15], [16, 15] ],
+ [ [15, 14], [15, 12], [12, 12], [12, 10] ],
+ ], 'polyline is clipped to square with hole';
+ }
}
#==========================================================
@@ -93,11 +139,14 @@ is_deeply $intersection, [ [12, 12], [18, 16] ], 'internal lines are preserved';
];
is is_counter_clockwise($small_circle), 0, "hole is clockwise";
+ my $expolygon = Slic3r::ExPolygon->new($large_circle, $small_circle);
$line = [ [152.741724,288.086671142818], [152.741724,34.166466971035] ];
- my $intersections = Slic3r::Geometry::clip_segment_complex_polygon($line, [ $large_circle, $small_circle ]);
+ my $intersections = $expolygon->clip_line($line);
is_deeply $intersections, [
- [ [152.741724, 35.166466971035], [152.741724, 108.087543109156] ],
- [ [152.741724, 215.178806915206], [152.741724, 288.086671142818] ],
+ [ [152.741724, 288.086671142818], [152.741724, 215.178806915206], ],
+ [ [152.741724, 108.087543109156], [152.741724, 35.166466971035] ],
], 'line is clipped to square with hole';
}
+
+#==========================================================