diff --git a/lib/Slic3r.pm b/lib/Slic3r.pm
index d9274bea93..1e94e0f482 100644
--- a/lib/Slic3r.pm
+++ b/lib/Slic3r.pm
@@ -28,11 +28,6 @@ BEGIN {
use FindBin;
-# Let the XS module know where the GUI resources reside.
-set_resources_dir(decode_path($FindBin::Bin) . (($^O eq 'darwin') ? '/../Resources' : '/resources'));
-set_var_dir(resources_dir() . "/icons");
-set_local_dir(resources_dir() . "/localization/");
-
use Moo 1.003001;
use Slic3r::XS; # import all symbols (constants etc.) before they get parsed
@@ -40,7 +35,6 @@ use Slic3r::Config;
use Slic3r::ExPolygon;
use Slic3r::ExtrusionLoop;
use Slic3r::ExtrusionPath;
-use Slic3r::Flow;
use Slic3r::GCode::Reader;
use Slic3r::Layer;
use Slic3r::Line;
@@ -60,82 +54,4 @@ use constant SCALING_FACTOR => 0.000001;
$Slic3r::loglevel = (defined($ENV{'SLIC3R_LOGLEVEL'}) && $ENV{'SLIC3R_LOGLEVEL'} =~ /^[1-9]/) ? $ENV{'SLIC3R_LOGLEVEL'} : 0;
set_logging_level($Slic3r::loglevel);
-# Let the palceholder parser evaluate one expression to initialize its local static macro_processor
-# class instance in a thread safe manner.
-Slic3r::GCode::PlaceholderParser->new->evaluate_boolean_expression('1==1');
-
-# Open a file by converting $filename to local file system locales.
-sub open {
- my ($fh, $mode, $filename) = @_;
- return CORE::open $$fh, $mode, encode_path($filename);
-}
-
-sub tags {
- my ($format) = @_;
- $format //= '';
- my %tags;
- # End of line
- $tags{eol} = ($format eq 'html') ? '
' : "\n";
- # Heading
- $tags{h2start} = ($format eq 'html') ? '' : '';
- $tags{h2end} = ($format eq 'html') ? '' : '';
- # Bold font
- $tags{bstart} = ($format eq 'html') ? '' : '';
- $tags{bend} = ($format eq 'html') ? '' : '';
- # Verbatim
- $tags{vstart} = ($format eq 'html') ? '
' : '';
- $tags{vend} = ($format eq 'html') ? '
' : '';
- return %tags;
-}
-
-sub slic3r_info
-{
- my (%params) = @_;
- my %tag = Slic3r::tags($params{format});
- my $out = '';
- $out .= "$tag{bstart}$Slic3r::FORK_NAME$tag{bend}$tag{eol}";
- $out .= "$tag{bstart}Version: $tag{bend}$Slic3r::VERSION$tag{eol}";
- $out .= "$tag{bstart}Build: $tag{bend}$Slic3r::BUILD$tag{eol}";
- return $out;
-}
-
-sub copyright_info
-{
- my (%params) = @_;
- my %tag = Slic3r::tags($params{format});
- my $out =
- 'Copyright © 2016 Vojtech Bubnik, Prusa Research.
' .
- 'Copyright © 2011-2016 Alessandro Ranellucci.
' .
- 'Slic3r is licensed under the ' .
- 'GNU Affero General Public License, version 3.' .
- '
' .
- 'Contributions by Henrik Brix Andersen, Nicolas Dandrimont, Mark Hindess, Petr Ledvina, Y. Sapir, Mike Sheldrake and numerous others. ' .
- 'Manual by Gary Hodgson. Inspired by the RepRap community.
' .
- 'Slic3r logo designed by Corey Daniels, Silk Icon Set designed by Mark James. ';
- return $out;
-}
-
-sub system_info
-{
- my (%params) = @_;
- my %tag = Slic3r::tags($params{format});
-
- my $out = '';
- $out .= "$tag{bstart}Operating System: $tag{bend}$Config{osname}$tag{eol}";
- $out .= "$tag{bstart}System Architecture: $tag{bend}$Config{archname}$tag{eol}";
- if ($^O eq 'MSWin32') {
- $out .= "$tag{bstart}Windows Version: $tag{bend}" . `ver` . $tag{eol};
- } else {
- # Hopefully some kind of unix / linux.
- $out .= "$tag{bstart}System Version: $tag{bend}" . `uname -a` . $tag{eol};
- }
- $out .= $tag{vstart} . Config::myconfig . $tag{vend};
- $out .= " $tag{bstart}\@INC:$tag{bend}$tag{eol}$tag{vstart}";
- foreach my $i (@INC) {
- $out .= " $i\n";
- }
- $out .= "$tag{vend}";
- return $out;
-}
-
1;
diff --git a/lib/Slic3r/Config.pm b/lib/Slic3r/Config.pm
index a9c822b96a..dadf76a0ab 100644
--- a/lib/Slic3r/Config.pm
+++ b/lib/Slic3r/Config.pm
@@ -23,54 +23,10 @@ our $Options = print_config_def();
}
}
-# From command line parameters, used by slic3r.pl
-sub new_from_cli {
- my $class = shift;
- my %args = @_;
-
- # Delete hash keys with undefined value.
- delete $args{$_} for grep !defined $args{$_}, keys %args;
-
- # Replace the start_gcode, end_gcode ... hash values
- # with the content of the files they reference.
- for (qw(start end layer toolchange)) {
- my $opt_key = "${_}_gcode";
- if ($args{$opt_key}) {
- if (-e $args{$opt_key}) {
- Slic3r::open(\my $fh, "<", $args{$opt_key})
- or die "Failed to open $args{$opt_key}\n";
- binmode $fh, ':utf8';
- $args{$opt_key} = do { local $/; <$fh> };
- close $fh;
- }
- }
- }
-
- my $self = $class->new;
- foreach my $opt_key (keys %args) {
- my $opt_def = $Options->{$opt_key};
-
- # we use set_deserialize() for bool options since GetOpt::Long doesn't handle
- # arrays of boolean values
- if ($opt_key =~ /^(?:bed_shape|duplicate_grid|extruder_offset)$/ || $opt_def->{type} eq 'bool') {
- $self->set_deserialize($opt_key, $args{$opt_key});
- } elsif (my $shortcut = $opt_def->{shortcut}) {
- $self->set($_, $args{$opt_key}) for @$shortcut;
- } else {
- $self->set($opt_key, $args{$opt_key});
- }
- }
-
- return $self;
-}
-
package Slic3r::Config::Static;
use parent 'Slic3r::Config';
sub Slic3r::Config::GCode::new { Slic3r::Config::Static::new_GCodeConfig }
sub Slic3r::Config::Print::new { Slic3r::Config::Static::new_PrintConfig }
-sub Slic3r::Config::PrintObject::new { Slic3r::Config::Static::new_PrintObjectConfig }
-sub Slic3r::Config::PrintRegion::new { Slic3r::Config::Static::new_PrintRegionConfig }
-sub Slic3r::Config::Full::new { Slic3r::Config::Static::new_FullPrintConfig }
1;
diff --git a/lib/Slic3r/ExPolygon.pm b/lib/Slic3r/ExPolygon.pm
index 4ab1bc8ab4..1b55849ebf 100644
--- a/lib/Slic3r/ExPolygon.pm
+++ b/lib/Slic3r/ExPolygon.pm
@@ -4,23 +4,9 @@ use warnings;
# an ExPolygon is a polygon with holes
-sub noncollapsing_offset_ex {
- my $self = shift;
- my ($distance, @params) = @_;
-
- return $self->offset_ex($distance + 1, @params);
-}
-
sub bounding_box {
my $self = shift;
return $self->contour->bounding_box;
}
-package Slic3r::ExPolygon::Collection;
-
-sub size {
- my $self = shift;
- return [ Slic3r::Geometry::size_2D([ map @$_, map @$_, @$self ]) ];
-}
-
1;
diff --git a/lib/Slic3r/Flow.pm b/lib/Slic3r/Flow.pm
deleted file mode 100644
index fed894e970..0000000000
--- a/lib/Slic3r/Flow.pm
+++ /dev/null
@@ -1,13 +0,0 @@
-package Slic3r::Flow;
-use strict;
-use warnings;
-
-use parent qw(Exporter);
-
-our @EXPORT_OK = qw(FLOW_ROLE_EXTERNAL_PERIMETER FLOW_ROLE_PERIMETER FLOW_ROLE_INFILL
- FLOW_ROLE_SOLID_INFILL
- FLOW_ROLE_TOP_SOLID_INFILL FLOW_ROLE_SUPPORT_MATERIAL
- FLOW_ROLE_SUPPORT_MATERIAL_INTERFACE);
-our %EXPORT_TAGS = (roles => \@EXPORT_OK);
-
-1;
diff --git a/lib/Slic3r/Geometry.pm b/lib/Slic3r/Geometry.pm
index ca262fc766..2e4f5a0972 100644
--- a/lib/Slic3r/Geometry.pm
+++ b/lib/Slic3r/Geometry.pm
@@ -9,24 +9,15 @@ our @ISA = qw(Exporter);
our @EXPORT_OK = qw(
PI epsilon
- angle3points
- collinear
- dot
- line_intersection
- normalize
- polyline_lines
- polygon_is_convex
scale
unscale
scaled_epsilon
- size_2D
X Y Z
convex_hull
chained_path_from
deg2rad
rad2deg
- rad2deg_dir
);
use constant PI => 4 * atan2(1, 1);
@@ -43,136 +34,6 @@ sub scaled_epsilon () { epsilon / &Slic3r::SCALING_FACTOR }
sub scale ($) { $_[0] / &Slic3r::SCALING_FACTOR }
sub unscale ($) { $_[0] * &Slic3r::SCALING_FACTOR }
-# used by geometry.t
-sub polyline_lines {
- my ($polyline) = @_;
- my @points = @$polyline;
- return map Slic3r::Line->new(@points[$_, $_+1]), 0 .. $#points-1;
-}
-
-# polygon must be simple (non complex) and ccw
-sub polygon_is_convex {
- my ($points) = @_;
- for (my $i = 0; $i <= $#$points; $i++) {
- my $angle = angle3points($points->[$i-1], $points->[$i-2], $points->[$i]);
- return 0 if $angle < PI;
- }
- return 1;
-}
-
-sub normalize {
- my ($line) = @_;
-
- my $len = sqrt( ($line->[X]**2) + ($line->[Y]**2) + ($line->[Z]**2) )
- or return [0, 0, 0]; # to avoid illegal division by zero
- return [ map $_ / $len, @$line ];
-}
-
-# 2D dot product
-# used by 3DScene.pm
-sub dot {
- my ($u, $v) = @_;
- return $u->[X] * $v->[X] + $u->[Y] * $v->[Y];
-}
-
-sub line_intersection {
- my ($line1, $line2, $require_crossing) = @_;
- $require_crossing ||= 0;
-
- my $intersection = _line_intersection(map @$_, @$line1, @$line2);
- return (ref $intersection && $intersection->[1] == $require_crossing)
- ? $intersection->[0]
- : undef;
-}
-
-# Used by test cases.
-sub collinear {
- my ($line1, $line2, $require_overlapping) = @_;
- my $intersection = _line_intersection(map @$_, @$line1, @$line2);
- return 0 unless !ref($intersection)
- && ($intersection eq 'parallel collinear'
- || ($intersection eq 'parallel vertical' && abs($line1->[A][X] - $line2->[A][X]) < epsilon));
-
- if ($require_overlapping) {
- my @box_a = bounding_box([ $line1->[0], $line1->[1] ]);
- my @box_b = bounding_box([ $line2->[0], $line2->[1] ]);
- return 0 unless bounding_box_intersect( 2, @box_a, @box_b );
- }
-
- return 1;
-}
-
-sub _line_intersection {
- my ( $x0, $y0, $x1, $y1, $x2, $y2, $x3, $y3 ) = @_;
-
- my ($x, $y); # The as-yet-undetermined intersection point.
-
- my $dy10 = $y1 - $y0; # dyPQ, dxPQ are the coordinate differences
- my $dx10 = $x1 - $x0; # between the points P and Q.
- my $dy32 = $y3 - $y2;
- my $dx32 = $x3 - $x2;
-
- my $dy10z = abs( $dy10 ) < epsilon; # Is the difference $dy10 "zero"?
- my $dx10z = abs( $dx10 ) < epsilon;
- my $dy32z = abs( $dy32 ) < epsilon;
- my $dx32z = abs( $dx32 ) < epsilon;
-
- my $dyx10; # The slopes.
- my $dyx32;
-
- $dyx10 = $dy10 / $dx10 unless $dx10z;
- $dyx32 = $dy32 / $dx32 unless $dx32z;
-
- # Now we know all differences and the slopes;
- # we can detect horizontal/vertical special cases.
- # E.g., slope = 0 means a horizontal line.
-
- unless ( defined $dyx10 or defined $dyx32 ) {
- return "parallel vertical";
- }
- elsif ( $dy10z and not $dy32z ) { # First line horizontal.
- $y = $y0;
- $x = $x2 + ( $y - $y2 ) * $dx32 / $dy32;
- }
- elsif ( not $dy10z and $dy32z ) { # Second line horizontal.
- $y = $y2;
- $x = $x0 + ( $y - $y0 ) * $dx10 / $dy10;
- }
- elsif ( $dx10z and not $dx32z ) { # First line vertical.
- $x = $x0;
- $y = $y2 + $dyx32 * ( $x - $x2 );
- }
- elsif ( not $dx10z and $dx32z ) { # Second line vertical.
- $x = $x2;
- $y = $y0 + $dyx10 * ( $x - $x0 );
- }
- elsif ( abs( $dyx10 - $dyx32 ) < epsilon ) {
- # The slopes are suspiciously close to each other.
- # Either we have parallel collinear or just parallel lines.
-
- # The bounding box checks have already weeded the cases
- # "parallel horizontal" and "parallel vertical" away.
-
- my $ya = $y0 - $dyx10 * $x0;
- my $yb = $y2 - $dyx32 * $x2;
-
- return "parallel collinear" if abs( $ya - $yb ) < epsilon;
- return "parallel";
- }
- else {
- # None of the special cases matched.
- # We have a "honest" line intersection.
-
- $x = ($y2 - $y0 + $dyx10*$x0 - $dyx32*$x2)/($dyx10 - $dyx32);
- $y = $y0 + $dyx10 * ($x - $x0);
- }
-
- my $h10 = $dx10 ? ($x - $x0) / $dx10 : ($dy10 ? ($y - $y0) / $dy10 : 1);
- my $h32 = $dx32 ? ($x - $x2) / $dx32 : ($dy32 ? ($y - $y2) / $dy32 : 1);
-
- return [Slic3r::Point->new($x, $y), $h10 >= 0 && $h10 <= 1 && $h32 >= 0 && $h32 <= 1];
-}
-
# 2D
sub bounding_box {
my ($points) = @_;
@@ -190,45 +51,4 @@ sub bounding_box {
return @bb[X1,Y1,X2,Y2];
}
-# used by ExPolygon::size
-sub size_2D {
- my @bounding_box = bounding_box(@_);
- return (
- ($bounding_box[X2] - $bounding_box[X1]),
- ($bounding_box[Y2] - $bounding_box[Y1]),
- );
-}
-
-# Used by sub collinear, which is used by test cases.
-# bounding_box_intersect($d, @a, @b)
-# Return true if the given bounding boxes @a and @b intersect
-# in $d dimensions. Used by sub collinear.
-sub bounding_box_intersect {
- my ( $d, @bb ) = @_; # Number of dimensions and box coordinates.
- my @aa = splice( @bb, 0, 2 * $d ); # The first box.
- # (@bb is the second one.)
-
- # Must intersect in all dimensions.
- for ( my $i_min = 0; $i_min < $d; $i_min++ ) {
- my $i_max = $i_min + $d; # The index for the maximum.
- return 0 if ( $aa[ $i_max ] + epsilon ) < $bb[ $i_min ];
- return 0 if ( $bb[ $i_max ] + epsilon ) < $aa[ $i_min ];
- }
-
- return 1;
-}
-
-# Used by test cases.
-# this assumes a CCW rotation from $p2 to $p3 around $p1
-sub angle3points {
- my ($p1, $p2, $p3) = @_;
- # p1 is the center
-
- my $angle = atan2($p2->[X] - $p1->[X], $p2->[Y] - $p1->[Y])
- - atan2($p3->[X] - $p1->[X], $p3->[Y] - $p1->[Y]);
-
- # we only want to return only positive angles
- return $angle <= 0 ? $angle + 2*PI() : $angle;
-}
-
1;
diff --git a/lib/Slic3r/Geometry/Clipper.pm b/lib/Slic3r/Geometry/Clipper.pm
deleted file mode 100644
index c1fa81d9f3..0000000000
--- a/lib/Slic3r/Geometry/Clipper.pm
+++ /dev/null
@@ -1,13 +0,0 @@
-package Slic3r::Geometry::Clipper;
-use strict;
-use warnings;
-
-require Exporter;
-our @ISA = qw(Exporter);
-our @EXPORT_OK = qw(
- offset
- offset2_ex
- diff_ex diff union_ex
- union);
-
-1;
diff --git a/lib/Slic3r/Layer.pm b/lib/Slic3r/Layer.pm
index 4bff9b61fb..7f7b589d0d 100644
--- a/lib/Slic3r/Layer.pm
+++ b/lib/Slic3r/Layer.pm
@@ -31,7 +31,4 @@ sub regions {
return [ map $self->get_region($_), 0..($self->region_count-1) ];
}
-package Slic3r::Layer::Support;
-our @ISA = qw(Slic3r::Layer);
-
1;
diff --git a/lib/Slic3r/Line.pm b/lib/Slic3r/Line.pm
index c06f9a1fa3..16b609c95e 100644
--- a/lib/Slic3r/Line.pm
+++ b/lib/Slic3r/Line.pm
@@ -5,9 +5,4 @@ use warnings;
# a line is a two-points line
use parent 'Slic3r::Polyline';
-sub grow {
- my $self = shift;
- return Slic3r::Polyline->new(@$self)->grow(@_);
-}
-
1;
diff --git a/lib/Slic3r/Model.pm b/lib/Slic3r/Model.pm
index ec31f6c8a1..d44e9878dd 100644
--- a/lib/Slic3r/Model.pm
+++ b/lib/Slic3r/Model.pm
@@ -133,11 +133,4 @@ sub add_instance {
}
}
-sub mesh_stats {
- my $self = shift;
-
- # TODO: sum values from all volumes
- return $self->volumes->[0]->mesh->stats;
-}
-
1;
diff --git a/lib/Slic3r/Polygon.pm b/lib/Slic3r/Polygon.pm
index 16222141a8..d5445047d9 100644
--- a/lib/Slic3r/Polygon.pm
+++ b/lib/Slic3r/Polygon.pm
@@ -5,9 +5,4 @@ use warnings;
# a polygon is a closed polyline.
use parent 'Slic3r::Polyline';
-sub grow {
- my $self = shift;
- return $self->split_at_first_point->grow(@_);
-}
-
-1;
\ No newline at end of file
+1;
diff --git a/lib/Slic3r/Print/Object.pm b/lib/Slic3r/Print/Object.pm
index 64480e08fe..b4e53245ae 100644
--- a/lib/Slic3r/Print/Object.pm
+++ b/lib/Slic3r/Print/Object.pm
@@ -4,8 +4,6 @@ use strict;
use warnings;
use List::Util qw(min max sum first);
-use Slic3r::Flow ':roles';
-use Slic3r::Print::State ':steps';
use Slic3r::Surface ':types';
sub layers {
@@ -13,9 +11,4 @@ sub layers {
return [ map $self->get_layer($_), 0..($self->layer_count - 1) ];
}
-sub support_layers {
- my $self = shift;
- return [ map $self->get_support_layer($_), 0..($self->support_layer_count - 1) ];
-}
-
1;
diff --git a/lib/Slic3r/Print/State.pm b/lib/Slic3r/Print/State.pm
deleted file mode 100644
index 17c614f1be..0000000000
--- a/lib/Slic3r/Print/State.pm
+++ /dev/null
@@ -1,12 +0,0 @@
-# Wraps C++ enums Slic3r::PrintStep and Slic3r::PrintObjectStep
-package Slic3r::Print::State;
-use strict;
-use warnings;
-
-require Exporter;
-our @ISA = qw(Exporter);
-our @EXPORT_OK = qw(STEP_SLICE STEP_PERIMETERS STEP_PREPARE_INFILL
- STEP_INFILL STEP_SUPPORTMATERIAL STEP_SKIRT STEP_BRIM STEP_WIPE_TOWER);
-our %EXPORT_TAGS = (steps => \@EXPORT_OK);
-
-1;
diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt
index 643afe69ec..d2ecefb9c7 100644
--- a/src/libslic3r/CMakeLists.txt
+++ b/src/libslic3r/CMakeLists.txt
@@ -40,8 +40,6 @@ set(SLIC3R_SOURCES
enum_bitmask.hpp
ExPolygon.cpp
ExPolygon.hpp
- ExPolygonCollection.cpp
- ExPolygonCollection.hpp
Extruder.cpp
Extruder.hpp
ExtrusionEntity.cpp
diff --git a/src/libslic3r/ClipperUtils.cpp b/src/libslic3r/ClipperUtils.cpp
index 25454d5001..5c4b5ac17b 100644
--- a/src/libslic3r/ClipperUtils.cpp
+++ b/src/libslic3r/ClipperUtils.cpp
@@ -240,7 +240,7 @@ TResult clipper_union(
// Perform union of input polygons using the positive rule, convert to ExPolygons.
//FIXME is there any benefit of not doing the boolean / using pftEvenOdd?
-ExPolygons ClipperPaths_to_Slic3rExPolygons(const ClipperLib::Paths &input, bool do_union)
+inline ExPolygons ClipperPaths_to_Slic3rExPolygons(const ClipperLib::Paths &input, bool do_union)
{
return PolyTreeToExPolygons(clipper_union(input, do_union ? ClipperLib::pftNonZero : ClipperLib::pftEvenOdd));
}
@@ -438,7 +438,7 @@ Slic3r::Polygons offset(const Slic3r::SurfacesPtr &surfaces, const float delta,
{ return to_polygons(expolygons_offset(surfaces, delta, joinType, miterLimit)); }
Slic3r::ExPolygons offset_ex(const Slic3r::ExPolygon &expolygon, const float delta, ClipperLib::JoinType joinType, double miterLimit)
//FIXME one may spare one Clipper Union call.
- { return ClipperPaths_to_Slic3rExPolygons(expolygon_offset(expolygon, delta, joinType, miterLimit)); }
+ { return ClipperPaths_to_Slic3rExPolygons(expolygon_offset(expolygon, delta, joinType, miterLimit), /* do union */ false); }
Slic3r::ExPolygons offset_ex(const Slic3r::ExPolygons &expolygons, const float delta, ClipperLib::JoinType joinType, double miterLimit)
{ return PolyTreeToExPolygons(expolygons_offset_pt(expolygons, delta, joinType, miterLimit)); }
Slic3r::ExPolygons offset_ex(const Slic3r::Surfaces &surfaces, const float delta, ClipperLib::JoinType joinType, double miterLimit)
@@ -713,6 +713,8 @@ Slic3r::Polylines intersection_pl(const Slic3r::Polylines &subject, const Slic3r
{ return _clipper_pl_open(ClipperLib::ctIntersection, ClipperUtils::PolylinesProvider(subject), ClipperUtils::SinglePathProvider(clip.points)); }
Slic3r::Polylines intersection_pl(const Slic3r::Polyline &subject, const Slic3r::Polygons &clip)
{ return _clipper_pl_open(ClipperLib::ctIntersection, ClipperUtils::SinglePathProvider(subject.points), ClipperUtils::PolygonsProvider(clip)); }
+Slic3r::Polylines intersection_pl(const Slic3r::Polyline &subject, const Slic3r::ExPolygons &clip)
+ { return _clipper_pl_open(ClipperLib::ctIntersection, ClipperUtils::SinglePathProvider(subject.points), ClipperUtils::ExPolygonsProvider(clip)); }
Slic3r::Polylines intersection_pl(const Slic3r::Polylines &subject, const Slic3r::Polygons &clip)
{ return _clipper_pl_open(ClipperLib::ctIntersection, ClipperUtils::PolylinesProvider(subject), ClipperUtils::PolygonsProvider(clip)); }
Slic3r::Polylines intersection_pl(const Slic3r::Polylines &subject, const Slic3r::ExPolygons &clip)
diff --git a/src/libslic3r/ClipperUtils.hpp b/src/libslic3r/ClipperUtils.hpp
index d7027e0ec8..484229f723 100644
--- a/src/libslic3r/ClipperUtils.hpp
+++ b/src/libslic3r/ClipperUtils.hpp
@@ -1,17 +1,27 @@
#ifndef slic3r_ClipperUtils_hpp_
#define slic3r_ClipperUtils_hpp_
+//#define SLIC3R_USE_CLIPPER2
+
#include "libslic3r.h"
-#include "clipper.hpp"
#include "ExPolygon.hpp"
#include "Polygon.hpp"
#include "Surface.hpp"
+#ifdef SLIC3R_USE_CLIPPER2
+
+#include
+
+#else /* SLIC3R_USE_CLIPPER2 */
+
+#include "clipper.hpp"
// import these wherever we're included
using Slic3r::ClipperLib::jtMiter;
using Slic3r::ClipperLib::jtRound;
using Slic3r::ClipperLib::jtSquare;
+#endif /* SLIC3R_USE_CLIPPER2 */
+
namespace Slic3r {
static constexpr const float ClipperSafetyOffset = 10.f;
@@ -298,9 +308,6 @@ namespace ClipperUtils {
};
}
-// Perform union of input polygons using the non-zero rule, convert to ExPolygons.
-ExPolygons ClipperPaths_to_Slic3rExPolygons(const ClipperLib::Paths &input, bool do_union = false);
-
// offset Polygons
// Wherever applicable, please use the expand() / shrink() variants instead, they convey their purpose better.
Slic3r::Polygons offset(const Slic3r::Polygon &polygon, const float delta, ClipperLib::JoinType joinType = DefaultJoinType, double miterLimit = DefaultMiterLimit);
@@ -429,6 +436,7 @@ Slic3r::ExPolygons intersection_ex(const Slic3r::Surfaces &subject, const Slic3r
Slic3r::ExPolygons intersection_ex(const Slic3r::SurfacesPtr &subject, const Slic3r::ExPolygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
Slic3r::Polylines intersection_pl(const Slic3r::Polylines &subject, const Slic3r::Polygon &clip);
Slic3r::Polylines intersection_pl(const Slic3r::Polyline &subject, const Slic3r::Polygons &clip);
+Slic3r::Polylines intersection_pl(const Slic3r::Polyline &subject, const Slic3r::ExPolygons &clip);
Slic3r::Polylines intersection_pl(const Slic3r::Polylines &subject, const Slic3r::Polygons &clip);
Slic3r::Polylines intersection_pl(const Slic3r::Polylines &subject, const Slic3r::ExPolygons &clip);
Slic3r::Polylines intersection_pl(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip);
diff --git a/src/libslic3r/EdgeGrid.cpp b/src/libslic3r/EdgeGrid.cpp
index 1385a51d8d..4985b788e4 100644
--- a/src/libslic3r/EdgeGrid.cpp
+++ b/src/libslic3r/EdgeGrid.cpp
@@ -136,11 +136,6 @@ void EdgeGrid::Grid::create(const ExPolygons &expolygons, coord_t resolution)
create_from_m_contours(resolution);
}
-void EdgeGrid::Grid::create(const ExPolygonCollection &expolygons, coord_t resolution)
-{
- create(expolygons.expolygons, resolution);
-}
-
// m_contours has been initialized. Now fill in the edge grid.
void EdgeGrid::Grid::create_from_m_contours(coord_t resolution)
{
diff --git a/src/libslic3r/EdgeGrid.hpp b/src/libslic3r/EdgeGrid.hpp
index 3c99291498..4be2bdd07c 100644
--- a/src/libslic3r/EdgeGrid.hpp
+++ b/src/libslic3r/EdgeGrid.hpp
@@ -7,7 +7,6 @@
#include "Point.hpp"
#include "BoundingBox.hpp"
#include "ExPolygon.hpp"
-#include "ExPolygonCollection.hpp"
namespace Slic3r {
namespace EdgeGrid {
@@ -112,7 +111,6 @@ public:
void create(const std::vector &polygons, coord_t resolution) { this->create(polygons, resolution, false); }
void create(const ExPolygon &expoly, coord_t resolution);
void create(const ExPolygons &expolygons, coord_t resolution);
- void create(const ExPolygonCollection &expolygons, coord_t resolution);
const std::vector& contours() const { return m_contours; }
@@ -123,7 +121,6 @@ public:
bool intersect(const Polygons &polygons) { for (size_t i = 0; i < polygons.size(); ++ i) if (intersect(polygons[i])) return true; return false; }
bool intersect(const ExPolygon &expoly) { if (intersect(expoly.contour)) return true; for (size_t i = 0; i < expoly.holes.size(); ++ i) if (intersect(expoly.holes[i])) return true; return false; }
bool intersect(const ExPolygons &expolygons) { for (size_t i = 0; i < expolygons.size(); ++ i) if (intersect(expolygons[i])) return true; return false; }
- bool intersect(const ExPolygonCollection &expolygons) { return intersect(expolygons.expolygons); }
// Test, whether a point is inside a contour.
bool inside(const Point &pt);
@@ -391,7 +388,7 @@ protected:
// Referencing the source contours.
// This format allows one to work with any Slic3r fixed point contour format
- // (Polygon, ExPolygon, ExPolygonCollection etc).
+ // (Polygon, ExPolygon, ExPolygons etc).
std::vector m_contours;
// Referencing a contour and a line segment of m_contours.
diff --git a/src/libslic3r/ExPolygon.hpp b/src/libslic3r/ExPolygon.hpp
index cbf6b1c1a2..344450c4a9 100644
--- a/src/libslic3r/ExPolygon.hpp
+++ b/src/libslic3r/ExPolygon.hpp
@@ -9,7 +9,7 @@
namespace Slic3r {
class ExPolygon;
-typedef std::vector ExPolygons;
+using ExPolygons = std::vector;
class ExPolygon
{
diff --git a/src/libslic3r/ExPolygonCollection.cpp b/src/libslic3r/ExPolygonCollection.cpp
deleted file mode 100644
index a0de8f6de6..0000000000
--- a/src/libslic3r/ExPolygonCollection.cpp
+++ /dev/null
@@ -1,136 +0,0 @@
-#include "ExPolygonCollection.hpp"
-#include "Geometry/ConvexHull.hpp"
-#include "BoundingBox.hpp"
-
-namespace Slic3r {
-
-ExPolygonCollection::ExPolygonCollection(const ExPolygon &expolygon)
-{
- this->expolygons.push_back(expolygon);
-}
-
-ExPolygonCollection::operator Points() const
-{
- Points points;
- Polygons pp = (Polygons)*this;
- for (Polygons::const_iterator poly = pp.begin(); poly != pp.end(); ++poly) {
- for (Points::const_iterator point = poly->points.begin(); point != poly->points.end(); ++point)
- points.push_back(*point);
- }
- return points;
-}
-
-ExPolygonCollection::operator Polygons() const
-{
- Polygons polygons;
- for (ExPolygons::const_iterator it = this->expolygons.begin(); it != this->expolygons.end(); ++it) {
- polygons.push_back(it->contour);
- for (Polygons::const_iterator ith = it->holes.begin(); ith != it->holes.end(); ++ith) {
- polygons.push_back(*ith);
- }
- }
- return polygons;
-}
-
-ExPolygonCollection::operator ExPolygons&()
-{
- return this->expolygons;
-}
-
-void
-ExPolygonCollection::scale(double factor)
-{
- for (ExPolygons::iterator it = expolygons.begin(); it != expolygons.end(); ++it) {
- (*it).scale(factor);
- }
-}
-
-void
-ExPolygonCollection::translate(double x, double y)
-{
- for (ExPolygons::iterator it = expolygons.begin(); it != expolygons.end(); ++it) {
- (*it).translate(x, y);
- }
-}
-
-void
-ExPolygonCollection::rotate(double angle, const Point ¢er)
-{
- for (ExPolygons::iterator it = expolygons.begin(); it != expolygons.end(); ++it) {
- (*it).rotate(angle, center);
- }
-}
-
-template
-bool ExPolygonCollection::contains(const T &item) const
-{
- for (const ExPolygon &poly : this->expolygons)
- if (poly.contains(item))
- return true;
- return false;
-}
-template bool ExPolygonCollection::contains(const Point &item) const;
-template bool ExPolygonCollection::contains(const Line &item) const;
-template bool ExPolygonCollection::contains(const Polyline &item) const;
-
-bool
-ExPolygonCollection::contains_b(const Point &point) const
-{
- for (ExPolygons::const_iterator it = this->expolygons.begin(); it != this->expolygons.end(); ++it) {
- if (it->contains_b(point)) return true;
- }
- return false;
-}
-
-void
-ExPolygonCollection::simplify(double tolerance)
-{
- ExPolygons expp;
- for (ExPolygons::const_iterator it = this->expolygons.begin(); it != this->expolygons.end(); ++it) {
- it->simplify(tolerance, &expp);
- }
- this->expolygons = expp;
-}
-
-Polygon
-ExPolygonCollection::convex_hull() const
-{
- Points pp;
- for (ExPolygons::const_iterator it = this->expolygons.begin(); it != this->expolygons.end(); ++it)
- pp.insert(pp.end(), it->contour.points.begin(), it->contour.points.end());
- return Slic3r::Geometry::convex_hull(pp);
-}
-
-Lines
-ExPolygonCollection::lines() const
-{
- Lines lines;
- for (ExPolygons::const_iterator it = this->expolygons.begin(); it != this->expolygons.end(); ++it) {
- Lines ex_lines = it->lines();
- lines.insert(lines.end(), ex_lines.begin(), ex_lines.end());
- }
- return lines;
-}
-
-Polygons
-ExPolygonCollection::contours() const
-{
- Polygons contours;
- contours.reserve(this->expolygons.size());
- for (ExPolygons::const_iterator it = this->expolygons.begin(); it != this->expolygons.end(); ++it)
- contours.push_back(it->contour);
- return contours;
-}
-
-void
-ExPolygonCollection::append(const ExPolygons &expp)
-{
- this->expolygons.insert(this->expolygons.end(), expp.begin(), expp.end());
-}
-
-BoundingBox get_extents(const ExPolygonCollection &expolygon)
-{
- return get_extents(expolygon.expolygons);
-}
-
-}
diff --git a/src/libslic3r/ExPolygonCollection.hpp b/src/libslic3r/ExPolygonCollection.hpp
deleted file mode 100644
index 35e1eef4eb..0000000000
--- a/src/libslic3r/ExPolygonCollection.hpp
+++ /dev/null
@@ -1,41 +0,0 @@
-#ifndef slic3r_ExPolygonCollection_hpp_
-#define slic3r_ExPolygonCollection_hpp_
-
-#include "libslic3r.h"
-#include "ExPolygon.hpp"
-#include "Line.hpp"
-#include "Polyline.hpp"
-
-namespace Slic3r {
-
-class ExPolygonCollection;
-typedef std::vector ExPolygonCollections;
-
-class ExPolygonCollection
-{
-public:
- ExPolygons expolygons;
-
- ExPolygonCollection() {}
- explicit ExPolygonCollection(const ExPolygon &expolygon);
- explicit ExPolygonCollection(const ExPolygons &expolygons) : expolygons(expolygons) {}
- explicit operator Points() const;
- explicit operator Polygons() const;
- explicit operator ExPolygons&();
- void scale(double factor);
- void translate(double x, double y);
- void rotate(double angle, const Point ¢er);
- template bool contains(const T &item) const;
- bool contains_b(const Point &point) const;
- void simplify(double tolerance);
- Polygon convex_hull() const;
- Lines lines() const;
- Polygons contours() const;
- void append(const ExPolygons &expolygons);
-};
-
-extern BoundingBox get_extents(const ExPolygonCollection &expolygon);
-
-}
-
-#endif
diff --git a/src/libslic3r/ExtrusionEntity.cpp b/src/libslic3r/ExtrusionEntity.cpp
index 7b2506a221..0c11653165 100644
--- a/src/libslic3r/ExtrusionEntity.cpp
+++ b/src/libslic3r/ExtrusionEntity.cpp
@@ -1,6 +1,6 @@
#include "ExtrusionEntity.hpp"
#include "ExtrusionEntityCollection.hpp"
-#include "ExPolygonCollection.hpp"
+#include "ExPolygon.hpp"
#include "ClipperUtils.hpp"
#include "Extruder.hpp"
#include "Flow.hpp"
@@ -12,14 +12,14 @@
namespace Slic3r {
-void ExtrusionPath::intersect_expolygons(const ExPolygonCollection &collection, ExtrusionEntityCollection* retval) const
+void ExtrusionPath::intersect_expolygons(const ExPolygons &collection, ExtrusionEntityCollection* retval) const
{
- this->_inflate_collection(intersection_pl(Polylines{ polyline }, collection.expolygons), retval);
+ this->_inflate_collection(intersection_pl(Polylines{ polyline }, collection), retval);
}
-void ExtrusionPath::subtract_expolygons(const ExPolygonCollection &collection, ExtrusionEntityCollection* retval) const
+void ExtrusionPath::subtract_expolygons(const ExPolygons &collection, ExtrusionEntityCollection* retval) const
{
- this->_inflate_collection(diff_pl(Polylines{ this->polyline }, collection.expolygons), retval);
+ this->_inflate_collection(diff_pl(Polylines{ this->polyline }, collection), retval);
}
void ExtrusionPath::clip_end(double distance)
diff --git a/src/libslic3r/ExtrusionEntity.hpp b/src/libslic3r/ExtrusionEntity.hpp
index 2e9e467890..52a8a563ce 100644
--- a/src/libslic3r/ExtrusionEntity.hpp
+++ b/src/libslic3r/ExtrusionEntity.hpp
@@ -11,7 +11,8 @@
namespace Slic3r {
-class ExPolygonCollection;
+class ExPolygon;
+using ExPolygons = std::vector;
class ExtrusionEntityCollection;
class Extruder;
@@ -144,12 +145,12 @@ public:
size_t size() const { return this->polyline.size(); }
bool empty() const { return this->polyline.empty(); }
bool is_closed() const { return ! this->empty() && this->polyline.points.front() == this->polyline.points.back(); }
- // Produce a list of extrusion paths into retval by clipping this path by ExPolygonCollection.
+ // Produce a list of extrusion paths into retval by clipping this path by ExPolygons.
// Currently not used.
- void intersect_expolygons(const ExPolygonCollection &collection, ExtrusionEntityCollection* retval) const;
- // Produce a list of extrusion paths into retval by removing parts of this path by ExPolygonCollection.
+ void intersect_expolygons(const ExPolygons &collection, ExtrusionEntityCollection* retval) const;
+ // Produce a list of extrusion paths into retval by removing parts of this path by ExPolygons.
// Currently not used.
- void subtract_expolygons(const ExPolygonCollection &collection, ExtrusionEntityCollection* retval) const;
+ void subtract_expolygons(const ExPolygons &collection, ExtrusionEntityCollection* retval) const;
void clip_end(double distance);
void simplify(double tolerance);
double length() const override;
diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp
index 1a6ee4b807..aef83f21f4 100644
--- a/src/libslic3r/GCode.cpp
+++ b/src/libslic3r/GCode.cpp
@@ -3063,7 +3063,7 @@ bool GCode::needs_retraction(const Polyline &travel, ExtrusionRole role)
if (role == erSupportMaterial) {
const SupportLayer* support_layer = dynamic_cast(m_layer);
//FIXME support_layer->support_islands.contains should use some search structure!
- if (support_layer != NULL && support_layer->support_islands.contains(travel))
+ if (support_layer != NULL && ! intersection_pl(travel, support_layer->support_islands).empty())
// skip retraction if this is a travel move inside a support material island
//FIXME not retracting over a long path may cause oozing, which in turn may result in missing material
// at the end of the extrusion path!
diff --git a/src/libslic3r/GCodeReader.cpp b/src/libslic3r/GCodeReader.cpp
index c8a9b790fc..44b0b89f60 100644
--- a/src/libslic3r/GCodeReader.cpp
+++ b/src/libslic3r/GCodeReader.cpp
@@ -215,9 +215,9 @@ bool GCodeReader::parse_file_raw(const std::string &filename, raw_line_callback_
[](size_t){});
}
-bool GCodeReader::GCodeLine::has(char axis) const
+const char* GCodeReader::axis_pos(const char *raw_str, char axis)
{
- const char *c = m_raw.c_str();
+ const char *c = raw_str;
// Skip the whitespaces.
c = skip_whitespaces(c);
// Skip the command.
@@ -230,40 +230,48 @@ bool GCodeReader::GCodeLine::has(char axis) const
break;
// Check the name of the axis.
if (*c == axis)
- return true;
+ return c;
// Skip the rest of the word.
c = skip_word(c);
}
- return false;
+ return nullptr;
+}
+
+bool GCodeReader::GCodeLine::has(char axis) const
+{
+ const char *c = axis_pos(m_raw.c_str(), axis);
+ return c != nullptr;
}
bool GCodeReader::GCodeLine::has_value(char axis, float &value) const
{
assert(is_decimal_separator_point());
- const char *c = m_raw.c_str();
- // Skip the whitespaces.
- c = skip_whitespaces(c);
- // Skip the command.
- c = skip_word(c);
- // Up to the end of line or comment.
- while (! is_end_of_gcode_line(*c)) {
- // Skip whitespaces.
- c = skip_whitespaces(c);
- if (is_end_of_gcode_line(*c))
- break;
- // Check the name of the axis.
- if (*c == axis) {
- // Try to parse the numeric value.
- char *pend = nullptr;
- double v = strtod(++ c, &pend);
- if (pend != nullptr && is_end_of_word(*pend)) {
- // The axis value has been parsed correctly.
- value = float(v);
- return true;
- }
- }
- // Skip the rest of the word.
- c = skip_word(c);
+ const char *c = axis_pos(m_raw.c_str(), axis);
+ if (c == nullptr)
+ return false;
+ // Try to parse the numeric value.
+ char *pend = nullptr;
+ double v = strtod(++ c, &pend);
+ if (pend != nullptr && is_end_of_word(*pend)) {
+ // The axis value has been parsed correctly.
+ value = float(v);
+ return true;
+ }
+ return false;
+}
+
+bool GCodeReader::GCodeLine::has_value(char axis, int &value) const
+{
+ const char *c = axis_pos(m_raw.c_str(), axis);
+ if (c == nullptr)
+ return false;
+ // Try to parse the numeric value.
+ char *pend = nullptr;
+ long v = strtol(++ c, &pend, 10);
+ if (pend != nullptr && is_end_of_word(*pend)) {
+ // The axis value has been parsed correctly.
+ value = int(v);
+ return true;
}
return false;
}
diff --git a/src/libslic3r/GCodeReader.hpp b/src/libslic3r/GCodeReader.hpp
index 40a0992292..25ba6ee0ba 100644
--- a/src/libslic3r/GCodeReader.hpp
+++ b/src/libslic3r/GCodeReader.hpp
@@ -30,6 +30,7 @@ public:
float value(Axis axis) const { return m_axis[axis]; }
bool has(char axis) const;
bool has_value(char axis, float &value) const;
+ bool has_value(char axis, int &value) const;
float new_X(const GCodeReader &reader) const { return this->has(X) ? this->x() : reader.x(); }
float new_Y(const GCodeReader &reader) const { return this->has(Y) ? this->y() : reader.y(); }
float new_Z(const GCodeReader &reader) const { return this->has(Z) ? this->z() : reader.z(); }
@@ -166,6 +167,7 @@ private:
; // silence -Wempty-body
return c;
}
+ static const char* axis_pos(const char *raw_str, char axis);
GCodeConfig m_config;
char m_extrusion_axis;
diff --git a/src/libslic3r/Geometry.cpp b/src/libslic3r/Geometry.cpp
index 937be67392..031e489f70 100644
--- a/src/libslic3r/Geometry.cpp
+++ b/src/libslic3r/Geometry.cpp
@@ -50,13 +50,6 @@ bool contains(const std::vector &vector, const Point &point)
}
template bool contains(const ExPolygons &vector, const Point &point);
-double rad2deg_dir(double angle)
-{
- angle = (angle < PI) ? (-angle + PI/2.0) : (angle + PI/2.0);
- if (angle < 0) angle += PI;
- return rad2deg(angle);
-}
-
void simplify_polygons(const Polygons &polygons, double tolerance, Polygons* retval)
{
Polygons pp;
diff --git a/src/libslic3r/Geometry.hpp b/src/libslic3r/Geometry.hpp
index 2cb9a35df7..bd8326bb65 100644
--- a/src/libslic3r/Geometry.hpp
+++ b/src/libslic3r/Geometry.hpp
@@ -291,7 +291,6 @@ bool directions_parallel(double angle1, double angle2, double max_diff = 0);
bool directions_perpendicular(double angle1, double angle2, double max_diff = 0);
template bool contains(const std::vector &vector, const Point &point);
template T rad2deg(T angle) { return T(180.0) * angle / T(PI); }
-double rad2deg_dir(double angle);
template constexpr T deg2rad(const T angle) { return T(PI) * angle / T(180.0); }
template T angle_to_0_2PI(T angle)
{
diff --git a/src/libslic3r/Geometry/ConvexHull.cpp b/src/libslic3r/Geometry/ConvexHull.cpp
index 2e92535f2d..9601069b5e 100644
--- a/src/libslic3r/Geometry/ConvexHull.cpp
+++ b/src/libslic3r/Geometry/ConvexHull.cpp
@@ -104,6 +104,17 @@ Polygon convex_hull(const Polygons &polygons)
return convex_hull(std::move(pp));
}
+Polygon convex_hull(const ExPolygons &expolygons)
+{
+ Points pp;
+ size_t sz = 0;
+ for (const auto &expoly : expolygons)
+ sz += expoly.contour.size();
+ pp.reserve(sz);
+ for (const auto &expoly : expolygons)
+ pp.insert(pp.end(), expoly.contour.points.begin(), expoly.contour.points.end());
+ return convex_hull(pp);
+}
namespace rotcalip {
diff --git a/src/libslic3r/Geometry/ConvexHull.hpp b/src/libslic3r/Geometry/ConvexHull.hpp
index 03f00af6ae..9ba957824e 100644
--- a/src/libslic3r/Geometry/ConvexHull.hpp
+++ b/src/libslic3r/Geometry/ConvexHull.hpp
@@ -9,6 +9,7 @@ namespace Geometry {
Pointf3s convex_hull(Pointf3s points);
Polygon convex_hull(Points points);
Polygon convex_hull(const Polygons &polygons);
+Polygon convex_hull(const ExPolygons &expolygons);
// Returns true if the intersection of the two convex polygons A and B
// is not an empty set.
diff --git a/src/libslic3r/Layer.hpp b/src/libslic3r/Layer.hpp
index 0fe4952f4a..2e3affec7b 100644
--- a/src/libslic3r/Layer.hpp
+++ b/src/libslic3r/Layer.hpp
@@ -5,10 +5,11 @@
#include "Flow.hpp"
#include "SurfaceCollection.hpp"
#include "ExtrusionEntityCollection.hpp"
-#include "ExPolygonCollection.hpp"
namespace Slic3r {
+class ExPolygon;
+using ExPolygons = std::vector;
class Layer;
using LayerPtrs = std::vector;
class LayerRegion;
@@ -191,7 +192,7 @@ class SupportLayer : public Layer
public:
// Polygons covered by the supports: base, interface and contact areas.
// Used to suppress retraction if moving for a support extrusion over these support_islands.
- ExPolygonCollection support_islands;
+ ExPolygons support_islands;
// Extrusion paths for the support base and for the support interface and contacts.
ExtrusionEntityCollection support_fills;
diff --git a/src/libslic3r/Polyline.cpp b/src/libslic3r/Polyline.cpp
index 1255d5473d..6994ef4251 100644
--- a/src/libslic3r/Polyline.cpp
+++ b/src/libslic3r/Polyline.cpp
@@ -2,7 +2,6 @@
#include "Polyline.hpp"
#include "Exception.hpp"
#include "ExPolygon.hpp"
-#include "ExPolygonCollection.hpp"
#include "Line.hpp"
#include "Polygon.hpp"
#include
@@ -196,7 +195,7 @@ BoundingBox get_extents(const Polylines &polylines)
const Point& leftmost_point(const Polylines &polylines)
{
if (polylines.empty())
- throw Slic3r::InvalidArgument("leftmost_point() called on empty PolylineCollection");
+ throw Slic3r::InvalidArgument("leftmost_point() called on empty Polylines");
Polylines::const_iterator it = polylines.begin();
const Point *p = &it->leftmost_point();
for (++ it; it != polylines.end(); ++it) {
diff --git a/src/libslic3r/Polyline.hpp b/src/libslic3r/Polyline.hpp
index 256dca28cc..e0379e8697 100644
--- a/src/libslic3r/Polyline.hpp
+++ b/src/libslic3r/Polyline.hpp
@@ -80,15 +80,6 @@ public:
inline bool operator==(const Polyline &lhs, const Polyline &rhs) { return lhs.points == rhs.points; }
inline bool operator!=(const Polyline &lhs, const Polyline &rhs) { return lhs.points != rhs.points; }
-// Don't use this class in production code, it is used exclusively by the Perl binding for unit tests!
-#ifdef PERL_UCHAR_MIN
-class PolylineCollection
-{
-public:
- Polylines polylines;
-};
-#endif /* PERL_UCHAR_MIN */
-
extern BoundingBox get_extents(const Polyline &polyline);
extern BoundingBox get_extents(const Polylines &polylines);
diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp
index 950816fa91..ab12bc8ce2 100644
--- a/src/libslic3r/PrintConfig.hpp
+++ b/src/libslic3r/PrintConfig.hpp
@@ -197,7 +197,6 @@ double min_object_distance(const ConfigBase &cfg);
// The dynamic configuration is also used to store user modifications of the print global parameters,
// so the modified configuration values may be diffed against the active configuration
// to invalidate the proper slicing resp. g-code generation processing steps.
-// This object is mapped to Perl as Slic3r::Config.
class DynamicPrintConfig : public DynamicConfig
{
public:
@@ -211,6 +210,16 @@ public:
DynamicPrintConfig& operator=(DynamicPrintConfig &&rhs) noexcept { DynamicConfig::operator=(std::move(rhs)); return *this; }
static DynamicPrintConfig full_print_config();
+ static DynamicPrintConfig full_print_config_with(const t_config_option_key &opt_key, const std::string &str, bool append = false) {
+ auto config = DynamicPrintConfig::full_print_config();
+ config.set_deserialize_strict(opt_key, str, append);
+ return config;
+ }
+ static DynamicPrintConfig full_print_config_with(std::initializer_list items) {
+ auto config = DynamicPrintConfig::full_print_config();
+ config.set_deserialize_strict(items);
+ return config;
+ }
static DynamicPrintConfig* new_from_defaults_keys(const std::vector &keys);
// Overrides ConfigBase::def(). Static configuration definition. Any value stored into this ConfigBase shall have its definition here.
@@ -454,7 +463,6 @@ protected: \
BOOST_PP_SEQ_FOR_EACH(PRINT_CONFIG_CLASS_ELEMENT_HASH, _, PARAMETER_DEFINITION_SEQ), \
BOOST_PP_SEQ_FOR_EACH(PRINT_CONFIG_CLASS_ELEMENT_EQUAL, _, PARAMETER_DEFINITION_SEQ))
-// This object is mapped to Perl as Slic3r::Config::PrintObject.
PRINT_CONFIG_CLASS_DEFINE(
PrintObjectConfig,
@@ -518,7 +526,6 @@ PRINT_CONFIG_CLASS_DEFINE(
((ConfigOptionBool, wipe_into_objects))
)
-// This object is mapped to Perl as Slic3r::Config::PrintRegion.
PRINT_CONFIG_CLASS_DEFINE(
PrintRegionConfig,
@@ -609,7 +616,6 @@ PRINT_CONFIG_CLASS_DEFINE(
((ConfigOptionFloats, machine_min_extruding_rate))
)
-// This object is mapped to Perl as Slic3r::Config::GCode.
PRINT_CONFIG_CLASS_DEFINE(
GCodeConfig,
@@ -695,7 +701,6 @@ static inline std::string get_extrusion_axis(const GCodeConfig &cfg)
(cfg.gcode_flavor.value == gcfNoExtrusion) ? "" : cfg.extrusion_axis.value;
}
-// This object is mapped to Perl as Slic3r::Config::Print.
PRINT_CONFIG_CLASS_DERIVED_DEFINE(
PrintConfig,
(MachineEnvelopeConfig, GCodeConfig),
@@ -774,7 +779,6 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE(
((ConfigOptionFloat, z_offset))
)
-// This object is mapped to Perl as Slic3r::Config::Full.
PRINT_CONFIG_CLASS_DERIVED_DEFINE0(
FullPrintConfig,
(PrintObjectConfig, PrintRegionConfig, PrintConfig)
diff --git a/src/libslic3r/SLA/SupportPointGenerator.cpp b/src/libslic3r/SLA/SupportPointGenerator.cpp
index c32da04319..4c1af03eb4 100644
--- a/src/libslic3r/SLA/SupportPointGenerator.cpp
+++ b/src/libslic3r/SLA/SupportPointGenerator.cpp
@@ -1,17 +1,14 @@
-//#include "igl/random_points_on_mesh.h"
-//#include "igl/AABB.h"
-
#include
#include "SupportPointGenerator.hpp"
#include "Concurrency.hpp"
+#include "Geometry/ConvexHull.hpp"
#include "Model.hpp"
#include "ExPolygon.hpp"
#include "SVG.hpp"
#include "Point.hpp"
#include "ClipperUtils.hpp"
#include "Tesselate.hpp"
-#include "ExPolygonCollection.hpp"
#include "MinAreaBoundingBox.hpp"
#include "libslic3r.h"
@@ -550,7 +547,7 @@ void SupportPointGenerator::uniformly_cover(const ExPolygons& islands, Structure
// auto bb = get_extents(islands);
if (flags & icfIsNew) {
- auto chull = ExPolygonCollection{islands}.convex_hull();
+ auto chull = Geometry::convex_hull(islands);
auto rotbox = MinAreaBoundigBox{chull, MinAreaBoundigBox::pcConvex};
Vec2d bbdim = {unscaled(rotbox.width()), unscaled(rotbox.height())};
diff --git a/src/libslic3r/SupportMaterial.cpp b/src/libslic3r/SupportMaterial.cpp
index 195fc9e172..52cb177bb8 100644
--- a/src/libslic3r/SupportMaterial.cpp
+++ b/src/libslic3r/SupportMaterial.cpp
@@ -4283,7 +4283,7 @@ void PrintObjectSupportMaterial::generate_toolpaths(
std::stable_sort(layer_cache_item.overlapping.begin(), layer_cache_item.overlapping.end(), [](auto *l1, auto *l2) { return *l1 < *l2; });
}
if (! polys.empty())
- expolygons_append(support_layer.support_islands.expolygons, union_ex(polys));
+ expolygons_append(support_layer.support_islands, union_ex(polys));
} // for each support_layer_id
});
diff --git a/src/libslic3r/Utils.hpp b/src/libslic3r/Utils.hpp
index 10790ef491..6a09e7fbf7 100644
--- a/src/libslic3r/Utils.hpp
+++ b/src/libslic3r/Utils.hpp
@@ -18,7 +18,6 @@ namespace Slic3r {
extern void set_logging_level(unsigned int level);
extern unsigned get_logging_level();
-extern void trace(unsigned int level, const char *message);
// Format memory allocated, separate thousands by comma.
extern std::string format_memsize_MB(size_t n);
// Return string to be added to the boost::log output to inform about the current process memory allocation.
@@ -68,13 +67,6 @@ std::string debug_out_path(const char *name, ...);
// This type is only needed for Perl bindings to relay to Perl that the string is raw, not UTF-8 encoded.
typedef std::string local_encoded_string;
-// Convert an UTF-8 encoded string into local coding.
-// On Windows, the UTF-8 string is converted to a local 8-bit code page.
-// On OSX and Linux, this function does no conversion and returns a copy of the source string.
-extern local_encoded_string encode_path(const char *src);
-extern std::string decode_path(const char *src);
-extern std::string normalize_utf8_nfc(const char *src);
-
// Returns next utf8 sequence length. =number of bytes in string, that creates together one utf-8 character.
// Starting at pos. ASCII characters returns 1. Works also if pos is in the middle of the sequence.
extern size_t get_utf8_sequence_length(const std::string& text, size_t pos = 0);
@@ -115,19 +107,6 @@ extern bool is_gallery_file(const boost::filesystem::directory_entry& path, char
extern bool is_gallery_file(const std::string& path, char const* type);
extern bool is_shapes_dir(const std::string& dir);
-// File path / name / extension splitting utilities, working with UTF-8,
-// to be published to Perl.
-namespace PerlUtils {
- // Get a file name including the extension.
- extern std::string path_to_filename(const char *src);
- // Get a file name without the extension.
- extern std::string path_to_stem(const char *src);
- // Get just the extension.
- extern std::string path_to_extension(const char *src);
- // Get a directory without the trailing slash.
- extern std::string path_to_parent_path(const char *src);
-};
-
std::string string_printf(const char *format, ...);
// Standard "generated by Slic3r version xxx timestamp xxx" header string,
diff --git a/src/libslic3r/utils.cpp b/src/libslic3r/utils.cpp
index ddc9a4081f..371b8eb115 100644
--- a/src/libslic3r/utils.cpp
+++ b/src/libslic3r/utils.cpp
@@ -125,14 +125,6 @@ static struct RunOnInit {
}
} g_RunOnInit;
-void trace(unsigned int level, const char *message)
-{
- boost::log::trivial::severity_level severity = level_to_boost(level);
-
- BOOST_LOG_STREAM_WITH_PARAMS(::boost::log::trivial::logger::get(),\
- (::boost::log::keywords::severity = severity)) << message;
-}
-
void disable_multi_threading()
{
// Disable parallelization so the Shiny profiler works
@@ -820,49 +812,6 @@ bool is_shapes_dir(const std::string& dir)
namespace Slic3r {
-// Encode an UTF-8 string to the local code page.
-std::string encode_path(const char *src)
-{
-#ifdef WIN32
- // Convert the source utf8 encoded string to a wide string.
- std::wstring wstr_src = boost::nowide::widen(src);
- if (wstr_src.length() == 0)
- return std::string();
- // Convert a wide string to a local code page.
- int size_needed = ::WideCharToMultiByte(0, 0, wstr_src.data(), (int)wstr_src.size(), nullptr, 0, nullptr, nullptr);
- std::string str_dst(size_needed, 0);
- ::WideCharToMultiByte(0, 0, wstr_src.data(), (int)wstr_src.size(), str_dst.data(), size_needed, nullptr, nullptr);
- return str_dst;
-#else /* WIN32 */
- return src;
-#endif /* WIN32 */
-}
-
-// Encode an 8-bit string from a local code page to UTF-8.
-// Multibyte to utf8
-std::string decode_path(const char *src)
-{
-#ifdef WIN32
- int len = int(strlen(src));
- if (len == 0)
- return std::string();
- // Convert the string encoded using the local code page to a wide string.
- int size_needed = ::MultiByteToWideChar(0, 0, src, len, nullptr, 0);
- std::wstring wstr_dst(size_needed, 0);
- ::MultiByteToWideChar(0, 0, src, len, wstr_dst.data(), size_needed);
- // Convert a wide string to utf8.
- return boost::nowide::narrow(wstr_dst.c_str());
-#else /* WIN32 */
- return src;
-#endif /* WIN32 */
-}
-
-std::string normalize_utf8_nfc(const char *src)
-{
- static std::locale locale_utf8(boost::locale::generator().generate(""));
- return boost::locale::normalize(src, boost::locale::norm_nfc, locale_utf8);
-}
-
size_t get_utf8_sequence_length(const std::string& text, size_t pos)
{
assert(pos < text.size());
@@ -933,18 +882,6 @@ size_t get_utf8_sequence_length(const char *seq, size_t size)
return length;
}
-namespace PerlUtils {
- // Get a file name including the extension.
- std::string path_to_filename(const char *src) { return boost::filesystem::path(src).filename().string(); }
- // Get a file name without the extension.
- std::string path_to_stem(const char *src) { return boost::filesystem::path(src).stem().string(); }
- // Get just the extension.
- std::string path_to_extension(const char *src) { return boost::filesystem::path(src).extension().string(); }
- // Get a directory without the trailing slash.
- std::string path_to_parent_path(const char *src) { return boost::filesystem::path(src).parent_path().string(); }
-};
-
-
std::string string_printf(const char *format, ...)
{
va_list args1;
diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp
index 86394819e7..96151d8c7f 100644
--- a/src/slic3r/GUI/Tab.cpp
+++ b/src/slic3r/GUI/Tab.cpp
@@ -3481,6 +3481,28 @@ void Tab::activate_selected_page(std::function throw_if_canceled)
toggle_options();
}
+#ifdef WIN32
+// Override the wxCheckForInterrupt to process inperruptions just from key or mouse
+// and to avoid an unwanted early call of CallAfter()
+static bool CheckForInterrupt(wxWindow* wnd)
+{
+ wxCHECK(wnd, false);
+
+ MSG msg;
+ while (::PeekMessage(&msg, ((HWND)((wnd)->GetHWND())), WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
+ {
+ ::TranslateMessage(&msg);
+ ::DispatchMessage(&msg);
+ }
+ while (::PeekMessage(&msg, ((HWND)((wnd)->GetHWND())), WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE))
+ {
+ ::TranslateMessage(&msg);
+ ::DispatchMessage(&msg);
+ }
+ return true;
+}
+#endif //WIN32
+
bool Tab::tree_sel_change_delayed()
{
// There is a bug related to Ubuntu overlay scrollbars, see https://github.com/prusa3d/PrusaSlicer/issues/898 and https://github.com/prusa3d/PrusaSlicer/issues/952.
@@ -3517,7 +3539,7 @@ bool Tab::tree_sel_change_delayed()
auto throw_if_canceled = std::function([this](){
#ifdef WIN32
- wxCheckForInterrupt(m_treectrl);
+ CheckForInterrupt(m_treectrl);
if (m_page_switch_planned)
throw UIBuildCanceled();
#else // WIN32
diff --git a/t/angles.t b/t/angles.t
deleted file mode 100644
index 9dc690dea7..0000000000
--- a/t/angles.t
+++ /dev/null
@@ -1,93 +0,0 @@
-use Test::More;
-use strict;
-use warnings;
-
-plan tests => 34;
-
-BEGIN {
- use FindBin;
- use lib "$FindBin::Bin/../lib";
- use local::lib "$FindBin::Bin/../local-lib";
-}
-
-use Slic3r;
-use Slic3r::Geometry qw(rad2deg_dir angle3points PI);
-
-#==========================================================
-
-{
- is line_atan([ [0, 0], [10, 0] ]), (0), 'E atan2';
- is line_atan([ [10, 0], [0, 0] ]), (PI), 'W atan2';
- is line_atan([ [0, 0], [0, 10] ]), (PI/2), 'N atan2';
- is line_atan([ [0, 10], [0, 0] ]), -(PI/2), 'S atan2';
-
- is line_atan([ [10, 10], [0, 0] ]), -(PI*3/4), 'SW atan2';
- is line_atan([ [0, 0], [10, 10] ]), (PI*1/4), 'NE atan2';
- is line_atan([ [0, 10], [10, 0] ]), -(PI*1/4), 'SE atan2';
- is line_atan([ [10, 0], [0, 10] ]), (PI*3/4), 'NW atan2';
-}
-
-#==========================================================
-
-{
- is line_orientation([ [0, 0], [10, 0] ]), (0), 'E orientation';
- is line_orientation([ [0, 0], [0, 10] ]), (PI/2), 'N orientation';
- is line_orientation([ [10, 0], [0, 0] ]), (PI), 'W orientation';
- is line_orientation([ [0, 10], [0, 0] ]), (PI*3/2), 'S orientation';
-
- is line_orientation([ [0, 0], [10, 10] ]), (PI*1/4), 'NE orientation';
- is line_orientation([ [10, 0], [0, 10] ]), (PI*3/4), 'NW orientation';
- is line_orientation([ [10, 10], [0, 0] ]), (PI*5/4), 'SW orientation';
- is line_orientation([ [0, 10], [10, 0] ]), (PI*7/4), 'SE orientation';
-}
-
-#==========================================================
-
-{
- is line_direction([ [0, 0], [10, 0] ]), (0), 'E direction';
- is line_direction([ [10, 0], [0, 0] ]), (0), 'W direction';
- is line_direction([ [0, 0], [0, 10] ]), (PI/2), 'N direction';
- is line_direction([ [0, 10], [0, 0] ]), (PI/2), 'S direction';
-
- is line_direction([ [10, 10], [0, 0] ]), (PI*1/4), 'SW direction';
- is line_direction([ [0, 0], [10, 10] ]), (PI*1/4), 'NE direction';
- is line_direction([ [0, 10], [10, 0] ]), (PI*3/4), 'SE direction';
- is line_direction([ [10, 0], [0, 10] ]), (PI*3/4), 'NW direction';
-}
-
-#==========================================================
-
-{
- is rad2deg_dir(0), 90, 'E (degrees)';
- is rad2deg_dir(PI), 270, 'W (degrees)';
- is rad2deg_dir(PI/2), 0, 'N (degrees)';
- is rad2deg_dir(-(PI/2)), 180, 'S (degrees)';
- is rad2deg_dir(PI*1/4), 45, 'NE (degrees)';
- is rad2deg_dir(PI*3/4), 135, 'NW (degrees)';
- is rad2deg_dir(PI/6), 60, '30°';
- is rad2deg_dir(PI/6*2), 30, '60°';
-}
-
-#==========================================================
-
-{
- is angle3points([0,0], [10,0], [0,10]), PI/2, 'CW angle3points';
- is angle3points([0,0], [0,10], [10,0]), PI/2*3, 'CCW angle3points';
-}
-
-#==========================================================
-
-sub line_atan {
- my ($l) = @_;
- return Slic3r::Line->new(@$l)->atan2_;
-}
-
-sub line_orientation {
- my ($l) = @_;
- return Slic3r::Line->new(@$l)->orientation;
-}
-
-sub line_direction {
- my ($l) = @_;
- return Slic3r::Line->new(@$l)->direction;
-}
\ No newline at end of file
diff --git a/t/avoid_crossing_perimeters.t b/t/avoid_crossing_perimeters.t
deleted file mode 100644
index 86c3e91cb9..0000000000
--- a/t/avoid_crossing_perimeters.t
+++ /dev/null
@@ -1,22 +0,0 @@
-use Test::More tests => 1;
-use strict;
-use warnings;
-
-BEGIN {
- use FindBin;
- use lib "$FindBin::Bin/../lib";
- use local::lib "$FindBin::Bin/../local-lib";
-}
-
-use List::Util qw(first sum);
-use Slic3r;
-use Slic3r::Test;
-
-{
- my $config = Slic3r::Config::new_from_defaults;
- $config->set('avoid_crossing_perimeters', 2);
- my $print = Slic3r::Test::init_print('20mm_cube', config => $config, duplicate => 2);
- ok my $gcode = Slic3r::Test::gcode($print), "no crash with avoid_crossing_perimeters and multiple objects";
-}
-
-__END__
diff --git a/t/bridges.t b/t/bridges.t
deleted file mode 100644
index ca55862b62..0000000000
--- a/t/bridges.t
+++ /dev/null
@@ -1,137 +0,0 @@
-use Test::More tests => 16;
-use strict;
-use warnings;
-
-BEGIN {
- use FindBin;
- use lib "$FindBin::Bin/../lib";
- use local::lib "$FindBin::Bin/../local-lib";
-}
-
-use List::Util qw(first sum);
-use Slic3r;
-use Slic3r::Geometry qw(scale epsilon deg2rad rad2deg);
-use Slic3r::Test;
-
-{
- my $test = sub {
- my ($bridge_size, $rotate, $expected_angle, $tolerance) = @_;
-
- my ($x, $y) = @$bridge_size;
- my $lower = Slic3r::ExPolygon->new(
- Slic3r::Polygon->new_scale([-2,-2], [$x+2,-2], [$x+2,$y+2], [-2,$y+2]),
- Slic3r::Polygon->new_scale([0,0], [0,$y], [$x,$y], [$x,0]),
- );
- $lower->translate(scale 20, scale 20); # avoid negative coordinates for easier SVG preview
- $lower->rotate(deg2rad($rotate), [$x/2,$y/2]);
- my $bridge = $lower->[1]->clone;
- $bridge->reverse;
- $bridge = Slic3r::ExPolygon->new($bridge);
-
- ok check_angle([$lower], $bridge, $expected_angle, $tolerance), 'correct bridge angle for O-shaped overhang';
- };
-
- $test->([20,10], 0, 90);
- $test->([10,20], 0, 0);
- $test->([20,10], 45, 135, 20);
- $test->([20,10], 135, 45, 20);
-}
-
-{
- my $bridge = Slic3r::ExPolygon->new(
- Slic3r::Polygon->new_scale([0,0], [20,0], [20,10], [0,10]),
- );
- my $lower = [
- Slic3r::ExPolygon->new(
- Slic3r::Polygon->new_scale([-2,0], [0,0], [0,10], [-2,10]),
- ),
- ];
- $_->translate(scale 20, scale 20) for $bridge, @$lower; # avoid negative coordinates for easier SVG preview
-
- $lower->[1] = $lower->[0]->clone;
- $lower->[1]->translate(scale 22, 0);
-
- ok check_angle($lower, $bridge, 0), 'correct bridge angle for two-sided bridge';
-}
-
-{
- my $bridge = Slic3r::ExPolygon->new(
- Slic3r::Polygon->new_scale([0,0], [20,0], [10,10], [0,10]),
- );
- my $lower = [
- Slic3r::ExPolygon->new(
- Slic3r::Polygon->new_scale([0,0], [0,10], [10,10], [10,12], [-2,12], [-2,-2], [22,-2], [22,0]),
- ),
- ];
- $_->translate(scale 20, scale 20) for $bridge, @$lower; # avoid negative coordinates for easier SVG preview
-
- ok check_angle($lower, $bridge, 135), 'correct bridge angle for C-shaped overhang';
-}
-
-{
- my $bridge = Slic3r::ExPolygon->new(
- Slic3r::Polygon->new_scale([10,10],[20,10],[20,20], [10,20]),
- );
- my $lower = [
- Slic3r::ExPolygon->new(
- Slic3r::Polygon->new_scale([10,10],[10,20],[20,20],[30,30],[0,30],[0,0]),
- ),
- ];
- $_->translate(scale 20, scale 20) for $bridge, @$lower; # avoid negative coordinates for easier SVG preview
-
- ok check_angle($lower, $bridge, 45, undef, $bridge->area/2), 'correct bridge angle for square overhang with L-shaped anchors';
-}
-
-sub check_angle {
- my ($lower, $bridge, $expected, $tolerance, $expected_coverage) = @_;
-
- if (ref($lower) eq 'ARRAY') {
- $lower = Slic3r::ExPolygon::Collection->new(@$lower);
- }
-
- $expected_coverage //= -1;
- $expected_coverage = $bridge->area if $expected_coverage == -1;
-
- my $bd = Slic3r::BridgeDetector->new($bridge, $lower, scale 0.5);
-
- $tolerance //= rad2deg($bd->resolution) + epsilon;
- $bd->detect_angle;
- my $result = $bd->angle;
- my $coverage = $bd->coverage;
- is sum(map $_->area, @$coverage), $expected_coverage, 'correct coverage area';
-
- # our epsilon is equal to the steps used by the bridge detection algorithm
- ###use XXX; YYY [ rad2deg($result), $expected ];
- # returned value must be non-negative, check for that too
- my $delta=rad2deg($result) - $expected;
- $delta-=180 if $delta>=180 - epsilon;
- return defined $result && $result>=0 && abs($delta) < $tolerance;
-}
-
-{
- my $config = Slic3r::Config::new_from_defaults;
- $config->set('top_solid_layers', 0); # to prevent bridging on sparse infill
- $config->set('bridge_speed', 99);
-
- my $print = Slic3r::Test::init_print('bridge', config => $config);
-
- my %extrusions = (); # angle => length
- Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub {
- my ($self, $cmd, $args, $info) = @_;
-
- if ($cmd eq 'G1' && ($args->{F} // $self->F)/60 == $config->bridge_speed) {
- my $line = Slic3r::Line->new_scale(
- [ $self->X, $self->Y ],
- [ $info->{new_X}, $info->{new_Y} ],
- );
- my $angle = $line->direction;
- $extrusions{$angle} //= 0;
- $extrusions{$angle} += $line->length;
- }
- });
- ok !!%extrusions, "bridge is generated";
- my ($main_angle) = sort { $extrusions{$b} <=> $extrusions{$a} } keys %extrusions;
- is $main_angle, 0, "bridge has the expected direction";
-}
-
-__END__
diff --git a/t/collinear.t b/t/collinear.t
deleted file mode 100644
index b28a3602c5..0000000000
--- a/t/collinear.t
+++ /dev/null
@@ -1,87 +0,0 @@
-use Test::More;
-use strict;
-use warnings;
-
-plan tests => 11;
-
-BEGIN {
- use FindBin;
- use lib "$FindBin::Bin/../lib";
- use local::lib "$FindBin::Bin/../local-lib";
-}
-
-use Slic3r;
-use Slic3r::Geometry qw(collinear);
-
-#==========================================================
-
-{
- my @lines = (
- Slic3r::Line->new([0,4], [4,2]),
- Slic3r::Line->new([2,3], [8,0]),
- Slic3r::Line->new([6,1], [8,0]),
- );
- is collinear($lines[0], $lines[1]), 1, 'collinear';
- is collinear($lines[1], $lines[2]), 1, 'collinear';
- is collinear($lines[0], $lines[2]), 1, 'collinear';
-}
-
-#==========================================================
-
-{
- # horizontal
- my @lines = (
- Slic3r::Line->new([0,1], [5,1]),
- Slic3r::Line->new([2,1], [8,1]),
- );
- is collinear($lines[0], $lines[1]), 1, 'collinear';
-}
-
-#==========================================================
-
-{
- # vertical
- my @lines = (
- Slic3r::Line->new([1,0], [1,5]),
- Slic3r::Line->new([1,2], [1,8]),
- );
- is collinear($lines[0], $lines[1]), 1, 'collinear';
-}
-
-#==========================================================
-
-{
- # non overlapping
- my @lines = (
- Slic3r::Line->new([0,1], [5,1]),
- Slic3r::Line->new([7,1], [10,1]),
- );
- is collinear($lines[0], $lines[1], 1), 0, 'non overlapping';
- is collinear($lines[0], $lines[1], 0), 1, 'overlapping';
-}
-
-#==========================================================
-
-{
- # with one common point
- my @lines = (
- Slic3r::Line->new([0,4], [4,2]),
- Slic3r::Line->new([4,2], [8,0]),
- );
- is collinear($lines[0], $lines[1], 1), 1, 'one common point';
- is collinear($lines[0], $lines[1], 0), 1, 'one common point';
-}
-
-#==========================================================
-
-{
- # not collinear
- my @lines = (
- Slic3r::Line->new([290000000,690525600], [285163380,684761540]),
- Slic3r::Line->new([285163380,684761540], [193267599,575244400]),
- );
- is collinear($lines[0], $lines[1], 0), 0, 'not collinear';
- is collinear($lines[0], $lines[1], 1), 0, 'not collinear';
-}
-
-#==========================================================
diff --git a/t/dynamic.t b/t/dynamic.t
deleted file mode 100644
index 5d4d3ceb4e..0000000000
--- a/t/dynamic.t
+++ /dev/null
@@ -1,93 +0,0 @@
-use Test::More;
-use strict;
-use warnings;
-
-plan skip_all => 'variable-width paths are currently disabled';
-plan tests => 20;
-
-BEGIN {
- use FindBin;
- use lib "$FindBin::Bin/../lib";
- use local::lib "$FindBin::Bin/../local-lib";
-}
-
-use List::Util qw(first);
-use Slic3r;
-use Slic3r::Geometry qw(X Y scale epsilon);
-use Slic3r::Surface ':types';
-
-sub scale_points (@) { map [scale $_->[X], scale $_->[Y]], @_ }
-
-{
- my $square = Slic3r::ExPolygon->new([
- scale_points [0,0], [10,0], [10,10], [0,10],
- ]);
-
- my @offsets = @{$square->noncollapsing_offset_ex(- scale 5)};
- is scalar @offsets, 1, 'non-collapsing offset';
-}
-
-{
- local $Slic3r::Config = Slic3r::Config->new(
- perimeters => 3,
- );
- my $w = 0.7;
- my $perimeter_flow = Slic3r::Flow->new(
- nozzle_diameter => 0.5,
- layer_height => 0.4,
- width => $w,
- );
-
- my $print = Slic3r::Print->new;
- my $region = Slic3r::Print::Region->new(
- print => $print,
- flows => { perimeter => $perimeter_flow },
- );
- push @{$print->regions}, $region;
- my $object = Slic3r::Print::Object->new(
- print => $print,
- size => [1,1],
- );
- my $make_layer = sub {
- my ($width) = @_;
- my $layer = Slic3r::Layer->new(
- object => $object,
- id => 1,
- slices => [
- Slic3r::Surface->new(
- surface_type => S_TYPE_INTERNAL,
- expolygon => Slic3r::ExPolygon->new([ scale_points [0,0], [50,0], [50,$width], [0,$width] ]),
- ),
- ],
- thin_walls => [],
- );
- my $layerm = $layer->region(0);
- $layer->make_perimeters;
- return $layerm;
- };
-
- my %widths = (
- 1 * $w => { perimeters => 1, gaps => 0 },
- 1.3 * $w => { perimeters => 1, gaps => 1, gap_flow_spacing => $perimeter_flow->clone(width => 0.2 * $w)->spacing },
- 1.5 * $w => { perimeters => 1, gaps => 1, gap_flow_spacing => $perimeter_flow->clone(width => 0.5 * $w)->spacing },
- 2 * $w => { perimeters => 1, gaps => 1, gap_flow_spacing => $perimeter_flow->spacing },
- 2.5 * $w => { perimeters => 1, gaps => 1, gap_flow_spacing => $perimeter_flow->clone(width => 1.5 * $w)->spacing },
- 3 * $w => { perimeters => 2, gaps => 0 },
- 4 * $w => { perimeters => 2, gaps => 1, gap_flow_spacing => $perimeter_flow->spacing },
- );
-
- foreach my $width (sort keys %widths) {
- my $layerm = $make_layer->($width);
- is scalar @{$layerm->perimeters}, $widths{$width}{perimeters}, 'right number of perimeters';
- is scalar @{$layerm->thin_fills} ? 1 : 0, $widths{$width}{gaps},
- ($widths{$width}{gaps} ? 'gaps were filled' : 'no gaps detected'); # TODO: we should check the exact number of gaps, but we need a better medial axis algorithm
-
- my @gaps = map $_, @{$layerm->thin_fills};
- if (@gaps) {
- ok +(!first { abs($_->flow_spacing - $widths{$width}{gap_flow_spacing}) > epsilon } @gaps),
- 'flow spacing was dynamically adjusted';
- }
- }
-}
-
-__END__
diff --git a/t/gaps.t b/t/gaps.t
index f0c75c3531..2594ac0870 100644
--- a/t/gaps.t
+++ b/t/gaps.t
@@ -10,7 +10,6 @@ BEGIN {
use List::Util qw(first);
use Slic3r;
-use Slic3r::Flow ':roles';
use Slic3r::Geometry qw(PI scale unscale convex_hull);
use Slic3r::Surface ':types';
use Slic3r::Test;
diff --git a/t/geometry.t b/t/geometry.t
index 874dab9877..981621ee8d 100644
--- a/t/geometry.t
+++ b/t/geometry.t
@@ -2,7 +2,7 @@ use Test::More;
use strict;
use warnings;
-plan tests => 27;
+plan tests => 11;
BEGIN {
use FindBin;
@@ -11,7 +11,7 @@ BEGIN {
}
use Slic3r;
-use Slic3r::Geometry qw(PI polygon_is_convex
+use Slic3r::Geometry qw(PI
chained_path_from epsilon scale);
{
@@ -27,18 +27,6 @@ use Slic3r::Geometry qw(PI polygon_is_convex
#==========================================================
-my $line1 = [ [5, 15], [30, 15] ];
-my $line2 = [ [10, 20], [10, 10] ];
-is_deeply Slic3r::Geometry::line_intersection($line1, $line2, 1)->arrayref, [10, 15], 'line_intersection';
-
-#==========================================================
-
-$line1 = [ [73.6310778185108/0.0000001, 371.74239268924/0.0000001], [73.6310778185108/0.0000001, 501.74239268924/0.0000001] ];
-$line2 = [ [75/0.0000001, 437.9853/0.0000001], [62.7484/0.0000001, 440.4223/0.0000001] ];
-isnt Slic3r::Geometry::line_intersection($line1, $line2, 1), undef, 'line_intersection';
-
-#==========================================================
-
my $polygons = [
Slic3r::Polygon->new( # contour, ccw
[45919000, 515273900], [14726100, 461246400], [14726100, 348753500], [33988700, 315389800],
@@ -57,54 +45,6 @@ my $polygons = [
),
];
-#==========================================================
-
-{
- my $p1 = [10, 10];
- my $p2 = [10, 20];
- my $p3 = [10, 30];
- my $p4 = [20, 20];
- my $p5 = [0, 20];
-
- is Slic3r::Geometry::angle3points($p2, $p3, $p1), PI(), 'angle3points';
- is Slic3r::Geometry::angle3points($p2, $p1, $p3), PI(), 'angle3points';
- is Slic3r::Geometry::angle3points($p2, $p3, $p4), PI()/2*3, 'angle3points';
- is Slic3r::Geometry::angle3points($p2, $p4, $p3), PI()/2, 'angle3points';
- is Slic3r::Geometry::angle3points($p2, $p1, $p4), PI()/2, 'angle3points';
- is Slic3r::Geometry::angle3points($p2, $p1, $p5), PI()/2*3, 'angle3points';
-}
-
-{
- my $p1 = [30, 30];
- my $p2 = [20, 20];
- my $p3 = [10, 10];
- my $p4 = [30, 10];
-
- is Slic3r::Geometry::angle3points($p2, $p1, $p3), PI(), 'angle3points';
- is Slic3r::Geometry::angle3points($p2, $p1, $p4), PI()/2*3, 'angle3points';
- is Slic3r::Geometry::angle3points($p2, $p1, $p1), 2*PI(), 'angle3points';
-}
-
-#==========================================================
-
-{
- my $cw_square = [ [0,0], [0,10], [10,10], [10,0] ];
- is polygon_is_convex($cw_square), 0, 'cw square is not convex';
- is polygon_is_convex([ reverse @$cw_square ]), 1, 'ccw square is convex';
-
- my $convex1 = [ [0,0], [10,0], [10,10], [0,10], [0,6], [4,6], [4,4], [0,4] ];
- is polygon_is_convex($convex1), 0, 'concave polygon';
-}
-
-#==========================================================
-
-{
- my $polyline = Slic3r::Polyline->new([0, 0], [10, 0], [20, 0]);
- is_deeply [ map $_->pp, @{$polyline->lines} ], [
- [ [0, 0], [10, 0] ],
- [ [10, 0], [20, 0] ],
- ], 'polyline_lines';
-}
#==========================================================
@@ -125,13 +65,6 @@ my $polygons = [
#==========================================================
-{
- my $line = Slic3r::Line->new([10,10], [20,10]);
- is $line->grow(5)->[0]->area, Slic3r::Polygon->new([10,5], [20,5], [20,15], [10,15])->area, 'grow line';
-}
-
-#==========================================================
-
{
# if chained_path() works correctly, these points should be joined with no diagonal paths
# (thus 26 units long)
diff --git a/t/multi.t b/t/multi.t
deleted file mode 100644
index e74a7a1a8b..0000000000
--- a/t/multi.t
+++ /dev/null
@@ -1,221 +0,0 @@
-use Test::More tests => 13;
-use strict;
-use warnings;
-
-BEGIN {
- use FindBin;
- use lib "$FindBin::Bin/../lib";
- use local::lib "$FindBin::Bin/../local-lib";
-}
-
-use List::Util qw(first);
-use Slic3r;
-use Slic3r::Geometry qw(scale convex_hull);
-use Slic3r::Geometry::Clipper qw(offset);
-use Slic3r::Test;
-
-{
- my $config = Slic3r::Config::new_from_defaults;
- $config->set('nozzle_diameter', [0.6,0.6,0.6,0.6]);
- $config->set('raft_layers', 2);
- $config->set('infill_extruder', 2);
- $config->set('solid_infill_extruder', 3);
- $config->set('support_material_extruder', 4);
- $config->set('ooze_prevention', 1);
- $config->set('extruder_offset', [ [0,0], [20,0], [0,20], [20,20] ]);
- $config->set('temperature', [200, 180, 170, 160]);
- $config->set('first_layer_temperature', [206, 186, 166, 156]);
- $config->set('toolchange_gcode', 'T[next_extruder] ;toolchange'); # test that it doesn't crash when this is supplied
- # Since July 2019, PrusaSlicer only emits automatic Tn command in case that the toolchange_gcode is empty
- # The "T[next_extruder]" is therefore needed in this test.
-
- my $print = Slic3r::Test::init_print('20mm_cube', config => $config);
-
- my $tool = undef;
- my @tool_temp = (0,0,0,0);
- my @toolchange_points = ();
- my @extrusion_points = ();
- Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub {
- my ($self, $cmd, $args, $info) = @_;
-
- if ($cmd =~ /^T(\d+)/) {
- # ignore initial toolchange
- if (defined $tool) {
- my $expected_temp = $self->Z == ($config->get_value('first_layer_height') + $config->z_offset)
- ? $config->first_layer_temperature->[$tool]
- : $config->temperature->[$tool];
- die 'standby temperature was not set before toolchange'
- if $tool_temp[$tool] != $expected_temp + $config->standby_temperature_delta;
-
- push @toolchange_points, my $point = Slic3r::Point->new_scale($self->X, $self->Y);
- }
- $tool = $1;
- } elsif ($cmd eq 'M104' || $cmd eq 'M109') {
- my $t = $args->{T} // $tool;
- if ($tool_temp[$t] == 0) {
- fail 'initial temperature is not equal to first layer temperature + standby delta'
- unless $args->{S} == $config->first_layer_temperature->[$t] + $config->standby_temperature_delta;
- }
- $tool_temp[$t] = $args->{S};
- } elsif ($cmd eq 'G1' && $info->{extruding} && $info->{dist_XY} > 0) {
- push @extrusion_points, my $point = Slic3r::Point->new_scale($args->{X}, $args->{Y});
- $point->translate(map +scale($_), @{ $config->extruder_offset->[$tool] });
- }
- });
- my $convex_hull = convex_hull(\@extrusion_points);
-
- my @t = ();
- foreach my $point (@toolchange_points) {
- foreach my $offset (@{$config->extruder_offset}) {
- push @t, my $p = $point->clone;
- $p->translate(map +scale($_), @$offset);
- }
- }
- ok !(defined first { $convex_hull->contains_point($_) } @t), 'all nozzles are outside skirt at toolchange';
-
- if (0) {
- require "Slic3r/SVG.pm";
- Slic3r::SVG::output(
- "ooze_prevention_test.svg",
- no_arrows => 1,
- polygons => [$convex_hull],
- red_points => \@t,
- points => \@toolchange_points,
- );
- }
-
- # offset the skirt by the maximum displacement between extruders plus a safety extra margin
- my $delta = scale(20 * sqrt(2) + 1);
- my $outer_convex_hull = offset([$convex_hull], +$delta)->[0];
- ok !(defined first { !$outer_convex_hull->contains_point($_) } @toolchange_points), 'all toolchanges happen within expected area';
-}
-
-{
- my $config = Slic3r::Config::new_from_defaults;
- $config->set('nozzle_diameter', [0.6,0.6,0.6,0.6]);
- $config->set('support_material_extruder', 3);
-
- my $print = Slic3r::Test::init_print('20mm_cube', config => $config);
- ok Slic3r::Test::gcode($print), 'no errors when using non-consecutive extruders';
-}
-
-{
- my $config = Slic3r::Config->new;
- $config->set('nozzle_diameter', [0.6,0.6,0.6,0.6]);
- $config->set('extruder', 2);
-
- my $print = Slic3r::Test::init_print('20mm_cube', config => $config);
- like Slic3r::Test::gcode($print), qr/ T1/, 'extruder shortcut';
-}
-
-{
- my $config = Slic3r::Config->new;
- $config->set('nozzle_diameter', [0.6,0.6,0.6,0.6]);
- $config->set('perimeter_extruder', 2);
- $config->set('infill_extruder', 2);
- $config->set('support_material_extruder', 2);
- $config->set('support_material_interface_extruder', 2);
-
- my $print = Slic3r::Test::init_print('20mm_cube', config => $config);
- ok Slic3r::Test::gcode($print), 'no errors when using multiple skirts with a single, non-zero, extruder';
-}
-
-{
- my $model = stacked_cubes();
- my $lower_config = $model->get_material('lower')->config;
- my $upper_config = $model->get_material('upper')->config;
-
- $lower_config->set('extruder', 1);
- $lower_config->set('bottom_solid_layers', 0);
- $lower_config->set('top_solid_layers', 1);
- $upper_config->set('extruder', 2);
- $upper_config->set('bottom_solid_layers', 1);
- $upper_config->set('top_solid_layers', 0);
- my $config = Slic3r::Config::new_from_defaults;
- $config->set('nozzle_diameter', [0.6,0.6,0.6,0.6]);
- $config->set('fill_density', 0);
- $config->set('solid_infill_speed', 99);
- $config->set('top_solid_infill_speed', 99);
- $config->set('cooling', [ 0 ]); # for preventing speeds from being altered
- $config->set('first_layer_speed', '100%'); # for preventing speeds from being altered
-
- my $test = sub {
- my $print = Slic3r::Test::init_print($model, config => $config);
- my $tool = undef;
- my %T0_shells = my %T1_shells = (); # Z => 1
- Slic3r::GCode::Reader->new->parse(my $gcode = Slic3r::Test::gcode($print), sub {
- my ($self, $cmd, $args, $info) = @_;
-
- if ($cmd =~ /^T(\d+)/) {
- $tool = $1;
- } elsif ($cmd eq 'G1' && $info->{extruding} && $info->{dist_XY} > 0) {
- if (($args->{F} // $self->F) == $config->solid_infill_speed*60) {
- if ($tool == 0) {
- $T0_shells{$self->Z} = 1;
- } elsif ($tool == 1) {
- $T1_shells{$self->Z} = 1;
- }
- }
- }
- });
- return [ sort keys %T0_shells ], [ sort keys %T1_shells ];
- };
-
- {
- my ($t0, $t1) = $test->();
- is scalar(@$t0), 0, 'no interface shells';
- is scalar(@$t1), 0, 'no interface shells';
- }
- {
- $config->set('interface_shells', 1);
- my ($t0, $t1) = $test->();
- is scalar(@$t0), $lower_config->top_solid_layers, 'top interface shells';
- is scalar(@$t1), $upper_config->bottom_solid_layers, 'bottom interface shells';
- }
-}
-
-{
- my $model = stacked_cubes();
- my $object = $model->objects->[0];
-
- my $config = Slic3r::Config::new_from_defaults;
- $config->set('nozzle_diameter', [0.6,0.6,0.6,0.6]);
- $config->set('layer_height', 0.4);
- $config->set('first_layer_height', $config->layer_height);
- $config->set('skirts', 0);
- my $print = Slic3r::Test::init_print($model, config => $config);
-
- is $object->volumes->[0]->config->extruder, 1, 'auto_assign_extruders() assigned correct extruder to first volume';
- is $object->volumes->[1]->config->extruder, 2, 'auto_assign_extruders() assigned correct extruder to second volume';
-
- my $tool = undef;
- my %T0 = my %T1 = (); # Z => 1
- Slic3r::GCode::Reader->new->parse(my $gcode = Slic3r::Test::gcode($print), sub {
- my ($self, $cmd, $args, $info) = @_;
-
- if ($cmd =~ /^T(\d+)/) {
- $tool = $1;
- } elsif ($cmd eq 'G1' && $info->{extruding} && $info->{dist_XY} > 0) {
- if ($tool == 0) {
- $T0{$self->Z} = 1;
- } elsif ($tool == 1) {
- $T1{$self->Z} = 1;
- }
- }
- });
-
- ok !(defined first { $_ > 20 } keys %T0), 'T0 is never used for upper object';
- ok !(defined first { $_ < 20 } keys %T1), 'T1 is never used for lower object';
-}
-
-sub stacked_cubes {
- my $model = Slic3r::Model->new;
- my $object = $model->add_object;
- $object->add_volume(mesh => Slic3r::Test::mesh('20mm_cube'), material_id => 'lower');
- $object->add_volume(mesh => Slic3r::Test::mesh('20mm_cube', translate => [0,0,20]), material_id => 'upper');
- $object->add_instance(offset => Slic3r::Pointf->new(0,0));
-
- return $model;
-}
-
-__END__
diff --git a/t/perimeters.t b/t/perimeters.t
deleted file mode 100644
index c4aef6e7e7..0000000000
--- a/t/perimeters.t
+++ /dev/null
@@ -1,444 +0,0 @@
-use Test::More tests => 59;
-use strict;
-use warnings;
-
-BEGIN {
- use FindBin;
- use lib "$FindBin::Bin/../lib";
- use local::lib "$FindBin::Bin/../local-lib";
-}
-
-use Slic3r::ExtrusionLoop ':roles';
-use Slic3r::ExtrusionPath ':roles';
-use List::Util qw(first);
-use Slic3r;
-use Slic3r::Flow ':roles';
-use Slic3r::Geometry qw(PI scale unscale);
-use Slic3r::Geometry::Clipper qw(union_ex diff);
-use Slic3r::Surface ':types';
-use Slic3r::Test;
-
-{
- my $flow = Slic3r::Flow->new(
- width => 1,
- height => 1,
- nozzle_diameter => 1,
- );
-
- my $config = Slic3r::Config->new;
- my $test = sub {
- my ($expolygons, %expected) = @_;
-
- my $slices = Slic3r::Surface::Collection->new;
- $slices->append(Slic3r::Surface->new(
- surface_type => S_TYPE_INTERNAL,
- expolygon => $_,
- )) for @$expolygons;
-
- my ($region_config, $object_config, $print_config, $loops, $gap_fill, $fill_surfaces);
- my $g = Slic3r::Layer::PerimeterGenerator->new(
- # input:
- $slices,
- 1, # layer height
- $flow,
- ($region_config = Slic3r::Config::PrintRegion->new),
- ($object_config = Slic3r::Config::PrintObject->new),
- ($print_config = Slic3r::Config::Print->new),
-
- # output:
- ($loops = Slic3r::ExtrusionPath::Collection->new),
- ($gap_fill = Slic3r::ExtrusionPath::Collection->new),
- ($fill_surfaces = Slic3r::Surface::Collection->new),
- );
- $g->config->apply_dynamic($config);
- $g->process;
-
- is scalar(@$loops),
- scalar(@$expolygons), 'expected number of collections';
- ok !defined(first { !$_->isa('Slic3r::ExtrusionPath::Collection') } @$loops),
- 'everything is returned as collections';
-
- my $flattened_loops = $loops->flatten;
- my @loops = @$flattened_loops;
- is scalar(@loops),
- $expected{total}, 'expected number of loops';
- is scalar(grep $_->role == EXTR_ROLE_EXTERNAL_PERIMETER, map @$_, @loops),
- $expected{external}, 'expected number of external loops';
- is_deeply [ map { ($_->role == EXTR_ROLE_EXTERNAL_PERIMETER) || 0 } map @$_, @loops ],
- $expected{ext_order}, 'expected external order';
- is scalar(grep $_->loop_role == EXTRL_ROLE_CONTOUR_INTERNAL_PERIMETER, @loops),
- $expected{cinternal}, 'expected number of internal contour loops';
- is scalar(grep $_->polygon->is_counter_clockwise, @loops),
- $expected{ccw}, 'expected number of ccw loops';
- is_deeply [ map $_->polygon->is_counter_clockwise, @loops ],
- $expected{ccw_order}, 'expected ccw/cw order';
-
- if ($expected{nesting}) {
- foreach my $nesting (@{ $expected{nesting} }) {
- for my $i (1..$#$nesting) {
- ok $loops[$nesting->[$i-1]]->polygon->contains_point($loops[$nesting->[$i]]->first_point),
- 'expected nesting order';
- }
- }
- }
- };
-
- $config->set('perimeters', 3);
- $test->(
- [
- Slic3r::ExPolygon->new(
- Slic3r::Polygon->new_scale([0,0], [100,0], [100,100], [0,100]),
- ),
- ],
- total => 3,
- external => 1,
- ext_order => [0,0,1],
- cinternal => 1,
- ccw => 3,
- ccw_order => [1,1,1],
- nesting => [ [2,1,0] ],
- );
- $test->(
- [
- Slic3r::ExPolygon->new(
- Slic3r::Polygon->new_scale([0,0], [100,0], [100,100], [0,100]),
- Slic3r::Polygon->new_scale([40,40], [40,60], [60,60], [60,40]),
- ),
- ],
- total => 6,
- external => 2,
- ext_order => [0,0,1,0,0,1],
- cinternal => 1,
- ccw => 3,
- ccw_order => [0,0,0,1,1,1],
- nesting => [ [5,4,3,0,1,2] ],
- );
- $test->(
- [
- Slic3r::ExPolygon->new(
- Slic3r::Polygon->new_scale([0,0], [200,0], [200,200], [0,200]),
- Slic3r::Polygon->new_scale([20,20], [20,180], [180,180], [180,20]),
- ),
- # nested:
- Slic3r::ExPolygon->new(
- Slic3r::Polygon->new_scale([50,50], [150,50], [150,150], [50,150]),
- Slic3r::Polygon->new_scale([80,80], [80,120], [120,120], [120,80]),
- ),
- ],
- total => 4*3,
- external => 4,
- ext_order => [0,0,1,0,0,1,0,0,1,0,0,1],
- cinternal => 2,
- ccw => 2*3,
- ccw_order => [0,0,0,1,1,1,0,0,0,1,1,1],
- );
-
- $config->set('perimeters', 2);
- $test->(
- [
- Slic3r::ExPolygon->new(
- Slic3r::Polygon->new_scale([0,0], [50,0], [50,50], [0,50]),
- Slic3r::Polygon->new_scale([7.5,7.5], [7.5,12.5], [12.5,12.5], [12.5,7.5]),
- Slic3r::Polygon->new_scale([7.5,17.5], [7.5,22.5], [12.5,22.5], [12.5,17.5]),
- Slic3r::Polygon->new_scale([7.5,27.5], [7.5,32.5], [12.5,32.5], [12.5,27.5]),
- Slic3r::Polygon->new_scale([7.5,37.5], [7.5,42.5], [12.5,42.5], [12.5,37.5]),
- Slic3r::Polygon->new_scale([17.5,7.5], [17.5,12.5], [22.5,12.5], [22.5,7.5]),
- ),
- ],
- total => 12,
- external => 6,
- ext_order => [0,1,0,1,0,1,0,1,0,1,0,1],
- cinternal => 1,
- ccw => 2,
- ccw_order => [0,0,0,0,0,0,0,0,0,0,1,1],
- nesting => [ [0,1],[2,3],[4,5],[6,7],[8,9] ],
- );
-}
-
-{
- my $config = Slic3r::Config::new_from_defaults;
- $config->set('skirts', 0);
- $config->set('fill_density', 0);
- $config->set('perimeters', 3);
- $config->set('top_solid_layers', 0);
- $config->set('bottom_solid_layers', 0);
- $config->set('cooling', [ 0 ]); # to prevent speeds from being altered
- $config->set('first_layer_speed', '100%'); # to prevent speeds from being altered
-
- {
- my $print = Slic3r::Test::init_print('overhang', config => $config);
- my $has_cw_loops = 0;
- my $cur_loop;
- Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub {
- my ($self, $cmd, $args, $info) = @_;
-
- if ($info->{extruding} && $info->{dist_XY} > 0) {
- $cur_loop ||= [ [$self->X, $self->Y] ];
- push @$cur_loop, [ @$info{qw(new_X new_Y)} ];
- } elsif ($cmd ne 'M73') { # skips remaining time lines (M73)
- if ($cur_loop) {
- $has_cw_loops = 1 if Slic3r::Polygon->new(@$cur_loop)->is_clockwise;
- $cur_loop = undef;
- }
- }
- });
- ok !$has_cw_loops, 'all perimeters extruded ccw';
- }
-
- foreach my $model (qw(cube_with_hole cube_with_concave_hole)) {
- $config->set('external_perimeter_speed', 68);
- my $print = Slic3r::Test::init_print(
- $model,
- config => $config,
- duplicate => 2, # we test two copies to make sure ExtrusionLoop objects are not modified in-place (the second object would not detect cw loops and thus would calculate wrong inwards moves)
- );
- my $has_cw_loops = my $has_outwards_move = my $starts_on_convex_point = 0;
- my $cur_loop;
- my %external_loops = (); # print_z => count of external loops
- Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub {
- my ($self, $cmd, $args, $info) = @_;
-
- if ($info->{extruding} && $info->{dist_XY} > 0) {
- $cur_loop ||= [ [$self->X, $self->Y] ];
- push @$cur_loop, [ @$info{qw(new_X new_Y)} ];
- } elsif ($cmd ne 'M73') { # skips remaining time lines (M73)
- if ($cur_loop) {
- $has_cw_loops = 1 if Slic3r::Polygon->new_scale(@$cur_loop)->is_clockwise;
- if ($self->F == $config->external_perimeter_speed*60) {
- my $move_dest = Slic3r::Point->new_scale(@$info{qw(new_X new_Y)});
-
- # reset counter for second object
- $external_loops{$self->Z} = 0
- if defined($external_loops{$self->Z}) && $external_loops{$self->Z} == 2;
-
- $external_loops{$self->Z}++;
- my $is_contour = $external_loops{$self->Z} == 2;
- my $is_hole = $external_loops{$self->Z} == 1;
-
- my $loop = Slic3r::Polygon->new_scale(@$cur_loop);
- my $loop_contains_point = $loop->contains_point($move_dest);
- $has_outwards_move = 1
- if (!$loop_contains_point && $is_contour) # contour should include destination
- || ($loop_contains_point && $is_hole); # hole should not
-
- if ($model eq 'cube_with_concave_hole') {
- # check that loop starts at a concave vertex
- my $ccw_angle = $loop->[-2]->ccw($loop->first_point, $loop->[1]);
- my $convex = ($ccw_angle > PI); # whether the angle on the *right* side is convex
- $starts_on_convex_point = 1
- if ($convex && $is_contour) || (!$convex && $is_hole);
- }
- }
- $cur_loop = undef;
- }
- }
- });
- ok !$has_cw_loops, 'all perimeters extruded ccw';
- ok !$has_outwards_move, 'move inwards after completing external loop';
- ok !$starts_on_convex_point, 'loops start on concave point if any';
- }
-
- {
- $config->set('perimeters', 1);
- $config->set('perimeter_speed', 77);
- $config->set('external_perimeter_speed', 66);
- $config->set('bridge_speed', 99);
- $config->set('cooling', [ 1 ]);
- $config->set('fan_below_layer_time', [ 0 ]);
- $config->set('slowdown_below_layer_time', [ 0 ]);
- $config->set('bridge_fan_speed', [ 100 ]);
- $config->set('bridge_flow_ratio', 33); # arbitrary value
- $config->set('overhangs', 1);
- my $print = Slic3r::Test::init_print('overhang', config => $config);
- my %layer_speeds = (); # print Z => [ speeds ]
- my $fan_speed = 0;
- my $bridge_mm_per_mm = ($config->nozzle_diameter->[0]**2) / ($config->filament_diameter->[0]**2) * $config->bridge_flow_ratio;
- Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub {
- my ($self, $cmd, $args, $info) = @_;
-
- $fan_speed = 0 if $cmd eq 'M107';
- $fan_speed = $args->{S} if $cmd eq 'M106';
- if ($info->{extruding} && $info->{dist_XY} > 0) {
- $layer_speeds{$self->Z} ||= {};
- $layer_speeds{$self->Z}{my $feedrate = $args->{F} // $self->F} = 1;
-
- fail 'wrong speed found'
- if $feedrate != $config->perimeter_speed*60
- && $feedrate != $config->external_perimeter_speed*60
- && $feedrate != $config->bridge_speed*60;
-
- if ($feedrate == $config->bridge_speed*60) {
- fail 'printing overhang but fan is not enabled or running at wrong speed'
- if $fan_speed != 255;
- my $mm_per_mm = $info->{dist_E} / $info->{dist_XY};
- fail 'wrong bridge flow' if abs($mm_per_mm - $bridge_mm_per_mm) > 0.01;
- } else {
- fail 'fan is running when not supposed to'
- if $fan_speed > 0;
- }
- }
- });
- is scalar(grep { keys %$_ > 1 } values %layer_speeds), 1,
- 'only overhang layer has more than one speed';
- }
-}
-
-{
- my $config = Slic3r::Config::new_from_defaults;
- $config->set('skirts', 0);
- $config->set('perimeters', 3);
- $config->set('layer_height', 0.4);
- $config->set('first_layer_height', 0.35);
- $config->set('extra_perimeters', 1);
- $config->set('cooling', [ 0 ]); # to prevent speeds from being altered
- $config->set('first_layer_speed', '100%'); # to prevent speeds from being altered
- $config->set('perimeter_speed', 99);
- $config->set('external_perimeter_speed', 99);
- $config->set('small_perimeter_speed', 99);
- $config->set('thin_walls', 0);
-
- my $print = Slic3r::Test::init_print('ipadstand', config => $config);
- my %perimeters = (); # z => number of loops
- my $in_loop = 0;
- Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub {
- my ($self, $cmd, $args, $info) = @_;
-
- if ($info->{extruding} && $info->{dist_XY} > 0 && ($args->{F} // $self->F) == $config->perimeter_speed*60) {
- $perimeters{$self->Z}++ if !$in_loop;
- $in_loop = 1;
- } elsif ($cmd ne 'M73') { # skips remaining time lines (M73)
- $in_loop = 0;
- }
- });
- ok !(grep { $_ % $config->perimeters } values %perimeters), 'no superfluous extra perimeters';
-}
-
-{
- my $config = Slic3r::Config::new_from_defaults;
- $config->set('nozzle_diameter', [0.4]);
- $config->set('perimeters', 2);
- $config->set('perimeter_extrusion_width', 0.4);
- $config->set('external_perimeter_extrusion_width', 0.4);
- $config->set('infill_extrusion_width', 0.53);
- $config->set('solid_infill_extrusion_width', 0.53);
-
- # we just need a pre-filled Print object
- my $print = Slic3r::Test::init_print('20mm_cube', config => $config);
-
- # override a layer's slices
- my $expolygon = Slic3r::ExPolygon->new([[-71974463,-139999376],[-71731792,-139987456],[-71706544,-139985616],[-71682119,-139982639],[-71441248,-139946912],[-71417487,-139942895],[-71379384,-139933984],[-71141800,-139874480],[-71105247,-139862895],[-70873544,-139779984],[-70838592,-139765856],[-70614943,-139660064],[-70581783,-139643567],[-70368368,-139515680],[-70323751,-139487872],[-70122160,-139338352],[-70082399,-139306639],[-69894800,-139136624],[-69878679,-139121327],[-69707992,-138933008],[-69668575,-138887343],[-69518775,-138685359],[-69484336,-138631632],[-69356423,-138418207],[-69250040,-138193296],[-69220920,-138128976],[-69137992,-137897168],[-69126095,-137860255],[-69066568,-137622608],[-69057104,-137582511],[-69053079,-137558751],[-69017352,-137317872],[-69014392,-137293456],[-69012543,-137268207],[-68999369,-137000000],[-63999999,-137000000],[-63705947,-136985551],[-63654984,-136977984],[-63414731,-136942351],[-63364756,-136929840],[-63129151,-136870815],[-62851950,-136771631],[-62585807,-136645743],[-62377483,-136520895],[-62333291,-136494415],[-62291908,-136463728],[-62096819,-136319023],[-62058644,-136284432],[-61878676,-136121328],[-61680968,-135903184],[-61650275,-135861807],[-61505591,-135666719],[-61354239,-135414191],[-61332211,-135367615],[-61228359,-135148063],[-61129179,-134870847],[-61057639,-134585262],[-61014451,-134294047],[-61000000,-134000000],[-61000000,-107999999],[-61014451,-107705944],[-61057639,-107414736],[-61129179,-107129152],[-61228359,-106851953],[-61354239,-106585808],[-61505591,-106333288],[-61680967,-106096816],[-61878675,-105878680],[-62096820,-105680967],[-62138204,-105650279],[-62333292,-105505591],[-62585808,-105354239],[-62632384,-105332207],[-62851951,-105228360],[-62900463,-105211008],[-63129152,-105129183],[-63414731,-105057640],[-63705947,-105014448],[-63999999,-105000000],[-68999369,-105000000],[-69012543,-104731792],[-69014392,-104706544],[-69017352,-104682119],[-69053079,-104441248],[-69057104,-104417487],[-69066008,-104379383],[-69125528,-104141799],[-69137111,-104105248],[-69220007,-103873544],[-69234136,-103838591],[-69339920,-103614943],[-69356415,-103581784],[-69484328,-103368367],[-69512143,-103323752],[-69661647,-103122160],[-69693352,-103082399],[-69863383,-102894800],[-69878680,-102878679],[-70066999,-102707992],[-70112656,-102668576],[-70314648,-102518775],[-70368367,-102484336],[-70581783,-102356424],[-70806711,-102250040],[-70871040,-102220919],[-71102823,-102137992],[-71139752,-102126095],[-71377383,-102066568],[-71417487,-102057104],[-71441248,-102053079],[-71682119,-102017352],[-71706535,-102014392],[-71731784,-102012543],[-71974456,-102000624],[-71999999,-102000000],[-104000000,-102000000],[-104025536,-102000624],[-104268207,-102012543],[-104293455,-102014392],[-104317880,-102017352],[-104558751,-102053079],[-104582512,-102057104],[-104620616,-102066008],[-104858200,-102125528],[-104894751,-102137111],[-105126455,-102220007],[-105161408,-102234136],[-105385056,-102339920],[-105418215,-102356415],[-105631632,-102484328],[-105676247,-102512143],[-105877839,-102661647],[-105917600,-102693352],[-106105199,-102863383],[-106121320,-102878680],[-106292007,-103066999],[-106331424,-103112656],[-106481224,-103314648],[-106515663,-103368367],[-106643575,-103581783],[-106749959,-103806711],[-106779080,-103871040],[-106862007,-104102823],[-106873904,-104139752],[-106933431,-104377383],[-106942896,-104417487],[-106946920,-104441248],[-106982648,-104682119],[-106985607,-104706535],[-106987456,-104731784],[-107000630,-105000000],[-112000000,-105000000],[-112294056,-105014448],[-112585264,-105057640],[-112870848,-105129184],[-112919359,-105146535],[-113148048,-105228360],[-113194624,-105250392],[-113414191,-105354239],[-113666711,-105505591],[-113708095,-105536279],[-113903183,-105680967],[-114121320,-105878679],[-114319032,-106096816],[-114349720,-106138200],[-114494408,-106333288],[-114645760,-106585808],[-114667792,-106632384],[-114771640,-106851952],[-114788991,-106900463],[-114870815,-107129151],[-114942359,-107414735],[-114985551,-107705943],[-115000000,-107999999],[-115000000,-134000000],[-114985551,-134294048],[-114942359,-134585263],[-114870816,-134870847],[-114853464,-134919359],[-114771639,-135148064],[-114645759,-135414192],[-114494407,-135666720],[-114319031,-135903184],[-114121320,-136121327],[-114083144,-136155919],[-113903184,-136319023],[-113861799,-136349712],[-113666711,-136494416],[-113458383,-136619264],[-113414192,-136645743],[-113148049,-136771631],[-112870848,-136870815],[-112820872,-136883327],[-112585264,-136942351],[-112534303,-136949920],[-112294056,-136985551],[-112000000,-137000000],[-107000630,-137000000],[-106987456,-137268207],[-106985608,-137293440],[-106982647,-137317872],[-106946920,-137558751],[-106942896,-137582511],[-106933991,-137620624],[-106874471,-137858208],[-106862888,-137894751],[-106779992,-138126463],[-106765863,-138161424],[-106660080,-138385055],[-106643584,-138418223],[-106515671,-138631648],[-106487855,-138676256],[-106338352,-138877839],[-106306647,-138917600],[-106136616,-139105199],[-106121320,-139121328],[-105933000,-139291999],[-105887344,-139331407],[-105685351,-139481232],[-105631632,-139515663],[-105418216,-139643567],[-105193288,-139749951],[-105128959,-139779072],[-104897175,-139862016],[-104860247,-139873904],[-104622616,-139933423],[-104582511,-139942896],[-104558751,-139946912],[-104317880,-139982656],[-104293463,-139985616],[-104268216,-139987456],[-104025544,-139999376],[-104000000,-140000000],[-71999999,-140000000]],[[-105000000,-138000000],[-105000000,-104000000],[-71000000,-104000000],[-71000000,-138000000]],[[-69000000,-132000000],[-69000000,-110000000],[-64991180,-110000000],[-64991180,-132000000]],[[-111008824,-132000000],[-111008824,-110000000],[-107000000,-110000000],[-107000000,-132000000]]);
- my $object = $print->print->objects->[0];
- $object->slice;
- my $layer = $object->get_layer(1);
- my $layerm = $layer->regions->[0];
- $layerm->slices->clear;
- $layerm->slices->append(Slic3r::Surface->new(surface_type => S_TYPE_INTERNAL, expolygon => $expolygon));
-
- # make perimeters
- $layer->make_perimeters;
-
- # compute the covered area
- my $pflow = $layerm->flow(FLOW_ROLE_PERIMETER);
- my $iflow = $layerm->flow(FLOW_ROLE_INFILL);
- my $covered_by_perimeters = union_ex([
- (map @{$_->polygon->split_at_first_point->grow($pflow->scaled_width/2)}, map @$_, @{$layerm->perimeters}),
- ]);
- my $covered_by_infill = union_ex([
- (map $_->p, @{$layerm->fill_surfaces}),
- (map @{$_->polyline->grow($iflow->scaled_width/2)}, @{$layerm->thin_fills}),
- ]);
-
- # compute the non covered area
- my $non_covered = diff(
- [ map @{$_->expolygon}, @{$layerm->slices} ],
- [ map @$_, (@$covered_by_perimeters, @$covered_by_infill) ],
- );
-
- if (0) {
- printf "max non covered = %f\n", List::Util::max(map unscale unscale $_->area, @$non_covered);
- require "Slic3r/SVG.pm";
- Slic3r::SVG::output(
- "gaps.svg",
- expolygons => [ map $_->expolygon, @{$layerm->slices} ],
- red_expolygons => union_ex([ map @$_, (@$covered_by_perimeters, @$covered_by_infill) ]),
- green_expolygons => union_ex($non_covered),
- no_arrows => 1,
- polylines => [
- map $_->polygon->split_at_first_point, map @$_, @{$layerm->perimeters},
- ],
- );
- }
- ok !(defined first { $_->area > ($iflow->scaled_width**2) } @$non_covered), 'no gap between perimeters and infill';
-}
-
-{
- my $config = Slic3r::Config::new_from_defaults;
- $config->set('skirts', 0);
- $config->set('perimeters', 3);
- $config->set('layer_height', 0.4);
- $config->set('bridge_speed', 99);
- $config->set('fill_density', 0); # to prevent bridging over sparse infill
- $config->set('overhangs', 1);
- $config->set('cooling', [ 0 ]); # to prevent speeds from being altered
- $config->set('first_layer_speed', '100%'); # to prevent speeds from being altered
-
- my $test = sub {
- my ($print) = @_;
- my %z_with_bridges = (); # z => 1
- Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub {
- my ($self, $cmd, $args, $info) = @_;
-
- if ($info->{extruding} && $info->{dist_XY} > 0) {
- $z_with_bridges{$self->Z} = 1 if ($args->{F} // $self->F) == $config->bridge_speed*60;
- }
- });
- return scalar keys %z_with_bridges;
- };
- ok $test->(Slic3r::Test::init_print('V', config => $config)) == 1,
- 'no overhangs printed with bridge speed'; # except for the two internal solid layers above void
- ok $test->(Slic3r::Test::init_print('V', config => $config, scale_xyz => [3,1,1])) > 2,
- 'overhangs printed with bridge speed';
-}
-
-{
- my $config = Slic3r::Config::new_from_defaults;
- $config->set('seam_position', 'random');
- my $print = Slic3r::Test::init_print('20mm_cube', config => $config);
- ok Slic3r::Test::gcode($print), 'successful generation of G-code with seam_position = random';
-}
-
-{
- my $test = sub {
- my ($model_name) = @_;
- my $config = Slic3r::Config::new_from_defaults;
- $config->set('seam_position', 'aligned');
- $config->set('skirts', 0);
- $config->set('perimeters', 1);
- $config->set('fill_density', 0);
- $config->set('top_solid_layers', 0);
- $config->set('bottom_solid_layers', 0);
- $config->set('retract_layer_change', [0]);
-
- my $was_extruding = 0;
- my @seam_points = ();
- my $print = Slic3r::Test::init_print($model_name, config => $config);
- Slic3r::GCode::Reader->new->parse(my $gcode = Slic3r::Test::gcode($print), sub {
- my ($self, $cmd, $args, $info) = @_;
-
- if ($info->{extruding}) {
- if (!$was_extruding) {
- push @seam_points, Slic3r::Point->new_scale($self->X, $self->Y);
- }
- $was_extruding = 1;
- } elsif ($cmd ne 'M73') { # skips remaining time lines (M73)
- $was_extruding = 0;
- }
- });
- my @dist = map unscale($_), map $seam_points[$_]->distance_to($seam_points[$_+1]), 0..($#seam_points-1);
- ok !(defined first { $_ > 3 } @dist), 'seam is aligned';
- };
- $test->('20mm_cube');
- $test->('small_dorito');
-}
-
-__END__
diff --git a/t/slice.t b/t/slice.t
deleted file mode 100644
index 2f193aae3c..0000000000
--- a/t/slice.t
+++ /dev/null
@@ -1,152 +0,0 @@
-use Test::More;
-use strict;
-use warnings;
-
-plan skip_all => 'temporarily disabled';
-plan tests => 16;
-
-BEGIN {
- use FindBin;
- use lib "$FindBin::Bin/../lib";
- use local::lib "$FindBin::Bin/../local-lib";
-}
-
-# temporarily disable compilation errors due to constant not being exported anymore
-sub Slic3r::TriangleMesh::I_B {}
-sub Slic3r::TriangleMesh::I_FACET_EDGE {}
-sub Slic3r::TriangleMesh::FE_BOTTOM {
-sub Slic3r::TriangleMesh::FE_TOP {}}
-
-use Slic3r;
-use Slic3r::Geometry qw(X Y Z);
-
-my @lines;
-my $z = 20;
-my @points = ([3, 4], [8, 5], [1, 9]); # XY coordinates of the facet vertices
-
-# NOTE:
-# the first point of the intersection lines is replaced by -1 because TriangleMesh.pm
-# is saving memory and doesn't store point A anymore since it's not actually needed.
-
-# We disable this test because intersect_facet() now assumes we never feed a horizontal
-# facet to it.
-# is_deeply lines(20, 20, 20), [
-# [ -1, $points[1] ], # $points[0]
-# [ -1, $points[2] ], # $points[1]
-# [ -1, $points[0] ], # $points[2]
-# ], 'horizontal';
-
-is_deeply lines(22, 20, 20), [ [ -1, $points[2] ] ], 'lower edge on layer'; # $points[1]
-is_deeply lines(20, 20, 22), [ [ -1, $points[1] ] ], 'lower edge on layer'; # $points[0]
-is_deeply lines(20, 22, 20), [ [ -1, $points[0] ] ], 'lower edge on layer'; # $points[2]
-
-is_deeply lines(20, 20, 10), [ [ -1, $points[0] ] ], 'upper edge on layer'; # $points[1]
-is_deeply lines(10, 20, 20), [ [ -1, $points[1] ] ], 'upper edge on layer'; # $points[2]
-is_deeply lines(20, 10, 20), [ [ -1, $points[2] ] ], 'upper edge on layer'; # $points[0]
-
-is_deeply lines(20, 15, 10), [ ], 'upper vertex on layer';
-is_deeply lines(28, 20, 30), [ ], 'lower vertex on layer';
-
-{
- my @z = (24, 10, 16);
- is_deeply lines(@z), [
- [
- -1, # line_plane_intersection([ vertices(@z)->[0], vertices(@z)->[1] ]),
- line_plane_intersection([ vertices(@z)->[2], vertices(@z)->[0] ]),
- ]
- ], 'two edges intersect';
-}
-
-{
- my @z = (16, 24, 10);
- is_deeply lines(@z), [
- [
- -1, # line_plane_intersection([ vertices(@z)->[1], vertices(@z)->[2] ]),
- line_plane_intersection([ vertices(@z)->[0], vertices(@z)->[1] ]),
- ]
- ], 'two edges intersect';
-}
-
-{
- my @z = (10, 16, 24);
- is_deeply lines(@z), [
- [
- -1, # line_plane_intersection([ vertices(@z)->[2], vertices(@z)->[0] ]),
- line_plane_intersection([ vertices(@z)->[1], vertices(@z)->[2] ]),
- ]
- ], 'two edges intersect';
-}
-
-{
- my @z = (24, 10, 20);
- is_deeply lines(@z), [
- [
- -1, # line_plane_intersection([ vertices(@z)->[0], vertices(@z)->[1] ]),
- $points[2],
- ]
- ], 'one vertex on plane and one edge intersects';
-}
-
-{
- my @z = (10, 20, 24);
- is_deeply lines(@z), [
- [
- -1, # line_plane_intersection([ vertices(@z)->[2], vertices(@z)->[0] ]),
- $points[1],
- ]
- ], 'one vertex on plane and one edge intersects';
-}
-
-{
- my @z = (20, 24, 10);
- is_deeply lines(@z), [
- [
- -1, # line_plane_intersection([ vertices(@z)->[1], vertices(@z)->[2] ]),
- $points[0],
- ]
- ], 'one vertex on plane and one edge intersects';
-}
-
-my @lower = intersect(22, 20, 20);
-my @upper = intersect(20, 20, 10);
-is $lower[0][Slic3r::TriangleMesh::I_FACET_EDGE], Slic3r::TriangleMesh::FE_BOTTOM, 'bottom edge on layer';
-is $upper[0][Slic3r::TriangleMesh::I_FACET_EDGE], Slic3r::TriangleMesh::FE_TOP, 'upper edge on layer';
-
-my $mesh;
-
-sub intersect {
- $mesh = Slic3r::TriangleMesh->new(
- facets => [],
- vertices => [],
- );
- push @{$mesh->facets}, [ [0,0,0], @{vertices(@_)} ];
- $mesh->analyze;
- return map Slic3r::TriangleMesh::unpack_line($_), $mesh->intersect_facet($#{$mesh->facets}, $z);
-}
-
-sub vertices {
- push @{$mesh->vertices}, map [ @{$points[$_]}, $_[$_] ], 0..2;
- [ ($#{$mesh->vertices}-2) .. $#{$mesh->vertices} ]
-}
-
-sub lines {
- my @lines = intersect(@_);
- #$_->a->[X] = sprintf('%.0f', $_->a->[X]) for @lines;
- #$_->a->[Y] = sprintf('%.0f', $_->a->[Y]) for @lines;
- $_->[Slic3r::TriangleMesh::I_B][X] = sprintf('%.0f', $_->[Slic3r::TriangleMesh::I_B][X]) for @lines;
- $_->[Slic3r::TriangleMesh::I_B][Y] = sprintf('%.0f', $_->[Slic3r::TriangleMesh::I_B][Y]) for @lines;
- return [ map [ -1, $_->[Slic3r::TriangleMesh::I_B] ], @lines ];
-}
-
-sub line_plane_intersection {
- my ($line) = @_;
- @$line = map $mesh->vertices->[$_], @$line;
-
- return [
- map sprintf('%.0f', $_),
- map +($line->[1][$_] + ($line->[0][$_] - $line->[1][$_]) * ($z - $line->[1][Z]) / ($line->[0][Z] - $line->[1][Z])),
- (X,Y)
- ];
-}
-
-__END__
diff --git a/t/support.t b/t/support.t
deleted file mode 100644
index 0283df22b1..0000000000
--- a/t/support.t
+++ /dev/null
@@ -1,272 +0,0 @@
-use Test::More;
-use strict;
-use warnings;
-
-plan skip_all => 'temporarily disabled';
-plan tests => 27;
-
-BEGIN {
- use FindBin;
- use lib "$FindBin::Bin/../lib";
- use local::lib "$FindBin::Bin/../local-lib";
-}
-
-use List::Util qw(first);
-use Slic3r;
-use Slic3r::Flow ':roles';
-use Slic3r::Geometry qw(epsilon scale);
-use Slic3r::Geometry::Clipper qw(diff);
-use Slic3r::Test;
-
-{
- my $config = Slic3r::Config::new_from_defaults;
- $config->set('support_material', 1);
- my @contact_z = my @top_z = ();
-
- my $test = sub {
- my $print = Slic3r::Test::init_print('20mm_cube', config => $config);
- my $object_config = $print->print->objects->[0]->config;
- my $flow = Slic3r::Flow->new_from_width(
- width => $object_config->support_material_extrusion_width || $object_config->extrusion_width,
- role => FLOW_ROLE_SUPPORT_MATERIAL,
- nozzle_diameter => $print->config->nozzle_diameter->[$object_config->support_material_extruder-1] // $print->config->nozzle_diameter->[0],
- layer_height => $object_config->layer_height,
- );
- my $support = Slic3r::Print::SupportMaterial->new(
- object_config => $print->print->objects->[0]->config,
- print_config => $print->print->config,
- flow => $flow,
- interface_flow => $flow,
- first_layer_flow => $flow,
- );
- my $support_z = $support->support_layers_z($print->print->objects->[0], \@contact_z, \@top_z, $config->layer_height);
- my $expected_top_spacing = $support->contact_distance($config->layer_height, $config->nozzle_diameter->[0]);
-
- is $support_z->[0], $config->first_layer_height,
- 'first layer height is honored';
- is scalar(grep { $support_z->[$_]-$support_z->[$_-1] <= 0 } 1..$#$support_z), 0,
- 'no null or negative support layers';
- is scalar(grep { $support_z->[$_]-$support_z->[$_-1] > $config->nozzle_diameter->[0] + epsilon } 1..$#$support_z), 0,
- 'no layers thicker than nozzle diameter';
-
- my $wrong_top_spacing = 0;
- foreach my $top_z (@top_z) {
- # find layer index of this top surface
- my $layer_id = first { abs($support_z->[$_] - $top_z) < epsilon } 0..$#$support_z;
-
- # check that first support layer above this top surface (or the next one) is spaced with nozzle diameter
- $wrong_top_spacing = 1
- if ($support_z->[$layer_id+1] - $support_z->[$layer_id]) != $expected_top_spacing
- && ($support_z->[$layer_id+2] - $support_z->[$layer_id]) != $expected_top_spacing;
- }
- ok !$wrong_top_spacing, 'layers above top surfaces are spaced correctly';
- };
-
- $config->set('layer_height', 0.2);
- $config->set('first_layer_height', 0.3);
- @contact_z = (1.9);
- @top_z = (1.1);
- $test->();
-
- $config->set('first_layer_height', 0.4);
- $test->();
-
- $config->set('layer_height', $config->nozzle_diameter->[0]);
- $test->();
-}
-
-{
- my $config = Slic3r::Config::new_from_defaults;
- $config->set('raft_layers', 3);
- $config->set('brim_width', 0);
- $config->set('skirts', 0);
- $config->set('support_material_extruder', 2);
- $config->set('support_material_interface_extruder', 2);
- $config->set('layer_height', 0.4);
- $config->set('first_layer_height', 0.4);
- my $print = Slic3r::Test::init_print('overhang', config => $config);
- ok my $gcode = Slic3r::Test::gcode($print), 'no conflict between raft/support and brim';
-
- my $tool = 0;
- Slic3r::GCode::Reader->new->parse($gcode, sub {
- my ($self, $cmd, $args, $info) = @_;
-
- if ($cmd =~ /^T(\d+)/) {
- $tool = $1;
- } elsif ($info->{extruding}) {
- if ($self->Z <= ($config->raft_layers * $config->layer_height)) {
- fail 'not extruding raft with support material extruder'
- if $tool != ($config->support_material_extruder-1);
- } else {
- fail 'support material exceeds raft layers'
- if $tool == $config->support_material_extruder-1;
- # TODO: we should test that full support is generated when we use raft too
- }
- }
- });
-}
-
-{
- my $config = Slic3r::Config::new_from_defaults;
- $config->set('skirts', 0);
- $config->set('raft_layers', 3);
- $config->set('support_material_pattern', 'honeycomb');
- $config->set('support_material_extrusion_width', 0.6);
- $config->set('first_layer_extrusion_width', '100%');
- $config->set('bridge_speed', 99);
- $config->set('cooling', [ 0 ]); # prevent speed alteration
- $config->set('first_layer_speed', '100%'); # prevent speed alteration
- $config->set('start_gcode', ''); # prevent any unexpected Z move
- my $print = Slic3r::Test::init_print('20mm_cube', config => $config);
-
- my $layer_id = -1; # so that first Z move sets this to 0
- my @raft = my @first_object_layer = ();
- my %first_object_layer_speeds = (); # F => 1
- Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub {
- my ($self, $cmd, $args, $info) = @_;
-
- if ($info->{extruding} && $info->{dist_XY} > 0) {
- if ($layer_id <= $config->raft_layers) {
- # this is a raft layer or the first object layer
- my $line = Slic3r::Line->new_scale([ $self->X, $self->Y ], [ $info->{new_X}, $info->{new_Y} ]);
- my @path = @{$line->grow(scale($config->support_material_extrusion_width/2))};
- if ($layer_id < $config->raft_layers) {
- # this is a raft layer
- push @raft, @path;
- } else {
- push @first_object_layer, @path;
- $first_object_layer_speeds{ $args->{F} // $self->F } = 1;
- }
- }
- } elsif ($cmd eq 'G1' && $info->{dist_Z} > 0) {
- $layer_id++;
- }
- });
-
- ok !@{diff(\@first_object_layer, \@raft)},
- 'first object layer is completely supported by raft';
- is scalar(keys %first_object_layer_speeds), 1,
- 'only one speed used in first object layer';
- ok +(keys %first_object_layer_speeds)[0] == $config->bridge_speed*60,
- 'bridge speed used in first object layer';
-}
-
-{
- my $config = Slic3r::Config::new_from_defaults;
- $config->set('skirts', 0);
- $config->set('layer_height', 0.35);
- $config->set('first_layer_height', 0.3);
- $config->set('nozzle_diameter', [0.5]);
- $config->set('support_material_extruder', 2);
- $config->set('support_material_interface_extruder', 2);
-
- my $test = sub {
- my ($raft_layers) = @_;
- $config->set('raft_layers', $raft_layers);
- my $print = Slic3r::Test::init_print('20mm_cube', config => $config);
- my %raft_z = (); # z => 1
- my $tool = undef;
- Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub {
- my ($self, $cmd, $args, $info) = @_;
-
- if ($cmd =~ /^T(\d+)/) {
- $tool = $1;
- } elsif ($info->{extruding} && $info->{dist_XY} > 0) {
- if ($tool == $config->support_material_extruder-1) {
- $raft_z{$self->Z} = 1;
- }
- }
- });
-
- is scalar(keys %raft_z), $config->raft_layers, 'correct number of raft layers is generated';
- };
-
- $test->(2);
- $test->(70);
-
- $config->set('layer_height', 0.4);
- $config->set('first_layer_height', 0.35);
- $test->(3);
- $test->(70);
-}
-
-{
- my $config = Slic3r::Config::new_from_defaults;
- $config->set('brim_width', 0);
- $config->set('skirts', 0);
- $config->set('support_material', 1);
- $config->set('top_solid_layers', 0); # so that we don't have the internal bridge over infill
- $config->set('bridge_speed', 99);
- $config->set('cooling', [ 0 ]);
- $config->set('first_layer_speed', '100%');
-
- my $test = sub {
- my $print = Slic3r::Test::init_print('overhang', config => $config);
-
- my $has_bridge_speed = 0;
- Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub {
- my ($self, $cmd, $args, $info) = @_;
-
- if ($info->{extruding}) {
- if (($args->{F} // $self->F) == $config->bridge_speed*60) {
- $has_bridge_speed = 1;
- }
- }
- });
- return $has_bridge_speed;
- };
-
- $config->set('support_material_contact_distance', 0.2);
- ok $test->(), 'bridge speed is used when support_material_contact_distance > 0';
-
- $config->set('support_material_contact_distance', 0);
- ok !$test->(), 'bridge speed is not used when support_material_contact_distance == 0';
-
- $config->set('raft_layers', 5);
- $config->set('support_material_contact_distance', 0.2);
- ok $test->(), 'bridge speed is used when raft_layers > 0 and support_material_contact_distance > 0';
-
- $config->set('support_material_contact_distance', 0);
- ok !$test->(), 'bridge speed is not used when raft_layers > 0 and support_material_contact_distance == 0';
-}
-
-{
- my $config = Slic3r::Config::new_from_defaults;
- $config->set('skirts', 0);
- $config->set('start_gcode', '');
- $config->set('raft_layers', 8);
- $config->set('nozzle_diameter', [0.4, 1]);
- $config->set('layer_height', 0.1);
- $config->set('first_layer_height', 0.8);
- $config->set('support_material_extruder', 2);
- $config->set('support_material_interface_extruder', 2);
- $config->set('support_material_contact_distance', 0);
- my $print = Slic3r::Test::init_print('20mm_cube', config => $config);
- ok my $gcode = Slic3r::Test::gcode($print), 'first_layer_height is validated with support material extruder nozzle diameter when using raft layers';
-
- my $tool = undef;
- my @z = (0);
- my %layer_heights_by_tool = (); # tool => [ lh, lh... ]
- Slic3r::GCode::Reader->new->parse($gcode, sub {
- my ($self, $cmd, $args, $info) = @_;
-
- if ($cmd =~ /^T(\d+)/) {
- $tool = $1;
- } elsif ($cmd eq 'G1' && exists $args->{Z} && $args->{Z} != $self->Z) {
- push @z, $args->{Z};
- } elsif ($info->{extruding} && $info->{dist_XY} > 0) {
- $layer_heights_by_tool{$tool} ||= [];
- push @{ $layer_heights_by_tool{$tool} }, $z[-1] - $z[-2];
- }
- });
-
- ok !defined(first { $_ > $config->nozzle_diameter->[0] + epsilon }
- @{ $layer_heights_by_tool{$config->perimeter_extruder-1} }),
- 'no object layer is thicker than nozzle diameter';
-
- ok !defined(first { abs($_ - $config->layer_height) < epsilon }
- @{ $layer_heights_by_tool{$config->support_material_extruder-1} }),
- 'no support material layer is as thin as object layers';
-}
-
-__END__
diff --git a/tests/fff_print/CMakeLists.txt b/tests/fff_print/CMakeLists.txt
index 50b45e384c..9e039c913b 100644
--- a/tests/fff_print/CMakeLists.txt
+++ b/tests/fff_print/CMakeLists.txt
@@ -1,6 +1,8 @@
get_filename_component(_TEST_NAME ${CMAKE_CURRENT_LIST_DIR} NAME)
add_executable(${_TEST_NAME}_tests
${_TEST_NAME}_tests.cpp
+ test_avoid_crossing_perimeters.cpp
+ test_bridges.cpp
test_data.cpp
test_data.hpp
test_extrusion_entity.cpp
@@ -10,6 +12,8 @@ add_executable(${_TEST_NAME}_tests
test_gcodefindreplace.cpp
test_gcodewriter.cpp
test_model.cpp
+ test_multi.cpp
+ test_perimeters.cpp
test_print.cpp
test_printgcode.cpp
test_printobject.cpp
diff --git a/tests/fff_print/test_avoid_crossing_perimeters.cpp b/tests/fff_print/test_avoid_crossing_perimeters.cpp
new file mode 100644
index 0000000000..a76ac12b53
--- /dev/null
+++ b/tests/fff_print/test_avoid_crossing_perimeters.cpp
@@ -0,0 +1,16 @@
+#include
+
+#include "test_data.hpp"
+
+using namespace Slic3r;
+
+SCENARIO("Avoid crossing perimeters", "[AvoidCrossingPerimeters]") {
+ WHEN("Two 20mm cubes sliced") {
+ std::string gcode = Slic3r::Test::slice(
+ { Slic3r::Test::TestMesh::cube_20x20x20, Slic3r::Test::TestMesh::cube_20x20x20 },
+ { { "avoid_crossing_perimeters", true } });
+ THEN("gcode not empty") {
+ REQUIRE(! gcode.empty());
+ }
+ }
+}
diff --git a/tests/fff_print/test_bridges.cpp b/tests/fff_print/test_bridges.cpp
new file mode 100644
index 0000000000..91ab9b6b29
--- /dev/null
+++ b/tests/fff_print/test_bridges.cpp
@@ -0,0 +1,133 @@
+#include
+
+#include
+#include
+
+#include "test_data.hpp"
+
+using namespace Slic3r;
+
+SCENARIO("Bridge detector", "[Bridging]")
+{
+ auto check_angle = [](const ExPolygons &lower, const ExPolygon &bridge, double expected, double tolerance = -1, double expected_coverage = -1)
+ {
+ if (expected_coverage < 0)
+ expected_coverage = bridge.area();
+
+ BridgeDetector bridge_detector(bridge, lower, scaled(0.5)); // extrusion width
+ if (tolerance < 0)
+ tolerance = Geometry::rad2deg(bridge_detector.resolution) + EPSILON;
+
+ bridge_detector.detect_angle();
+ double result = bridge_detector.angle;
+ Polygons coverage = bridge_detector.coverage();
+ THEN("correct coverage area") {
+ REQUIRE(is_approx(area(coverage), expected_coverage));
+ }
+ // our epsilon is equal to the steps used by the bridge detection algorithm
+ //##use XXX; YYY [ rad2deg($result), $expected ];
+ // returned value must be non-negative, check for that too
+ double delta = Geometry::rad2deg(result) - expected;
+ if (delta >= 180. - EPSILON)
+ delta -= 180;
+ return result >= 0. && std::abs(delta) < tolerance;
+ };
+ GIVEN("O-shaped overhang") {
+ auto test = [&check_angle](const Point &size, double rotate, double expected_angle, double tolerance = -1) {
+ ExPolygon lower{
+ Polygon::new_scale({ {-2,-2}, {size.x()+2,-2}, {size.x()+2,size.y()+2}, {-2,size.y()+2} }),
+ Polygon::new_scale({ {0,0}, {0,size.y()}, {size.x(),size.y()}, {size.x(),0} } )
+ };
+ lower.rotate(Geometry::deg2rad(rotate), size / 2);
+ ExPolygon bridge_expoly(lower.holes.front());
+ bridge_expoly.contour.reverse();
+ return check_angle({ lower }, bridge_expoly, expected_angle, tolerance);
+ };
+ WHEN("Bridge size 20x10") {
+ bool valid = test({20,10}, 0., 90.);
+ THEN("bridging angle is 90 degrees") {
+ REQUIRE(valid);
+ }
+ }
+ WHEN("Bridge size 10x20") {
+ bool valid = test({10,20}, 0., 0.);
+ THEN("bridging angle is 0 degrees") {
+ REQUIRE(valid);
+ }
+ }
+ WHEN("Bridge size 20x10, rotated by 45 degrees") {
+ bool valid = test({20,10}, 45., 135., 20.);
+ THEN("bridging angle is 135 degrees") {
+ REQUIRE(valid);
+ }
+ }
+ WHEN("Bridge size 20x10, rotated by 135 degrees") {
+ bool valid = test({20,10}, 135., 45., 20.);
+ THEN("bridging angle is 45 degrees") {
+ REQUIRE(valid);
+ }
+ }
+ }
+ GIVEN("two-sided bridge") {
+ ExPolygon bridge{ Polygon::new_scale({ {0,0}, {20,0}, {20,10}, {0,10} }) };
+ ExPolygons lower { ExPolygon{ Polygon::new_scale({ {-2,0}, {0,0}, {0,10}, {-2,10} }) } };
+ lower.emplace_back(lower.front());
+ lower.back().translate(Point::new_scale(22, 0));
+ THEN("Bridging angle 0 degrees") {
+ REQUIRE(check_angle(lower, bridge, 0));
+ }
+ }
+ GIVEN("for C-shaped overhang") {
+ ExPolygon bridge{ Polygon::new_scale({ {0,0}, {20,0}, {10,10}, {0,10} }) };
+ ExPolygon lower{ Polygon::new_scale({ {0,0}, {0,10}, {10,10}, {10,12}, {-2,12}, {-2,-2}, {22,-2}, {22,0} }) };
+ bool valid = check_angle({ lower }, bridge, 135);
+ THEN("Bridging angle is 135 degrees") {
+ REQUIRE(valid);
+ }
+ }
+ GIVEN("square overhang with L-shaped anchors") {
+ ExPolygon bridge{ Polygon::new_scale({ {10,10}, {20,10}, {20,20}, {10,20} }) };
+ ExPolygon lower{ Polygon::new_scale({ {10,10}, {10,20}, {20,20}, {30,30}, {0,30}, {0,0} }) };
+ bool valid = check_angle({ lower }, bridge, 45., -1., bridge.area() / 2.);
+ THEN("Bridging angle is 45 degrees") {
+ REQUIRE(valid);
+ }
+ }
+}
+
+SCENARIO("Bridging integration", "[Bridging]") {
+ DynamicPrintConfig config = Slic3r::DynamicPrintConfig::full_print_config_with({
+ { "top_solid_layers", 0 },
+ // to prevent bridging on sparse infill
+ { "bridge_speed", 99 }
+ });
+
+ std::string gcode = Slic3r::Test::slice({ Slic3r::Test::TestMesh::bridge }, config);
+
+ GCodeReader parser;
+ const double bridge_speed = config.opt_float("bridge_speed") * 60.;
+ // angle => length
+ std::map extrusions;
+ parser.parse_buffer(gcode, [&extrusions, bridge_speed](Slic3r::GCodeReader &self, const Slic3r::GCodeReader::GCodeLine &line)
+ {
+ // if the command is a T command, set the the current tool
+ if (line.cmd() == "G1" && is_approx(bridge_speed, line.new_F(self))) {
+ // Accumulate lengths of bridging extrusions according to bridging angle.
+ Line l{ self.xy_scaled(), line.new_XY_scaled(self) };
+ size_t angle = scaled(l.direction());
+ auto it = extrusions.find(angle);
+ if (it == extrusions.end())
+ it = extrusions.insert(std::make_pair(angle, 0.)).first;
+ it->second += l.length();
+ }
+ });
+ THEN("bridge is generated") {
+ REQUIRE(! extrusions.empty());
+ }
+ THEN("bridge has the expected direction 0 degrees") {
+ // Bridging with the longest extrusion.
+ auto it_longest_extrusion = std::max_element(extrusions.begin(), extrusions.end(),
+ [](const auto &e1, const auto &e2){ return e1.second < e2.second; });
+ REQUIRE(it_longest_extrusion->first == 0);
+ }
+}
diff --git a/tests/fff_print/test_extrusion_entity.cpp b/tests/fff_print/test_extrusion_entity.cpp
index 7e0ca822fc..c98e0ec1a4 100644
--- a/tests/fff_print/test_extrusion_entity.cpp
+++ b/tests/fff_print/test_extrusion_entity.cpp
@@ -140,4 +140,11 @@ TEST_CASE("ExtrusionEntityCollection: Chained path", "[ExtrusionEntity]") {
REQUIRE(p1 == p2);
}
}
-}
\ No newline at end of file
+}
+
+TEST_CASE("ExtrusionEntityCollection: Chained path with no explicit starting point", "[ExtrusionEntity]") {
+ auto polylines = Polylines { { { 0, 15 }, {0, 18}, {0, 20} }, { { 0, 10 }, {0, 8}, {0, 5} } };
+ auto target = Polylines { { {0, 5}, {0, 8}, { 0, 10 } }, { { 0, 15 }, {0, 18}, {0, 20} } };
+ auto chained = chain_polylines(polylines);
+ REQUIRE(chained == target);
+}
diff --git a/tests/fff_print/test_fill.cpp b/tests/fff_print/test_fill.cpp
index 9f30bf8be7..c3af6e8fc5 100644
--- a/tests/fff_print/test_fill.cpp
+++ b/tests/fff_print/test_fill.cpp
@@ -197,8 +197,7 @@ TEST_CASE("Fill: Pattern Path Length", "[Fill]") {
SCENARIO("Infill does not exceed perimeters", "[Fill]")
{
auto test = [](const std::string_view pattern) {
- DynamicPrintConfig config = Slic3r::DynamicPrintConfig::full_print_config();
- config.set_deserialize_strict({
+ DynamicPrintConfig config = Slic3r::DynamicPrintConfig::full_print_config_with({
{ "nozzle_diameter", "0.4, 0.4, 0.4, 0.4" },
{ "fill_pattern", pattern },
{ "top_fill_pattern", pattern },
diff --git a/tests/fff_print/test_multi.cpp b/tests/fff_print/test_multi.cpp
new file mode 100644
index 0000000000..03c7f644b0
--- /dev/null
+++ b/tests/fff_print/test_multi.cpp
@@ -0,0 +1,268 @@
+#include
+
+#include
+#include
+
+#include "libslic3r/ClipperUtils.hpp"
+#include "libslic3r/Geometry.hpp"
+#include "libslic3r/Geometry/ConvexHull.hpp"
+#include "libslic3r/Print.hpp"
+#include "libslic3r/libslic3r.h"
+
+#include "test_data.hpp"
+
+using namespace Slic3r;
+using namespace std::literals;
+
+SCENARIO("Basic tests", "[Multi]")
+{
+ WHEN("Slicing multi-material print with non-consecutive extruders") {
+ std::string gcode = Slic3r::Test::slice({ Slic3r::Test::TestMesh::cube_20x20x20 },
+ {
+ { "nozzle_diameter", "0.6, 0.6, 0.6, 0.6" },
+ { "extruder", 2 },
+ { "infill_extruder", 4 },
+ { "support_material_extruder", 0 }
+ });
+ THEN("Sliced successfully") {
+ REQUIRE(! gcode.empty());
+ }
+ THEN("T3 toolchange command found") {
+ bool T1_found = gcode.find("\nT3\n") != gcode.npos;
+ REQUIRE(T1_found);
+ }
+ }
+ WHEN("Slicing with multiple skirts with a single, non-zero extruder") {
+ std::string gcode = Slic3r::Test::slice({ Slic3r::Test::TestMesh::cube_20x20x20 },
+ {
+ { "nozzle_diameter", "0.6, 0.6, 0.6, 0.6" },
+ { "perimeter_extruder", 2 },
+ { "infill_extruder", 2 },
+ { "support_material_extruder", 2 },
+ { "support_material_interface_extruder", 2 },
+ });
+ THEN("Sliced successfully") {
+ REQUIRE(! gcode.empty());
+ }
+ }
+}
+
+SCENARIO("Ooze prevention", "[Multi]")
+{
+ DynamicPrintConfig config = Slic3r::DynamicPrintConfig::full_print_config_with({
+ { "nozzle_diameter", "0.6, 0.6, 0.6, 0.6" },
+ { "raft_layers", 2 },
+ { "infill_extruder", 2 },
+ { "solid_infill_extruder", 3 },
+ { "support_material_extruder", 4 },
+ { "ooze_prevention", 1 },
+ { "extruder_offset", "0x0, 20x0, 0x20, 20x20" },
+ { "temperature", "200, 180, 170, 160" },
+ { "first_layer_temperature", "206, 186, 166, 156" },
+ // test that it doesn't crash when this is supplied
+ { "toolchange_gcode", "T[next_extruder] ;toolchange" }
+ });
+ FullPrintConfig print_config;
+ print_config.apply(config);
+
+ // Since July 2019, PrusaSlicer only emits automatic Tn command in case that the toolchange_gcode is empty
+ // The "T[next_extruder]" is therefore needed in this test.
+
+ std::string gcode = Slic3r::Test::slice({ Slic3r::Test::TestMesh::cube_20x20x20 }, config);
+
+ GCodeReader parser;
+ int tool = -1;
+ int tool_temp[] = { 0, 0, 0, 0};
+ Points toolchange_points;
+ Points extrusion_points;
+ parser.parse_buffer(gcode, [&tool, &tool_temp, &toolchange_points, &extrusion_points, &print_config]
+ (Slic3r::GCodeReader &self, const Slic3r::GCodeReader::GCodeLine &line)
+ {
+ // if the command is a T command, set the the current tool
+ if (boost::starts_with(line.cmd(), "T")) {
+ // Ignore initial toolchange.
+ if (tool != -1) {
+ int expected_temp = is_approx(self.z(), print_config.get_abs_value("first_layer_height") + print_config.z_offset) ?
+ print_config.first_layer_temperature.get_at(tool) :
+ print_config.temperature.get_at(tool);
+ if (tool_temp[tool] != expected_temp + print_config.standby_temperature_delta)
+ throw std::runtime_error("Standby temperature was not set before toolchange.");
+ toolchange_points.emplace_back(self.xy_scaled());
+ }
+ tool = atoi(line.cmd().data() + 1);
+ } else if (line.cmd_is("M104") || line.cmd_is("M109")) {
+ // May not be defined on this line.
+ int t = tool;
+ line.has_value('T', t);
+ // Should be available on this line.
+ int s;
+ if (! line.has_value('S', s))
+ throw std::runtime_error("M104 or M109 without S");
+ if (tool_temp[t] == 0 && s != print_config.first_layer_temperature.get_at(t) + print_config.standby_temperature_delta)
+ throw std::runtime_error("initial temperature is not equal to first layer temperature + standby delta");
+ tool_temp[t] = s;
+ } else if (line.cmd_is("G1") && line.extruding(self) && line.dist_XY(self) > 0) {
+ extrusion_points.emplace_back(line.new_XY_scaled(self) + scaled(print_config.extruder_offset.get_at(tool)));
+ }
+ });
+
+ Polygon convex_hull = Geometry::convex_hull(extrusion_points);
+
+ THEN("all nozzles are outside skirt at toolchange") {
+ Points t;
+ sort_remove_duplicates(toolchange_points);
+ size_t inside = 0;
+ for (const auto &point : toolchange_points)
+ for (const Vec2d &offset : print_config.extruder_offset.values) {
+ Point p = point + scaled(offset);
+ if (convex_hull.contains(p))
+ ++ inside;
+ }
+ REQUIRE(inside == 0);
+ }
+
+#if 0
+ require "Slic3r/SVG.pm";
+ Slic3r::SVG::output(
+ "ooze_prevention_test.svg",
+ no_arrows => 1,
+ polygons => [$convex_hull],
+ red_points => \@t,
+ points => \@toolchange_points,
+ );
+#endif
+
+ THEN("all toolchanges happen within expected area") {
+ // offset the skirt by the maximum displacement between extruders plus a safety extra margin
+ const float delta = scaled(20. * sqrt(2.) + 1.);
+ Polygon outer_convex_hull = expand(convex_hull, delta).front();
+ size_t inside = std::count_if(toolchange_points.begin(), toolchange_points.end(), [&outer_convex_hull](const Point &p){ return outer_convex_hull.contains(p); });
+ REQUIRE(inside == toolchange_points.size());
+ }
+}
+
+std::string slice_stacked_cubes(const DynamicPrintConfig &config, const DynamicPrintConfig &volume1config, const DynamicPrintConfig &volume2config)
+{
+ Model model;
+ ModelObject *object = model.add_object();
+ object->name = "object.stl";
+ ModelVolume *v1 = object->add_volume(Test::mesh(Test::TestMesh::cube_20x20x20));
+ v1->set_material_id("lower_material");
+ v1->config.assign_config(volume1config);
+ ModelVolume *v2 = object->add_volume(Test::mesh(Test::TestMesh::cube_20x20x20));
+ v2->set_material_id("upper_material");
+ v2->translate(0., 0., 20.);
+ v2->config.assign_config(volume2config);
+ object->add_instance();
+ object->ensure_on_bed();
+ Print print;
+ print.auto_assign_extruders(object);
+ THEN("auto_assign_extruders() assigned correct extruder to first volume") {
+ REQUIRE(v1->config.extruder() == 1);
+ }
+ THEN("auto_assign_extruders() assigned correct extruder to second volume") {
+ REQUIRE(v2->config.extruder() == 2);
+ }
+ print.apply(model, config);
+ print.validate();
+ return Test::gcode(print);
+}
+
+SCENARIO("Stacked cubes", "[Multi]")
+{
+ DynamicPrintConfig lower_config;
+ lower_config.set_deserialize_strict({
+ { "extruder", 1 },
+ { "bottom_solid_layers", 0 },
+ { "top_solid_layers", 1 },
+ });
+
+ DynamicPrintConfig upper_config;
+ upper_config.set_deserialize_strict({
+ { "extruder", 2 },
+ { "bottom_solid_layers", 1 },
+ { "top_solid_layers", 0 }
+ });
+
+ static constexpr const double solid_infill_speed = 99;
+ auto config = Slic3r::DynamicPrintConfig::full_print_config_with({
+ { "nozzle_diameter", "0.6, 0.6, 0.6, 0.6" },
+ { "fill_density", 0 },
+ { "solid_infill_speed", solid_infill_speed },
+ { "top_solid_infill_speed", solid_infill_speed },
+ // for preventing speeds from being altered
+ { "cooling", "0, 0, 0, 0" },
+ // for preventing speeds from being altered
+ { "first_layer_speed", "100%" }
+ });
+
+ auto test_shells = [](const std::string &gcode) {
+ GCodeReader parser;
+ int tool = -1;
+ // Scaled Z heights.
+ std::set T0_shells, T1_shells;
+ parser.parse_buffer(gcode, [&tool, &T0_shells, &T1_shells]
+ (Slic3r::GCodeReader &self, const Slic3r::GCodeReader::GCodeLine &line)
+ {
+ if (boost::starts_with(line.cmd(), "T")) {
+ tool = atoi(line.cmd().data() + 1);
+ } else if (line.cmd() == "G1" && line.extruding(self) && line.dist_XY(self) > 0) {
+ if (is_approx(line.new_F(self), solid_infill_speed * 60.) && (tool == 0 || tool == 1))
+ (tool == 0 ? T0_shells : T1_shells).insert(scaled(self.z()));
+ }
+ });
+ return std::make_pair(T0_shells, T1_shells);
+ };
+
+ WHEN("Interface shells disabled") {
+ std::string gcode = slice_stacked_cubes(config, lower_config, upper_config);
+ auto [t0, t1] = test_shells(gcode);
+ THEN("no interface shells") {
+ REQUIRE(t0.empty());
+ REQUIRE(t1.empty());
+ }
+ }
+ WHEN("Interface shells enabled") {
+ config.set_deserialize_strict("interface_shells", "1");
+ std::string gcode = slice_stacked_cubes(config, lower_config, upper_config);
+ auto [t0, t1] = test_shells(gcode);
+ THEN("top interface shells") {
+ REQUIRE(t0.size() == lower_config.opt_int("top_solid_layers"));
+ }
+ THEN("bottom interface shells") {
+ REQUIRE(t1.size() == upper_config.opt_int("bottom_solid_layers"));
+ }
+ }
+ WHEN("Slicing with auto-assigned extruders") {
+ auto config = Slic3r::DynamicPrintConfig::full_print_config_with({
+ { "nozzle_diameter", "0.6,0.6,0.6,0.6" },
+ { "layer_height", 0.4 },
+ { "first_layer_height", 0.4 },
+ { "skirts", 0 }
+ });
+ std::string gcode = slice_stacked_cubes(config, DynamicPrintConfig{}, DynamicPrintConfig{});
+ GCodeReader parser;
+ int tool = -1;
+ // Scaled Z heights.
+ std::set T0_shells, T1_shells;
+ parser.parse_buffer(gcode, [&tool, &T0_shells, &T1_shells](Slic3r::GCodeReader &self, const Slic3r::GCodeReader::GCodeLine &line)
+ {
+ if (boost::starts_with(line.cmd(), "T")) {
+ tool = atoi(line.cmd().data() + 1);
+ } else if (line.cmd() == "G1" && line.extruding(self) && line.dist_XY(self) > 0) {
+ if (tool == 0 && self.z() > 20)
+ // Layers incorrectly extruded with T0 at the top object.
+ T0_shells.insert(scaled(self.z()));
+ else if (tool == 1 && self.z() < 20)
+ // Layers incorrectly extruded with T1 at the bottom object.
+ T1_shells.insert(scaled(self.z()));
+ }
+ });
+ THEN("T0 is never used for upper object") {
+ REQUIRE(T0_shells.empty());
+ }
+ THEN("T0 is never used for lower object") {
+ REQUIRE(T1_shells.empty());
+ }
+ }
+}
diff --git a/tests/fff_print/test_perimeters.cpp b/tests/fff_print/test_perimeters.cpp
new file mode 100644
index 0000000000..a3f11113aa
--- /dev/null
+++ b/tests/fff_print/test_perimeters.cpp
@@ -0,0 +1,599 @@
+#include
+
+#include
+#include
+
+#include "libslic3r/Config.hpp"
+#include "libslic3r/ClipperUtils.hpp"
+#include "libslic3r/Layer.hpp"
+#include "libslic3r/PerimeterGenerator.hpp"
+#include "libslic3r/Print.hpp"
+#include "libslic3r/PrintConfig.hpp"
+#include "libslic3r/SurfaceCollection.hpp"
+#include "libslic3r/libslic3r.h"
+
+#include "test_data.hpp"
+
+using namespace Slic3r;
+
+SCENARIO("Perimeter nesting", "[Perimeters]")
+{
+ struct TestData {
+ ExPolygons expolygons;
+ // expected number of loops
+ int total;
+ // expected number of external loops
+ int external;
+ // expected external perimeter
+ std::vector ext_order;
+ // expected number of internal contour loops
+ int cinternal;
+ // expected number of ccw loops
+ int ccw;
+ // expected ccw/cw order
+ std::vector ccw_order;
+ // expected nesting order
+ std::vector> nesting;
+ };
+
+ FullPrintConfig config;
+
+ auto test = [&config](const TestData &data) {
+ SurfaceCollection slices;
+ slices.append(data.expolygons, stInternal);
+
+ ExtrusionEntityCollection loops;
+ ExtrusionEntityCollection gap_fill;
+ SurfaceCollection fill_surfaces;
+ PerimeterGenerator perimeter_generator(
+ &slices,
+ 1., // layer height
+ Flow(1., 1., 1.),
+ static_cast(&config),
+ static_cast(&config),
+ static_cast(&config),
+ false, // spiral_vase
+ // output:
+ &loops, &gap_fill, &fill_surfaces);
+ perimeter_generator.process();
+
+ THEN("expected number of collections") {
+ REQUIRE(loops.entities.size() == data.expolygons.size());
+ }
+
+ loops = loops.flatten();
+ THEN("expected number of loops") {
+ REQUIRE(loops.entities.size() == data.total);
+ }
+ THEN("expected number of external loops") {
+ size_t num_external = std::count_if(loops.entities.begin(), loops.entities.end(),
+ [](const ExtrusionEntity *ee){ return ee->role() == erExternalPerimeter; });
+ REQUIRE(num_external == data.external);
+ }
+ THEN("expected external order") {
+ std::vector ext_order;
+ for (auto *ee : loops.entities)
+ ext_order.emplace_back(ee->role() == erExternalPerimeter);
+ REQUIRE(ext_order == data.ext_order);
+ }
+ THEN("expected number of internal contour loops") {
+ size_t cinternal = std::count_if(loops.entities.begin(), loops.entities.end(),
+ [](const ExtrusionEntity *ee){ return dynamic_cast(ee)->loop_role() == elrContourInternalPerimeter; });
+ REQUIRE(cinternal == data.cinternal);
+ }
+ THEN("expected number of ccw loops") {
+ size_t ccw = std::count_if(loops.entities.begin(), loops.entities.end(),
+ [](const ExtrusionEntity *ee){ return dynamic_cast(ee)->polygon().is_counter_clockwise(); });
+ REQUIRE(ccw == data.ccw);
+ }
+ THEN("expected ccw/cw order") {
+ std::vector ccw_order;
+ for (auto *ee : loops.entities)
+ ccw_order.emplace_back(dynamic_cast(ee)->polygon().is_counter_clockwise());
+ REQUIRE(ccw_order == data.ccw_order);
+ }
+ THEN("expected nesting order") {
+ for (const std::vector &nesting : data.nesting) {
+ for (size_t i = 1; i < nesting.size(); ++ i)
+ REQUIRE(dynamic_cast(loops.entities[nesting[i - 1]])->polygon().contains(loops.entities[nesting[i]]->first_point()));
+ }
+ }
+ };
+
+ WHEN("Rectangle") {
+ config.perimeters.value = 3;
+ TestData data;
+ data.expolygons = {
+ ExPolygon{ Polygon::new_scale({ {0,0}, {100,0}, {100,100}, {0,100} }) }
+ };
+ data.total = 3;
+ data.external = 1;
+ data.ext_order = { false, false, true };
+ data.cinternal = 1;
+ data.ccw = 3;
+ data.ccw_order = { true, true, true };
+ data.nesting = { { 2, 1, 0 } };
+ test(data);
+ }
+ WHEN("Rectangle with hole") {
+ config.perimeters.value = 3;
+ TestData data;
+ data.expolygons = {
+ ExPolygon{ Polygon::new_scale({ {0,0}, {100,0}, {100,100}, {0,100} }),
+ Polygon::new_scale({ {40,40}, {40,60}, {60,60}, {60,40} }) }
+ };
+ data.total = 6;
+ data.external = 2;
+ data.ext_order = { false, false, true, false, false, true };
+ data.cinternal = 1;
+ data.ccw = 3;
+ data.ccw_order = { false, false, false, true, true, true };
+ data.nesting = { { 5, 4, 3, 0, 1, 2 } };
+ test(data);
+ }
+ WHEN("Nested rectangles with holes") {
+ config.perimeters.value = 3;
+ TestData data;
+ data.expolygons = {
+ ExPolygon{ Polygon::new_scale({ {0,0}, {200,0}, {200,200}, {0,200} }),
+ Polygon::new_scale({ {20,20}, {20,180}, {180,180}, {180,20} }) },
+ ExPolygon{ Polygon::new_scale({ {50,50}, {150,50}, {150,150}, {50,150} }),
+ Polygon::new_scale({ {80,80}, {80,120}, {120,120}, {120,80} }) }
+ };
+ data.total = 4*3;
+ data.external = 4;
+ data.ext_order = { false, false, true, false, false, true, false, false, true, false, false, true };
+ data.cinternal = 2;
+ data.ccw = 2*3;
+ data.ccw_order = { false, false, false, true, true, true, false, false, false, true, true, true };
+ test(data);
+ }
+ WHEN("Rectangle with multiple holes") {
+ config.perimeters.value = 2;
+ TestData data;
+ ExPolygon expoly{ Polygon::new_scale({ {0,0}, {50,0}, {50,50}, {0,50} }) };
+ expoly.holes.emplace_back(Polygon::new_scale({ {7.5,7.5}, {7.5,12.5}, {12.5,12.5}, {12.5,7.5} }));
+ expoly.holes.emplace_back(Polygon::new_scale({ {7.5,17.5}, {7.5,22.5}, {12.5,22.5}, {12.5,17.5} }));
+ expoly.holes.emplace_back(Polygon::new_scale({ {7.5,27.5}, {7.5,32.5}, {12.5,32.5}, {12.5,27.5} }));
+ expoly.holes.emplace_back(Polygon::new_scale({ {7.5,37.5}, {7.5,42.5}, {12.5,42.5}, {12.5,37.5} }));
+ expoly.holes.emplace_back(Polygon::new_scale({ {17.5,7.5}, {17.5,12.5}, {22.5,12.5}, {22.5,7.5} }));
+ data.expolygons = { expoly };
+ data.total = 12;
+ data.external = 6;
+ data.ext_order = { false, true, false, true, false, true, false, true, false, true, false, true };
+ data.cinternal = 1;
+ data.ccw = 2;
+ data.ccw_order = { false, false, false, false, false, false, false, false, false, false, true, true };
+ data.nesting = { {0,1},{2,3},{4,5},{6,7},{8,9} };
+ test(data);
+ };
+}
+
+SCENARIO("Perimeters", "[Perimeters]")
+{
+ auto config = Slic3r::DynamicPrintConfig::full_print_config_with({
+ { "skirts", 0 },
+ { "fill_density", 0 },
+ { "perimeters", 3 },
+ { "top_solid_layers", 0 },
+ { "bottom_solid_layers", 0 },
+ // to prevent speeds from being altered
+ { "cooling", "0" },
+ // to prevent speeds from being altered
+ { "first_layer_speed", "100%" }
+ });
+
+ WHEN("Bridging perimeters disabled") {
+ std::string gcode = Slic3r::Test::slice({ Slic3r::Test::TestMesh::overhang }, config);
+
+ THEN("all perimeters extruded ccw") {
+ GCodeReader parser;
+ bool has_cw_loops = false;
+ Polygon current_loop;
+ parser.parse_buffer(gcode, [&has_cw_loops, ¤t_loop](Slic3r::GCodeReader &self, const Slic3r::GCodeReader::GCodeLine &line)
+ {
+ if (line.extruding(self) && line.dist_XY(self) > 0) {
+ if (current_loop.empty())
+ current_loop.points.emplace_back(self.xy_scaled());
+ current_loop.points.emplace_back(line.new_XY_scaled(self));
+ } else if (! line.cmd_is("M73")) {
+ // skips remaining time lines (M73)
+ if (! current_loop.empty() && current_loop.is_clockwise())
+ has_cw_loops = true;
+ current_loop.clear();
+ }
+ });
+ REQUIRE(! has_cw_loops);
+ }
+ }
+
+ auto test = [&config](Test::TestMesh model) {
+ // we test two copies to make sure ExtrusionLoop objects are not modified in-place (the second object would not detect cw loops and thus would calculate wrong)
+ std::string gcode = Slic3r::Test::slice({ model, model }, config);
+ GCodeReader parser;
+ bool has_cw_loops = false;
+ bool has_outwards_move = false;
+ bool starts_on_convex_point = false;
+ // print_z => count of external loops
+ std::map external_loops;
+ Polygon current_loop;
+ const double external_perimeter_speed = config.get_abs_value("external_perimeter_speed") * 60.;
+ parser.parse_buffer(gcode, [&has_cw_loops, &has_outwards_move, &starts_on_convex_point, &external_loops, ¤t_loop, external_perimeter_speed, model]
+ (Slic3r::GCodeReader &self, const Slic3r::GCodeReader::GCodeLine &line)
+ {
+ if (line.extruding(self) && line.dist_XY(self) > 0) {
+ if (current_loop.empty())
+ current_loop.points.emplace_back(self.xy_scaled());
+ current_loop.points.emplace_back(line.new_XY_scaled(self));
+ } else if (! line.cmd_is("M73")) {
+ // skips remaining time lines (M73)
+ if (! current_loop.empty()) {
+ if (current_loop.is_clockwise())
+ has_cw_loops = true;
+ if (is_approx(self.f(), external_perimeter_speed)) {
+ // reset counter for second object
+ coord_t z = scaled(self.z());
+ auto it = external_loops.find(z);
+ if (it == external_loops.end())
+ it = external_loops.insert(std::make_pair(z, 0)).first;
+ else if (it->second == 2)
+ it->second = 0;
+ ++ it->second;
+ bool is_contour = it->second == 2;
+ bool is_hole = it->second == 1;
+ // Testing whether the move point after loop ends up inside the extruded loop.
+ bool loop_contains_point = current_loop.contains(line.new_XY_scaled(self));
+ if (// contour should include destination
+ (! loop_contains_point && is_contour) ||
+ // hole should not
+ (loop_contains_point && is_hole))
+ has_outwards_move = true;
+ if (model == Test::TestMesh::cube_with_concave_hole) {
+ // check that loop starts at a concave vertex
+ double cross = cross2((current_loop.points.front() - current_loop.points[current_loop.points.size() - 2]).cast(), (current_loop.points[1] - current_loop.points.front()).cast());
+ bool convex = cross > 0.;
+ if ((convex && is_contour) || (! convex && is_hole))
+ starts_on_convex_point = true;
+ }
+ }
+ current_loop.clear();
+ }
+ }
+ });
+ THEN("all perimeters extruded ccw") {
+ REQUIRE(! has_cw_loops);
+ }
+ THEN("move inwards after completing external loop") {
+ REQUIRE(! has_outwards_move);
+ }
+ THEN("loops start on concave point if any") {
+ REQUIRE(! starts_on_convex_point);
+ }
+
+ };
+ // Reusing the config above.
+ config.set_deserialize_strict({
+ { "external_perimeter_speed", 68 }
+ });
+ GIVEN("Cube with hole") { test(Test::TestMesh::cube_with_hole); }
+ GIVEN("Cube with concave hole") { test(Test::TestMesh::cube_with_concave_hole); }
+
+ WHEN("Bridging perimeters enabled") {
+ // Reusing the config above.
+ config.set_deserialize_strict({
+ { "perimeters", 1 },
+ { "perimeter_speed", 77 },
+ { "external_perimeter_speed", 66 },
+ { "bridge_speed", 99 },
+ { "cooling", "1" },
+ { "fan_below_layer_time", "0" },
+ { "slowdown_below_layer_time", "0" },
+ { "bridge_fan_speed", "100" },
+ // arbitrary value
+ { "bridge_flow_ratio", 33 },
+ { "overhangs", true }
+ });
+
+ std::string gcode = Slic3r::Test::slice({ mesh(Slic3r::Test::TestMesh::overhang) }, config);
+
+ THEN("Bridging is applied to bridging perimeters") {
+ GCodeReader parser;
+ // print Z => speeds
+ std::map> layer_speeds;
+ int fan_speed = 0;
+ const double perimeter_speed = config.opt_float("perimeter_speed") * 60.;
+ const double external_perimeter_speed = config.get_abs_value("external_perimeter_speed") * 60.;
+ const double bridge_speed = config.opt_float("bridge_speed") * 60.;
+ const double nozzle_dmr = config.opt("nozzle_diameter")->get_at(0);
+ const double filament_dmr = config.opt("filament_diameter")->get_at(0);
+ const double bridge_mm_per_mm = sqr(nozzle_dmr / filament_dmr) * config.opt_float("bridge_flow_ratio");
+ parser.parse_buffer(gcode, [&layer_speeds, &fan_speed, perimeter_speed, external_perimeter_speed, bridge_speed, nozzle_dmr, filament_dmr, bridge_mm_per_mm]
+ (Slic3r::GCodeReader &self, const Slic3r::GCodeReader::GCodeLine &line)
+ {
+ if (line.cmd_is("M107"))
+ fan_speed = 0;
+ else if (line.cmd_is("M106"))
+ line.has_value('S', fan_speed);
+ else if (line.extruding(self) && line.dist_XY(self) > 0) {
+ double feedrate = line.new_F(self);
+ REQUIRE((is_approx(feedrate, perimeter_speed) || is_approx(feedrate, external_perimeter_speed) || is_approx(feedrate, bridge_speed)));
+ layer_speeds[self.z()].insert(feedrate);
+ bool bridging = is_approx(feedrate, bridge_speed);
+ double mm_per_mm = line.dist_E(self) / line.dist_XY(self);
+ // Fan enabled at full speed when bridging, disabled when not bridging.
+ REQUIRE((! bridging || fan_speed == 255));
+ REQUIRE((bridging || fan_speed == 0));
+ // When bridging, bridge flow is applied.
+ REQUIRE((! bridging || std::abs(mm_per_mm - bridge_mm_per_mm) <= 0.01));
+ }
+ });
+ // only overhang layer has more than one speed
+ size_t num_overhangs = std::count_if(layer_speeds.begin(), layer_speeds.end(), [](const std::pair> &v){ return v.second.size() > 1; });
+ REQUIRE(num_overhangs == 1);
+ }
+ }
+
+ GIVEN("iPad stand") {
+ WHEN("Extra perimeters enabled") {
+ auto config = Slic3r::DynamicPrintConfig::full_print_config_with({
+ { "skirts", 0 },
+ { "perimeters", 3 },
+ { "layer_height", 0.4 },
+ { "first_layer_height", 0.35 },
+ { "extra_perimeters", 1 },
+ // to prevent speeds from being altered
+ { "cooling", "0" },
+ // to prevent speeds from being altered
+ { "first_layer_speed", "100%" },
+ { "perimeter_speed", 99 },
+ { "external_perimeter_speed", 99 },
+ { "small_perimeter_speed", 99 },
+ { "thin_walls", 0 },
+ });
+
+ std::string gcode = Slic3r::Test::slice({ Slic3r::Test::TestMesh::ipadstand }, config);
+ // z => number of loops
+ std::map perimeters;
+ bool in_loop = false;
+ const double perimeter_speed = config.opt_float("perimeter_speed") * 60.;
+ GCodeReader parser;
+ parser.parse_buffer(gcode, [&perimeters, &in_loop, perimeter_speed](Slic3r::GCodeReader &self, const Slic3r::GCodeReader::GCodeLine &line)
+ {
+ if (line.extruding(self) && line.dist_XY(self) > 0 && is_approx(line.new_F(self), perimeter_speed)) {
+ if (! in_loop) {
+ coord_t z = scaled(self.z());
+ auto it = perimeters.find(z);
+ if (it == perimeters.end())
+ it = perimeters.insert(std::make_pair(z, 0)).first;
+ ++ it->second;
+ }
+ in_loop = true;
+ } else if (! line.cmd_is("M73")) {
+ // skips remaining time lines (M73)
+ in_loop = false;
+ }
+ });
+ THEN("no superfluous extra perimeters") {
+ const int num_perimeters = config.opt_int("perimeters");
+ size_t extra_perimeters = std::count_if(perimeters.begin(), perimeters.end(), [num_perimeters](const std::pair &v){ return (v.second % num_perimeters) > 0; });
+ REQUIRE(extra_perimeters == 0);
+ }
+ }
+ }
+}
+
+SCENARIO("Some weird coverage test", "[Perimeters]")
+{
+ auto config = Slic3r::DynamicPrintConfig::full_print_config_with({
+ { "nozzle_diameter", "0.4" },
+ { "perimeters", 2 },
+ { "perimeter_extrusion_width", 0.4 },
+ { "external_perimeter_extrusion_width", 0.4 },
+ { "infill_extrusion_width", 0.53 },
+ { "solid_infill_extrusion_width", 0.53 }
+ });
+
+ // we just need a pre-filled Print object
+ Print print;
+ Model model;
+ Slic3r::Test::init_print({ Test::TestMesh::cube_20x20x20 }, print, model, config);
+
+ // override a layer's slices
+ ExPolygon expolygon;
+ expolygon.contour = {
+ {-71974463,-139999376},{-71731792,-139987456},{-71706544,-139985616},{-71682119,-139982639},{-71441248,-139946912},{-71417487,-139942895},{-71379384,-139933984},{-71141800,-139874480},
+ {-71105247,-139862895},{-70873544,-139779984},{-70838592,-139765856},{-70614943,-139660064},{-70581783,-139643567},{-70368368,-139515680},{-70323751,-139487872},{-70122160,-139338352},
+ {-70082399,-139306639},{-69894800,-139136624},{-69878679,-139121327},{-69707992,-138933008},{-69668575,-138887343},{-69518775,-138685359},{-69484336,-138631632},{-69356423,-138418207},
+ {-69250040,-138193296},{-69220920,-138128976},{-69137992,-137897168},{-69126095,-137860255},{-69066568,-137622608},{-69057104,-137582511},{-69053079,-137558751},{-69017352,-137317872},
+ {-69014392,-137293456},{-69012543,-137268207},{-68999369,-137000000},{-63999999,-137000000},{-63705947,-136985551},{-63654984,-136977984},{-63414731,-136942351},{-63364756,-136929840},
+ {-63129151,-136870815},{-62851950,-136771631},{-62585807,-136645743},{-62377483,-136520895},{-62333291,-136494415},{-62291908,-136463728},{-62096819,-136319023},{-62058644,-136284432},
+ {-61878676,-136121328},{-61680968,-135903184},{-61650275,-135861807},{-61505591,-135666719},{-61354239,-135414191},{-61332211,-135367615},{-61228359,-135148063},{-61129179,-134870847},
+ {-61057639,-134585262},{-61014451,-134294047},{-61000000,-134000000},{-61000000,-107999999},{-61014451,-107705944},{-61057639,-107414736},{-61129179,-107129152},{-61228359,-106851953},
+ {-61354239,-106585808},{-61505591,-106333288},{-61680967,-106096816},{-61878675,-105878680},{-62096820,-105680967},{-62138204,-105650279},{-62333292,-105505591},{-62585808,-105354239},
+ {-62632384,-105332207},{-62851951,-105228360},{-62900463,-105211008},{-63129152,-105129183},{-63414731,-105057640},{-63705947,-105014448},{-63999999,-105000000},{-68999369,-105000000},
+ {-69012543,-104731792},{-69014392,-104706544},{-69017352,-104682119},{-69053079,-104441248},{-69057104,-104417487},{-69066008,-104379383},{-69125528,-104141799},{-69137111,-104105248},
+ {-69220007,-103873544},{-69234136,-103838591},{-69339920,-103614943},{-69356415,-103581784},{-69484328,-103368367},{-69512143,-103323752},{-69661647,-103122160},{-69693352,-103082399},
+ {-69863383,-102894800},{-69878680,-102878679},{-70066999,-102707992},{-70112656,-102668576},{-70314648,-102518775},{-70368367,-102484336},{-70581783,-102356424},{-70806711,-102250040},
+ {-70871040,-102220919},{-71102823,-102137992},{-71139752,-102126095},{-71377383,-102066568},{-71417487,-102057104},{-71441248,-102053079},{-71682119,-102017352},{-71706535,-102014392},
+ {-71731784,-102012543},{-71974456,-102000624},{-71999999,-102000000},{-104000000,-102000000},{-104025536,-102000624},{-104268207,-102012543},{-104293455,-102014392},
+ {-104317880,-102017352},{-104558751,-102053079},{-104582512,-102057104},{-104620616,-102066008},{-104858200,-102125528},{-104894751,-102137111},{-105126455,-102220007},
+ {-105161408,-102234136},{-105385056,-102339920},{-105418215,-102356415},{-105631632,-102484328},{-105676247,-102512143},{-105877839,-102661647},{-105917600,-102693352},
+ {-106105199,-102863383},{-106121320,-102878680},{-106292007,-103066999},{-106331424,-103112656},{-106481224,-103314648},{-106515663,-103368367},{-106643575,-103581783},
+ {-106749959,-103806711},{-106779080,-103871040},{-106862007,-104102823},{-106873904,-104139752},{-106933431,-104377383},{-106942896,-104417487},{-106946920,-104441248},
+ {-106982648,-104682119},{-106985607,-104706535},{-106987456,-104731784},{-107000630,-105000000},{-112000000,-105000000},{-112294056,-105014448},{-112585264,-105057640},
+ {-112870848,-105129184},{-112919359,-105146535},{-113148048,-105228360},{-113194624,-105250392},{-113414191,-105354239},{-113666711,-105505591},{-113708095,-105536279},
+ {-113903183,-105680967},{-114121320,-105878679},{-114319032,-106096816},{-114349720,-106138200},{-114494408,-106333288},{-114645760,-106585808},{-114667792,-106632384},
+ {-114771640,-106851952},{-114788991,-106900463},{-114870815,-107129151},{-114942359,-107414735},{-114985551,-107705943},{-115000000,-107999999},{-115000000,-134000000},
+ {-114985551,-134294048},{-114942359,-134585263},{-114870816,-134870847},{-114853464,-134919359},{-114771639,-135148064},{-114645759,-135414192},{-114494407,-135666720},
+ {-114319031,-135903184},{-114121320,-136121327},{-114083144,-136155919},{-113903184,-136319023},{-113861799,-136349712},{-113666711,-136494416},{-113458383,-136619264},
+ {-113414192,-136645743},{-113148049,-136771631},{-112870848,-136870815},{-112820872,-136883327},{-112585264,-136942351},{-112534303,-136949920},{-112294056,-136985551},
+ {-112000000,-137000000},{-107000630,-137000000},{-106987456,-137268207},{-106985608,-137293440},{-106982647,-137317872},{-106946920,-137558751},{-106942896,-137582511},
+ {-106933991,-137620624},{-106874471,-137858208},{-106862888,-137894751},{-106779992,-138126463},{-106765863,-138161424},{-106660080,-138385055},{-106643584,-138418223},
+ {-106515671,-138631648},{-106487855,-138676256},{-106338352,-138877839},{-106306647,-138917600},{-106136616,-139105199},{-106121320,-139121328},{-105933000,-139291999},
+ {-105887344,-139331407},{-105685351,-139481232},{-105631632,-139515663},{-105418216,-139643567},{-105193288,-139749951},{-105128959,-139779072},{-104897175,-139862016},
+ {-104860247,-139873904},{-104622616,-139933423},{-104582511,-139942896},{-104558751,-139946912},{-104317880,-139982656},{-104293463,-139985616},{-104268216,-139987456},
+ {-104025544,-139999376},{-104000000,-140000000},{-71999999,-140000000}
+ };
+ expolygon.holes = {
+ {{-105000000,-138000000},{-105000000,-104000000},{-71000000,-104000000},{-71000000,-138000000}},
+ {{-69000000,-132000000},{-69000000,-110000000},{-64991180,-110000000},{-64991180,-132000000}},
+ {{-111008824,-132000000},{-111008824,-110000000},{-107000000,-110000000},{-107000000,-132000000}}
+ };
+ PrintObject *object = print.get_object(0);
+ object->slice();
+ Layer *layer = object->get_layer(1);
+ LayerRegion *layerm = layer->get_region(0);
+ layerm->slices.clear();
+ layerm->slices.append({ expolygon }, stInternal);
+
+ // make perimeters
+ layer->make_perimeters();
+
+ // compute the covered area
+ Flow pflow = layerm->flow(frPerimeter);
+ Flow iflow = layerm->flow(frInfill);
+ Polygons covered_by_perimeters;
+ Polygons covered_by_infill;
+ {
+ Polygons acc;
+ for (const ExtrusionEntity *ee : layerm->perimeters.entities)
+ for (const ExtrusionEntity *ee : dynamic_cast(ee)->entities)
+ append(acc, offset(dynamic_cast(ee)->polygon().split_at_first_point(), float(pflow.scaled_width() / 2.f + SCALED_EPSILON)));
+ covered_by_perimeters = union_(acc);
+ }
+ {
+ Polygons acc;
+ for (const Surface &surface : layerm->fill_surfaces.surfaces)
+ append(acc, to_polygons(surface.expolygon));
+ for (const ExtrusionEntity *ee : layerm->thin_fills.entities)
+ append(acc, offset(dynamic_cast(ee)->polyline, float(iflow.scaled_width() / 2.f + SCALED_EPSILON)));
+ covered_by_infill = union_(acc);
+ }
+
+ // compute the non covered area
+ ExPolygons non_covered = diff_ex(to_polygons(layerm->slices.surfaces), union_(covered_by_perimeters, covered_by_infill));
+
+ /*
+ if (0) {
+ printf "max non covered = %f\n", List::Util::max(map unscale unscale $_->area, @$non_covered);
+ require "Slic3r/SVG.pm";
+ Slic3r::SVG::output(
+ "gaps.svg",
+ expolygons => [ map $_->expolygon, @{$layerm->slices} ],
+ red_expolygons => union_ex([ map @$_, (@$covered_by_perimeters, @$covered_by_infill) ]),
+ green_expolygons => union_ex($non_covered),
+ no_arrows => 1,
+ polylines => [
+ map $_->polygon->split_at_first_point, map @$_, @{$layerm->perimeters},
+ ],
+ );
+ }
+ */
+ THEN("no gap between perimeters and infill") {
+ size_t num_non_convered = std::count_if(non_covered.begin(), non_covered.end(), [&iflow](const ExPolygon &ex){ return ex.area() > sqr(double(iflow.scaled_width())); });
+ REQUIRE(num_non_convered == 0);
+ }
+}
+
+SCENARIO("Perimeters3", "[Perimeters]")
+{
+ auto config = Slic3r::DynamicPrintConfig::full_print_config_with({
+ { "skirts", 0 },
+ { "perimeters", 3 },
+ { "layer_height", 0.4 },
+ { "bridge_speed", 99 },
+ // to prevent bridging over sparse infill
+ { "fill_density", 0 },
+ { "overhangs", true },
+ // to prevent speeds from being altered
+ { "cooling", "0" },
+ // to prevent speeds from being altered
+ { "first_layer_speed", "100%" }
+ });
+
+ auto test = [&config](const Vec3d &scale) {
+ std::string gcode = Slic3r::Test::slice({ mesh(Slic3r::Test::TestMesh::V, Vec3d::Zero(), scale) }, config);
+ GCodeReader parser;
+ std::set z_with_bridges;
+ const double bridge_speed = config.opt_float("bridge_speed") * 60.;
+ parser.parse_buffer(gcode, [&z_with_bridges, bridge_speed](Slic3r::GCodeReader &self, const Slic3r::GCodeReader::GCodeLine &line)
+ {
+ if (line.extruding(self) && line.dist_XY(self) > 0 && is_approx(line.new_F(self), bridge_speed))
+ z_with_bridges.insert(scaled(self.z()));
+ });
+ return z_with_bridges.size();
+ };
+
+ GIVEN("V shape, unscaled") {
+ int n = test(Vec3d(1., 1., 1.));
+ // except for the two internal solid layers above void
+ THEN("no overhangs printed with bridge speed") {
+ REQUIRE(n == 1);
+ }
+ }
+ GIVEN("V shape, scaled 3x in X") {
+ int n = test(Vec3d(3., 1., 1.));
+ // except for the two internal solid layers above void
+ THEN("overhangs printed with bridge speed") {
+ REQUIRE(n > 2);
+ }
+ }
+}
+
+SCENARIO("Perimeters4", "[Perimeters]")
+{
+ auto config = Slic3r::DynamicPrintConfig::full_print_config_with({
+ { "seam_position", "random" }
+ });
+ std::string gcode = Slic3r::Test::slice({ Slic3r::Test::TestMesh::cube_20x20x20 }, config);
+ THEN("successful generation of G-code with seam_position = random") {
+ REQUIRE(! gcode.empty());
+ }
+}
+
+SCENARIO("Seam alignment", "[Perimeters]")
+{
+ auto test = [](Test::TestMesh model) {
+ auto config = Slic3r::DynamicPrintConfig::full_print_config_with({
+ { "seam_position", "aligned" },
+ { "skirts", 0 },
+ { "perimeters", 1 },
+ { "fill_density", 0 },
+ { "top_solid_layers", 0 },
+ { "bottom_solid_layers", 0 },
+ { "retract_layer_change", "0" }
+ });
+ std::string gcode = Slic3r::Test::slice({ model }, config);
+ bool was_extruding = false;
+ Points seam_points;
+ GCodeReader parser;
+ parser.parse_buffer(gcode, [&was_extruding, &seam_points](Slic3r::GCodeReader &self, const Slic3r::GCodeReader::GCodeLine &line)
+ {
+ if (line.extruding(self)) {
+ if (! was_extruding)
+ seam_points.emplace_back(self.xy_scaled());
+ was_extruding = true;
+ } else if (! line.cmd_is("M73")) {
+ // skips remaining time lines (M73)
+ was_extruding = false;
+ }
+ });
+ THEN("seam is aligned") {
+ size_t num_not_aligned = 0;
+ for (size_t i = 1; i < seam_points.size(); ++ i) {
+ double d = (seam_points[i] - seam_points[i - 1]).cast().norm();
+ // Seams shall be aligned up to 3mm.
+ if (d > scaled(3.))
+ ++ num_not_aligned;
+ }
+ REQUIRE(num_not_aligned == 0);
+ }
+ };
+
+ GIVEN("20mm cube") {
+ test(Slic3r::Test::TestMesh::cube_20x20x20);
+ }
+ GIVEN("small_dorito") {
+ test(Slic3r::Test::TestMesh::small_dorito);
+ }
+}
diff --git a/tests/fff_print/test_support_material.cpp b/tests/fff_print/test_support_material.cpp
index 442db7654f..c5087263c3 100644
--- a/tests/fff_print/test_support_material.cpp
+++ b/tests/fff_print/test_support_material.cpp
@@ -236,3 +236,262 @@ SCENARIO("SupportMaterial: Checking bridge speed", "[SupportMaterial]")
}
#endif
+
+
+/*
+
+Old Perl tests, which were disabled by Vojtech at the time of first Support Generator refactoring.
+
+#if 0
+{
+ my $config = Slic3r::Config::new_from_defaults;
+ $config->set('support_material', 1);
+ my @contact_z = my @top_z = ();
+
+ my $test = sub {
+ my $print = Slic3r::Test::init_print('20mm_cube', config => $config);
+ my $object_config = $print->print->objects->[0]->config;
+ my $flow = Slic3r::Flow->new_from_width(
+ width => $object_config->support_material_extrusion_width || $object_config->extrusion_width,
+ role => FLOW_ROLE_SUPPORT_MATERIAL,
+ nozzle_diameter => $print->config->nozzle_diameter->[$object_config->support_material_extruder-1] // $print->config->nozzle_diameter->[0],
+ layer_height => $object_config->layer_height,
+ );
+ my $support = Slic3r::Print::SupportMaterial->new(
+ object_config => $print->print->objects->[0]->config,
+ print_config => $print->print->config,
+ flow => $flow,
+ interface_flow => $flow,
+ first_layer_flow => $flow,
+ );
+ my $support_z = $support->support_layers_z($print->print->objects->[0], \@contact_z, \@top_z, $config->layer_height);
+ my $expected_top_spacing = $support->contact_distance($config->layer_height, $config->nozzle_diameter->[0]);
+
+ is $support_z->[0], $config->first_layer_height,
+ 'first layer height is honored';
+ is scalar(grep { $support_z->[$_]-$support_z->[$_-1] <= 0 } 1..$#$support_z), 0,
+ 'no null or negative support layers';
+ is scalar(grep { $support_z->[$_]-$support_z->[$_-1] > $config->nozzle_diameter->[0] + epsilon } 1..$#$support_z), 0,
+ 'no layers thicker than nozzle diameter';
+
+ my $wrong_top_spacing = 0;
+ foreach my $top_z (@top_z) {
+ # find layer index of this top surface
+ my $layer_id = first { abs($support_z->[$_] - $top_z) < epsilon } 0..$#$support_z;
+
+ # check that first support layer above this top surface (or the next one) is spaced with nozzle diameter
+ $wrong_top_spacing = 1
+ if ($support_z->[$layer_id+1] - $support_z->[$layer_id]) != $expected_top_spacing
+ && ($support_z->[$layer_id+2] - $support_z->[$layer_id]) != $expected_top_spacing;
+ }
+ ok !$wrong_top_spacing, 'layers above top surfaces are spaced correctly';
+ };
+
+ $config->set('layer_height', 0.2);
+ $config->set('first_layer_height', 0.3);
+ @contact_z = (1.9);
+ @top_z = (1.1);
+ $test->();
+
+ $config->set('first_layer_height', 0.4);
+ $test->();
+
+ $config->set('layer_height', $config->nozzle_diameter->[0]);
+ $test->();
+}
+
+{
+ my $config = Slic3r::Config::new_from_defaults;
+ $config->set('raft_layers', 3);
+ $config->set('brim_width', 0);
+ $config->set('skirts', 0);
+ $config->set('support_material_extruder', 2);
+ $config->set('support_material_interface_extruder', 2);
+ $config->set('layer_height', 0.4);
+ $config->set('first_layer_height', 0.4);
+ my $print = Slic3r::Test::init_print('overhang', config => $config);
+ ok my $gcode = Slic3r::Test::gcode($print), 'no conflict between raft/support and brim';
+
+ my $tool = 0;
+ Slic3r::GCode::Reader->new->parse($gcode, sub {
+ my ($self, $cmd, $args, $info) = @_;
+
+ if ($cmd =~ /^T(\d+)/) {
+ $tool = $1;
+ } elsif ($info->{extruding}) {
+ if ($self->Z <= ($config->raft_layers * $config->layer_height)) {
+ fail 'not extruding raft with support material extruder'
+ if $tool != ($config->support_material_extruder-1);
+ } else {
+ fail 'support material exceeds raft layers'
+ if $tool == $config->support_material_extruder-1;
+ # TODO: we should test that full support is generated when we use raft too
+ }
+ }
+ });
+}
+
+{
+ my $config = Slic3r::Config::new_from_defaults;
+ $config->set('skirts', 0);
+ $config->set('raft_layers', 3);
+ $config->set('support_material_pattern', 'honeycomb');
+ $config->set('support_material_extrusion_width', 0.6);
+ $config->set('first_layer_extrusion_width', '100%');
+ $config->set('bridge_speed', 99);
+ $config->set('cooling', [ 0 ]); # prevent speed alteration
+ $config->set('first_layer_speed', '100%'); # prevent speed alteration
+ $config->set('start_gcode', ''); # prevent any unexpected Z move
+ my $print = Slic3r::Test::init_print('20mm_cube', config => $config);
+
+ my $layer_id = -1; # so that first Z move sets this to 0
+ my @raft = my @first_object_layer = ();
+ my %first_object_layer_speeds = (); # F => 1
+ Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub {
+ my ($self, $cmd, $args, $info) = @_;
+
+ if ($info->{extruding} && $info->{dist_XY} > 0) {
+ if ($layer_id <= $config->raft_layers) {
+ # this is a raft layer or the first object layer
+ my $line = Slic3r::Line->new_scale([ $self->X, $self->Y ], [ $info->{new_X}, $info->{new_Y} ]);
+ my @path = @{$line->grow(scale($config->support_material_extrusion_width/2))};
+ if ($layer_id < $config->raft_layers) {
+ # this is a raft layer
+ push @raft, @path;
+ } else {
+ push @first_object_layer, @path;
+ $first_object_layer_speeds{ $args->{F} // $self->F } = 1;
+ }
+ }
+ } elsif ($cmd eq 'G1' && $info->{dist_Z} > 0) {
+ $layer_id++;
+ }
+ });
+
+ ok !@{diff(\@first_object_layer, \@raft)},
+ 'first object layer is completely supported by raft';
+ is scalar(keys %first_object_layer_speeds), 1,
+ 'only one speed used in first object layer';
+ ok +(keys %first_object_layer_speeds)[0] == $config->bridge_speed*60,
+ 'bridge speed used in first object layer';
+}
+
+{
+ my $config = Slic3r::Config::new_from_defaults;
+ $config->set('skirts', 0);
+ $config->set('layer_height', 0.35);
+ $config->set('first_layer_height', 0.3);
+ $config->set('nozzle_diameter', [0.5]);
+ $config->set('support_material_extruder', 2);
+ $config->set('support_material_interface_extruder', 2);
+
+ my $test = sub {
+ my ($raft_layers) = @_;
+ $config->set('raft_layers', $raft_layers);
+ my $print = Slic3r::Test::init_print('20mm_cube', config => $config);
+ my %raft_z = (); # z => 1
+ my $tool = undef;
+ Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub {
+ my ($self, $cmd, $args, $info) = @_;
+
+ if ($cmd =~ /^T(\d+)/) {
+ $tool = $1;
+ } elsif ($info->{extruding} && $info->{dist_XY} > 0) {
+ if ($tool == $config->support_material_extruder-1) {
+ $raft_z{$self->Z} = 1;
+ }
+ }
+ });
+
+ is scalar(keys %raft_z), $config->raft_layers, 'correct number of raft layers is generated';
+ };
+
+ $test->(2);
+ $test->(70);
+
+ $config->set('layer_height', 0.4);
+ $config->set('first_layer_height', 0.35);
+ $test->(3);
+ $test->(70);
+}
+
+{
+ my $config = Slic3r::Config::new_from_defaults;
+ $config->set('brim_width', 0);
+ $config->set('skirts', 0);
+ $config->set('support_material', 1);
+ $config->set('top_solid_layers', 0); # so that we don't have the internal bridge over infill
+ $config->set('bridge_speed', 99);
+ $config->set('cooling', [ 0 ]);
+ $config->set('first_layer_speed', '100%');
+
+ my $test = sub {
+ my $print = Slic3r::Test::init_print('overhang', config => $config);
+
+ my $has_bridge_speed = 0;
+ Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub {
+ my ($self, $cmd, $args, $info) = @_;
+
+ if ($info->{extruding}) {
+ if (($args->{F} // $self->F) == $config->bridge_speed*60) {
+ $has_bridge_speed = 1;
+ }
+ }
+ });
+ return $has_bridge_speed;
+ };
+
+ $config->set('support_material_contact_distance', 0.2);
+ ok $test->(), 'bridge speed is used when support_material_contact_distance > 0';
+
+ $config->set('support_material_contact_distance', 0);
+ ok !$test->(), 'bridge speed is not used when support_material_contact_distance == 0';
+
+ $config->set('raft_layers', 5);
+ $config->set('support_material_contact_distance', 0.2);
+ ok $test->(), 'bridge speed is used when raft_layers > 0 and support_material_contact_distance > 0';
+
+ $config->set('support_material_contact_distance', 0);
+ ok !$test->(), 'bridge speed is not used when raft_layers > 0 and support_material_contact_distance == 0';
+}
+
+{
+ my $config = Slic3r::Config::new_from_defaults;
+ $config->set('skirts', 0);
+ $config->set('start_gcode', '');
+ $config->set('raft_layers', 8);
+ $config->set('nozzle_diameter', [0.4, 1]);
+ $config->set('layer_height', 0.1);
+ $config->set('first_layer_height', 0.8);
+ $config->set('support_material_extruder', 2);
+ $config->set('support_material_interface_extruder', 2);
+ $config->set('support_material_contact_distance', 0);
+ my $print = Slic3r::Test::init_print('20mm_cube', config => $config);
+ ok my $gcode = Slic3r::Test::gcode($print), 'first_layer_height is validated with support material extruder nozzle diameter when using raft layers';
+
+ my $tool = undef;
+ my @z = (0);
+ my %layer_heights_by_tool = (); # tool => [ lh, lh... ]
+ Slic3r::GCode::Reader->new->parse($gcode, sub {
+ my ($self, $cmd, $args, $info) = @_;
+
+ if ($cmd =~ /^T(\d+)/) {
+ $tool = $1;
+ } elsif ($cmd eq 'G1' && exists $args->{Z} && $args->{Z} != $self->Z) {
+ push @z, $args->{Z};
+ } elsif ($info->{extruding} && $info->{dist_XY} > 0) {
+ $layer_heights_by_tool{$tool} ||= [];
+ push @{ $layer_heights_by_tool{$tool} }, $z[-1] - $z[-2];
+ }
+ });
+
+ ok !defined(first { $_ > $config->nozzle_diameter->[0] + epsilon }
+ @{ $layer_heights_by_tool{$config->perimeter_extruder-1} }),
+ 'no object layer is thicker than nozzle diameter';
+
+ ok !defined(first { abs($_ - $config->layer_height) < epsilon }
+ @{ $layer_heights_by_tool{$config->support_material_extruder-1} }),
+ 'no support material layer is as thin as object layers';
+}
+
+*/
diff --git a/tests/libslic3r/test_clipper_utils.cpp b/tests/libslic3r/test_clipper_utils.cpp
index b357d8ca83..048ebba107 100644
--- a/tests/libslic3r/test_clipper_utils.cpp
+++ b/tests/libslic3r/test_clipper_utils.cpp
@@ -294,13 +294,18 @@ SCENARIO("Various Clipper operations - t/clipper.t", "[ClipperUtils]") {
WHEN("clipping a line") {
auto line = Polyline::new_scale({ { 152.742,288.086671142818 }, { 152.742,34.166466971035 } });
- Polylines intersection = intersection_pl({ line }, { circle_with_hole });
+ Polylines intersection = intersection_pl(line, Polygons{ circle_with_hole });
THEN("clipped to two pieces") {
REQUIRE(intersection.front().length() == Approx((Vec2d(152742000, 215178843) - Vec2d(152742000, 288086661)).norm()));
REQUIRE(intersection[1].length() == Approx((Vec2d(152742000, 35166477) - Vec2d(152742000, 108087507)).norm()));
}
}
}
+ GIVEN("line") {
+ THEN("expand by 5") {
+ REQUIRE(offset(Polyline({10,10}, {20,10}), 5).front().area() == Polygon({ {10,5}, {20,5}, {20,15}, {10,15} }).area());
+ }
+ }
}
template
diff --git a/xs/CMakeLists.txt b/xs/CMakeLists.txt
index 022ba2c013..1a58aab122 100644
--- a/xs/CMakeLists.txt
+++ b/xs/CMakeLists.txt
@@ -44,27 +44,19 @@ set(XSP_DIR ${CMAKE_CURRENT_SOURCE_DIR}/xsp)
#FIXME list the dependecies explicitely, add dependency on the typemap.
set(XS_XSP_FILES
${XSP_DIR}/BoundingBox.xsp
- ${XSP_DIR}/BridgeDetector.xsp
- ${XSP_DIR}/Clipper.xsp
${XSP_DIR}/Config.xsp
${XSP_DIR}/ExPolygon.xsp
- ${XSP_DIR}/ExPolygonCollection.xsp
${XSP_DIR}/ExtrusionEntityCollection.xsp
${XSP_DIR}/ExtrusionLoop.xsp
- ${XSP_DIR}/ExtrusionMultiPath.xsp
${XSP_DIR}/ExtrusionPath.xsp
- ${XSP_DIR}/Flow.xsp
${XSP_DIR}/GCode.xsp
${XSP_DIR}/Geometry.xsp
${XSP_DIR}/Layer.xsp
${XSP_DIR}/Line.xsp
${XSP_DIR}/Model.xsp
- ${XSP_DIR}/PerimeterGenerator.xsp
- ${XSP_DIR}/PlaceholderParser.xsp
${XSP_DIR}/Point.xsp
${XSP_DIR}/Polygon.xsp
${XSP_DIR}/Polyline.xsp
- ${XSP_DIR}/PolylineCollection.xsp
${XSP_DIR}/Print.xsp
${XSP_DIR}/Surface.xsp
${XSP_DIR}/SurfaceCollection.xsp
diff --git a/xs/lib/Slic3r/XS.pm b/xs/lib/Slic3r/XS.pm
index 83bc0ee70e..1675ac1935 100644
--- a/xs/lib/Slic3r/XS.pm
+++ b/xs/lib/Slic3r/XS.pm
@@ -4,21 +4,6 @@ use strict;
our $VERSION = '0.01';
-# We have to load these modules in order to have Wx.pm find the correct paths
-# for wxWidgets dlls on MSW.
-# We avoid loading these on OS X because Wx::Load() initializes a Wx App
-# automatically and it steals focus even when we're not running Slic3r in GUI mode.
-# TODO: only load these when compiling with GUI support
-BEGIN {
- if ($^O eq 'MSWin32') {
- eval "use Wx";
- eval "use Wx::GLCanvas";
- eval "use Wx::GLContext";
- eval "use Wx::Html";
- eval "use Wx::Print"; # because of some Wx bug, thread creation fails if we don't have this (looks like Wx::Printout is hard-coded in some thread cleanup code)
- }
-}
-
use Carp qw();
use XSLoader;
XSLoader::load(__PACKAGE__, $VERSION);
@@ -58,21 +43,11 @@ use overload
'@{}' => sub { $_[0]->arrayref },
'fallback' => 1;
-package Slic3r::Polyline::Collection;
-use overload
- '@{}' => sub { $_[0]->arrayref },
- 'fallback' => 1;
-
package Slic3r::Polygon;
use overload
'@{}' => sub { $_[0]->arrayref },
'fallback' => 1;
-package Slic3r::ExPolygon::Collection;
-use overload
- '@{}' => sub { $_[0]->arrayref },
- 'fallback' => 1;
-
package Slic3r::ExtrusionPath::Collection;
use overload
'@{}' => sub { $_[0]->arrayref },
@@ -99,11 +74,6 @@ sub new_from_paths {
return $loop;
}
-package Slic3r::ExtrusionMultiPath;
-use overload
- '@{}' => sub { $_[0]->arrayref },
- 'fallback' => 1;
-
package Slic3r::ExtrusionPath;
use overload
'@{}' => sub { $_[0]->arrayref },
@@ -133,25 +103,6 @@ sub clone {
);
}
-package Slic3r::Flow;
-
-sub new {
- my ($class, %args) = @_;
-
- my $self = $class->_new(
- @args{qw(width height nozzle_diameter)},
- );
- return $self;
-}
-
-sub new_from_width {
- my ($class, %args) = @_;
-
- return $class->_new_from_width(
- @args{qw(role width nozzle_diameter layer_height)},
- );
-}
-
package Slic3r::Surface;
sub new {
@@ -197,58 +148,21 @@ sub new {
return $self;
}
-package Slic3r::Print::SupportMaterial2;
-
-sub new {
- my ($class, %args) = @_;
-
- return $class->_new(
- $args{print_config}, # required
- $args{object_config}, # required
- $args{first_layer_flow}, # required
- $args{flow}, # required
- $args{interface_flow}, # required
- $args{soluble_interface} // 0
- );
-}
-
-package Slic3r::GUI::_3DScene::GLVolume::Collection;
-use overload
- '@{}' => sub { $_[0]->arrayref },
- 'fallback' => 1;
-
-package Slic3r::GUI::PresetCollection;
-use overload
- '@{}' => sub { $_[0]->arrayref },
- 'fallback' => 1;
-
package main;
for my $class (qw(
- Slic3r::BridgeDetector
Slic3r::Config
- Slic3r::Config::Full
Slic3r::Config::GCode
Slic3r::Config::Print
- Slic3r::Config::PrintObject
- Slic3r::Config::PrintRegion
Slic3r::Config::Static
Slic3r::ExPolygon
- Slic3r::ExPolygon::Collection
Slic3r::ExtrusionLoop
- Slic3r::ExtrusionMultiPath
Slic3r::ExtrusionPath
Slic3r::ExtrusionPath::Collection
- Slic3r::Flow
Slic3r::GCode
- Slic3r::GCode::PlaceholderParser
Slic3r::Geometry::BoundingBox
- Slic3r::Geometry::BoundingBoxf
- Slic3r::Geometry::BoundingBoxf3
Slic3r::Layer
Slic3r::Layer::Region
- Slic3r::Layer::Support
Slic3r::Line
- Slic3r::Linef3
Slic3r::Model
Slic3r::Model::Instance
Slic3r::Model::Material
@@ -264,10 +178,8 @@ for my $class (qw(
Slic3r::Print
Slic3r::Print::Object
Slic3r::Print::Region
- Slic3r::Print::State
Slic3r::Surface
Slic3r::Surface::Collection
- Slic3r::Print::SupportMaterial2
Slic3r::TriangleMesh
))
{
diff --git a/xs/src/perlglue.cpp b/xs/src/perlglue.cpp
index 2d996120dd..4e293a2f9f 100644
--- a/xs/src/perlglue.cpp
+++ b/xs/src/perlglue.cpp
@@ -4,24 +4,16 @@
namespace Slic3r {
REGISTER_CLASS(ExPolygon, "ExPolygon");
-REGISTER_CLASS(ExPolygonCollection, "ExPolygon::Collection");
-REGISTER_CLASS(ExtrusionMultiPath, "ExtrusionMultiPath");
REGISTER_CLASS(ExtrusionPath, "ExtrusionPath");
REGISTER_CLASS(ExtrusionLoop, "ExtrusionLoop");
REGISTER_CLASS(ExtrusionEntityCollection, "ExtrusionPath::Collection");
-REGISTER_CLASS(Flow, "Flow");
REGISTER_CLASS(CoolingBuffer, "GCode::CoolingBuffer");
REGISTER_CLASS(GCode, "GCode");
REGISTER_CLASS(Layer, "Layer");
-REGISTER_CLASS(SupportLayer, "Layer::Support");
REGISTER_CLASS(LayerRegion, "Layer::Region");
REGISTER_CLASS(Line, "Line");
-REGISTER_CLASS(Linef3, "Linef3");
-REGISTER_CLASS(PerimeterGenerator, "Layer::PerimeterGenerator");
-REGISTER_CLASS(PlaceholderParser, "GCode::PlaceholderParser");
REGISTER_CLASS(Polygon, "Polygon");
REGISTER_CLASS(Polyline, "Polyline");
-REGISTER_CLASS(PolylineCollection, "Polyline::Collection");
REGISTER_CLASS(Print, "Print");
REGISTER_CLASS(PrintObject, "Print::Object");
REGISTER_CLASS(PrintRegion, "Print::Region");
@@ -31,22 +23,16 @@ REGISTER_CLASS(ModelObject, "Model::Object");
REGISTER_CLASS(ModelVolume, "Model::Volume");
REGISTER_CLASS(ModelInstance, "Model::Instance");
REGISTER_CLASS(BoundingBox, "Geometry::BoundingBox");
-REGISTER_CLASS(BoundingBoxf, "Geometry::BoundingBoxf");
-REGISTER_CLASS(BoundingBoxf3, "Geometry::BoundingBoxf3");
-REGISTER_CLASS(BridgeDetector, "BridgeDetector");
REGISTER_CLASS(Point, "Point");
__REGISTER_CLASS(Vec2d, "Pointf");
__REGISTER_CLASS(Vec3d, "Pointf3");
REGISTER_CLASS(DynamicPrintConfig, "Config");
REGISTER_CLASS(StaticPrintConfig, "Config::Static");
-REGISTER_CLASS(PrintObjectConfig, "Config::PrintObject");
-REGISTER_CLASS(PrintRegionConfig, "Config::PrintRegion");
REGISTER_CLASS(GCodeConfig, "Config::GCode");
REGISTER_CLASS(PrintConfig, "Config::Print");
-REGISTER_CLASS(FullPrintConfig, "Config::Full");
REGISTER_CLASS(Surface, "Surface");
REGISTER_CLASS(SurfaceCollection, "Surface::Collection");
-REGISTER_CLASS(PrintObjectSupportMaterial, "Print::SupportMaterial2");
+REGISTER_CLASS(FullPrintConfig, "Config::Full");
REGISTER_CLASS(TriangleMesh, "TriangleMesh");
SV* ConfigBase__as_hash(ConfigBase* THIS)
diff --git a/xs/t/01_trianglemesh.t b/xs/t/01_trianglemesh.t
index 453cc92189..a071a75a28 100644
--- a/xs/t/01_trianglemesh.t
+++ b/xs/t/01_trianglemesh.t
@@ -4,7 +4,7 @@ use strict;
use warnings;
use Slic3r::XS;
-use Test::More tests => 5;
+use Test::More tests => 4;
my $cube = {
vertices => [ [20,20,0], [20,0,0], [0,0,0], [0,20,0], [20,20,20], [0,20,20], [0,0,20], [20,0,20] ],
@@ -25,11 +25,6 @@ my $cube = {
is_deeply $m2->facets, $cube->{facets}, 'cloned facets arrayref roundtrip';
$m2->scale(3); # check that it does not affect $m
}
-
- {
- my $stats = $m->stats;
- is $stats->{number_of_facets}, scalar(@{ $cube->{facets} }), 'stats.number_of_facets';
- }
}
__END__
diff --git a/xs/t/04_expolygon.t b/xs/t/04_expolygon.t
index 65e274ab9a..48eaed551a 100644
--- a/xs/t/04_expolygon.t
+++ b/xs/t/04_expolygon.t
@@ -5,7 +5,7 @@ use warnings;
use List::Util qw(first sum);
use Slic3r::XS;
-use Test::More tests => 21;
+use Test::More tests => 15;
use constant PI => 4 * atan2(1, 1);
@@ -81,28 +81,4 @@ is $expolygon->area, 100*100-20*20, 'area';
], 'rotate around pure-Perl Point';
}
-{
- my $expolygon2 = $expolygon->clone;
- $expolygon2->scale(2);
- my $collection = Slic3r::ExPolygon::Collection->new($expolygon->pp, $expolygon2->pp);
- is_deeply $collection->pp, [ $expolygon->pp, $expolygon2->pp ],
- 'expolygon collection (pure Perl) roundtrip';
-
- my $collection2 = Slic3r::ExPolygon::Collection->new($expolygon, $expolygon2);
- is_deeply $collection->pp, $collection2->pp,
- 'expolygon collection (XS) roundtrip';
-
- $collection->clear;
- is scalar(@$collection), 0, 'clear collection';
-
- $collection->append($expolygon);
- is scalar(@$collection), 1, 'append to collection';
-
- my $exp = $collection->[0];
- $exp->scale(3);
- is $collection->[0][0][0][0], $exp->[0][0][0], 'collection items are returned by reference';
-
- is_deeply $collection->[0]->clone->pp, $collection->[0]->pp, 'clone collection item';
-}
-
__END__
diff --git a/xs/t/13_polylinecollection.t b/xs/t/13_polylinecollection.t
deleted file mode 100644
index 9b36e7ffa7..0000000000
--- a/xs/t/13_polylinecollection.t
+++ /dev/null
@@ -1,35 +0,0 @@
-#!/usr/bin/perl
-
-use strict;
-use warnings;
-
-use Slic3r::XS;
-use Test::More tests => 3;
-
-{
- my $collection = Slic3r::Polyline::Collection->new(
- Slic3r::Polyline->new([0,15], [0,18], [0,20]),
- Slic3r::Polyline->new([0,10], [0,8], [0,5]),
- );
- is_deeply
- [ map $_->y, map @$_, @{$collection->chained_path_from(Slic3r::Point->new(0,30), 0)} ],
- [20, 18, 15, 10, 8, 5],
- 'chained_path_from';
- is_deeply
- [ map $_->y, map @$_, @{$collection->chained_path(0)} ],
- [15, 18, 20, 10, 8, 5],
- 'chained_path';
-}
-
-{
- my $collection = Slic3r::Polyline::Collection->new(
- Slic3r::Polyline->new([15,0], [10,0], [4,0]),
- Slic3r::Polyline->new([10,5], [15,5], [20,5]),
- );
- is_deeply
- [ map $_->x, map @$_, @{$collection->chained_path_from(Slic3r::Point->new(30,0), 0)} ],
- [reverse 4, 10, 15, 10, 15, 20],
- 'chained_path_from';
-}
-
-__END__
diff --git a/xs/xsp/BoundingBox.xsp b/xs/xsp/BoundingBox.xsp
index a34cad0bc8..75592e7c38 100644
--- a/xs/xsp/BoundingBox.xsp
+++ b/xs/xsp/BoundingBox.xsp
@@ -50,69 +50,3 @@ new_from_points(CLASS, points)
%}
};
-%name{Slic3r::Geometry::BoundingBoxf} class BoundingBoxf {
- BoundingBoxf();
- ~BoundingBoxf();
- Clone clone()
- %code{% RETVAL = THIS; %};
- void merge(BoundingBoxf* bb) %code{% THIS->merge(*bb); %};
- void merge_point(Vec2d* point) %code{% THIS->merge(*point); %};
- void scale(double factor);
- void translate(double x, double y);
- Clone size();
- Clone center();
- double radius();
- bool empty() %code{% RETVAL = empty(*THIS); %};
- Clone min_point() %code{% RETVAL = THIS->min; %};
- Clone max_point() %code{% RETVAL = THIS->max; %};
- double x_min() %code{% RETVAL = THIS->min(0); %};
- double x_max() %code{% RETVAL = THIS->max(0); %};
- double y_min() %code{% RETVAL = THIS->min(1); %};
- double y_max() %code{% RETVAL = THIS->max(1); %};
- void set_x_min(double val) %code{% THIS->min(0) = val; %};
- void set_x_max(double val) %code{% THIS->max(0) = val; %};
- void set_y_min(double val) %code{% THIS->min(1) = val; %};
- void set_y_max(double val) %code{% THIS->max(1) = val; %};
- std::string serialize() %code{% char buf[2048]; sprintf(buf, "%lf,%lf;%lf,%lf", THIS->min(0), THIS->min(1), THIS->max(0), THIS->max(1)); RETVAL = buf; %};
- bool defined() %code{% RETVAL = THIS->defined; %};
-
-%{
-
-BoundingBoxf*
-new_from_points(CLASS, points)
- char* CLASS
- Pointfs points
- CODE:
- RETVAL = new BoundingBoxf(points);
- OUTPUT:
- RETVAL
-
-%}
-};
-
-%name{Slic3r::Geometry::BoundingBoxf3} class BoundingBoxf3 {
- BoundingBoxf3();
- ~BoundingBoxf3();
- Clone clone()
- %code{% RETVAL = THIS; %};
- void merge(BoundingBoxf3* bb) %code{% THIS->merge(*bb); %};
- void merge_point(Vec3d* point) %code{% THIS->merge(*point); %};
- void scale(double factor);
- void translate(double x, double y, double z);
- void offset(double delta);
- bool contains_point(Vec3d* point) %code{% RETVAL = THIS->contains(*point); %};
- Clone size();
- Clone center();
- double radius();
- bool empty() %code{% RETVAL = empty(*THIS); %};
- Clone min_point() %code{% RETVAL = THIS->min; %};
- Clone max_point() %code{% RETVAL = THIS->max; %};
- double x_min() %code{% RETVAL = THIS->min(0); %};
- double x_max() %code{% RETVAL = THIS->max(0); %};
- double y_min() %code{% RETVAL = THIS->min(1); %};
- double y_max() %code{% RETVAL = THIS->max(1); %};
- double z_min() %code{% RETVAL = THIS->min(2); %};
- double z_max() %code{% RETVAL = THIS->max(2); %};
- std::string serialize() %code{% char buf[2048]; sprintf(buf, "%lf,%lf,%lf;%lf,%lf,%lf", THIS->min(0), THIS->min(1), THIS->min(2), THIS->max(0), THIS->max(1), THIS->max(2)); RETVAL = buf; %};
- bool defined() %code{% RETVAL = THIS->defined; %};
-};
diff --git a/xs/xsp/BridgeDetector.xsp b/xs/xsp/BridgeDetector.xsp
deleted file mode 100644
index eb3793cf7c..0000000000
--- a/xs/xsp/BridgeDetector.xsp
+++ /dev/null
@@ -1,43 +0,0 @@
-%module{Slic3r::XS};
-
-%{
-#include
-#include "libslic3r/BridgeDetector.hpp"
-%}
-
-%name{Slic3r::BridgeDetector} class BridgeDetector {
- ~BridgeDetector();
-
- bool detect_angle();
- Polygons coverage();
- %name{coverage_by_angle} Polygons coverage(double angle);
- Polylines unsupported_edges();
- %name{unsupported_edges_by_angle} Polylines unsupported_edges(double angle);
- double angle()
- %code{% RETVAL = THIS->angle; %};
- double resolution()
- %code{% RETVAL = THIS->resolution; %};
-%{
-
-BridgeDetector*
-BridgeDetector::new(expolygon, lower_slices, extrusion_width)
- ExPolygon* expolygon;
- ExPolygonCollection* lower_slices;
- int extrusion_width;
- CODE:
- RETVAL = new BridgeDetector(*expolygon, lower_slices->expolygons, extrusion_width);
- OUTPUT:
- RETVAL
-
-BridgeDetector*
-BridgeDetector::new_expolygons(expolygons, lower_slices, extrusion_width)
- ExPolygonCollection* expolygons;
- ExPolygonCollection* lower_slices;
- int extrusion_width;
- CODE:
- RETVAL = new BridgeDetector(expolygons->expolygons, lower_slices->expolygons, extrusion_width);
- OUTPUT:
- RETVAL
-
-%}
-};
diff --git a/xs/xsp/Clipper.xsp b/xs/xsp/Clipper.xsp
deleted file mode 100644
index 5f9f359067..0000000000
--- a/xs/xsp/Clipper.xsp
+++ /dev/null
@@ -1,73 +0,0 @@
-%module{Slic3r::XS};
-
-%{
-#include
-#include "libslic3r/ClipperUtils.hpp"
-%}
-
-%package{Slic3r::Geometry::Clipper};
-
-%{
-
-Polygons
-offset(polygons, delta, joinType = Slic3r::ClipperLib::jtMiter, miterLimit = 3)
- Polygons polygons
- const float delta
- Slic3r::ClipperLib::JoinType joinType
- double miterLimit
- CODE:
- RETVAL = offset(polygons, delta, joinType, miterLimit);
- OUTPUT:
- RETVAL
-
-ExPolygons
-offset2_ex(polygons, delta1, delta2, joinType = Slic3r::ClipperLib::jtMiter, miterLimit = 3)
- Polygons polygons
- const float delta1
- const float delta2
- Slic3r::ClipperLib::JoinType joinType
- double miterLimit
- CODE:
- RETVAL = offset2_ex(union_ex(polygons), delta1, delta2, joinType, miterLimit);
- OUTPUT:
- RETVAL
-
-Polygons
-diff(subject, clip, safety_offset = false)
- Polygons subject
- Polygons clip
- bool safety_offset
- CODE:
- RETVAL = diff(subject, clip, safety_offset ? ApplySafetyOffset::Yes : ApplySafetyOffset::No);
- OUTPUT:
- RETVAL
-
-ExPolygons
-diff_ex(subject, clip, safety_offset = false)
- Polygons subject
- Polygons clip
- bool safety_offset
- CODE:
- RETVAL = diff_ex(subject, clip, safety_offset ? ApplySafetyOffset::Yes : ApplySafetyOffset::No);
- OUTPUT:
- RETVAL
-
-Polygons
-union(subject, safety_offset = false)
- Polygons subject
- bool safety_offset
- CODE:
- RETVAL = safety_offset ? union_safety_offset(subject) : union_(subject);
- OUTPUT:
- RETVAL
-
-ExPolygons
-union_ex(subject, safety_offset = false)
- Polygons subject
- bool safety_offset
- CODE:
- RETVAL = safety_offset ? union_safety_offset_ex(subject) : union_ex(subject);
- OUTPUT:
- RETVAL
-
-%}
diff --git a/xs/xsp/Config.xsp b/xs/xsp/Config.xsp
index 7034270351..14f235d93d 100644
--- a/xs/xsp/Config.xsp
+++ b/xs/xsp/Config.xsp
@@ -76,10 +76,6 @@
%code{% RETVAL = new GCodeConfig(); %};
static StaticPrintConfig* new_PrintConfig()
%code{% RETVAL = static_cast(new PrintConfig()); %};
- static StaticPrintConfig* new_PrintObjectConfig()
- %code{% RETVAL = new PrintObjectConfig(); %};
- static StaticPrintConfig* new_PrintRegionConfig()
- %code{% RETVAL = new PrintRegionConfig(); %};
static StaticPrintConfig* new_FullPrintConfig()
%code{% RETVAL = static_cast(new FullPrintConfig()); %};
~StaticPrintConfig();
diff --git a/xs/xsp/ExPolygonCollection.xsp b/xs/xsp/ExPolygonCollection.xsp
deleted file mode 100644
index 5321afb155..0000000000
--- a/xs/xsp/ExPolygonCollection.xsp
+++ /dev/null
@@ -1,81 +0,0 @@
-%module{Slic3r::XS};
-
-%{
-#include
-#include "libslic3r/ExPolygonCollection.hpp"
-%}
-
-%name{Slic3r::ExPolygon::Collection} class ExPolygonCollection {
- ~ExPolygonCollection();
- Clone clone()
- %code{% RETVAL = THIS; %};
- void clear()
- %code{% THIS->expolygons.clear(); %};
- void scale(double factor);
- void translate(double x, double y);
- void rotate(double angle, Point* center)
- %code{% THIS->rotate(angle, *center); %};
- int count()
- %code{% RETVAL = THIS->expolygons.size(); %};
- bool contains_point(Point* point)
- %code{% RETVAL = THIS->contains(*point); %};
- bool contains_line(Line* line)
- %code{% RETVAL = THIS->contains(*line); %};
- bool contains_polyline(Polyline* polyline)
- %code{% RETVAL = THIS->contains(*polyline); %};
- void simplify(double tolerance);
- Polygons polygons()
- %code{% RETVAL = (Polygons)*THIS; %};
- Clone convex_hull();
-%{
-
-ExPolygonCollection*
-ExPolygonCollection::new(...)
- CODE:
- RETVAL = new ExPolygonCollection ();
- // ST(0) is class name, others are expolygons
- RETVAL->expolygons.resize(items-1);
- for (unsigned int i = 1; i < items; i++) {
- // Note: a COPY of the input is stored
- from_SV_check(ST(i), &RETVAL->expolygons[i-1]);
- }
- OUTPUT:
- RETVAL
-
-SV*
-ExPolygonCollection::arrayref()
- CODE:
- AV* av = newAV();
- av_fill(av, THIS->expolygons.size()-1);
- int i = 0;
- for (ExPolygons::iterator it = THIS->expolygons.begin(); it != THIS->expolygons.end(); ++it) {
- av_store(av, i++, perl_to_SV_ref(*it));
- }
- RETVAL = newRV_noinc((SV*)av);
- OUTPUT:
- RETVAL
-
-SV*
-ExPolygonCollection::pp()
- CODE:
- AV* av = newAV();
- av_fill(av, THIS->expolygons.size()-1);
- int i = 0;
- for (ExPolygons::iterator it = THIS->expolygons.begin(); it != THIS->expolygons.end(); ++it) {
- av_store(av, i++, to_SV_pureperl(&*it));
- }
- RETVAL = newRV_noinc((SV*)av);
- OUTPUT:
- RETVAL
-
-void
-ExPolygonCollection::append(...)
- CODE:
- for (unsigned int i = 1; i < items; i++) {
- ExPolygon expolygon;
- from_SV_check(ST(i), &expolygon);
- THIS->expolygons.push_back(expolygon);
- }
-
-%}
-};
diff --git a/xs/xsp/ExtrusionEntityCollection.xsp b/xs/xsp/ExtrusionEntityCollection.xsp
index a01788c56c..1c33373037 100644
--- a/xs/xsp/ExtrusionEntityCollection.xsp
+++ b/xs/xsp/ExtrusionEntityCollection.xsp
@@ -55,8 +55,6 @@ ExtrusionEntityCollection::arrayref()
// return our item by reference
if (ExtrusionPath* path = dynamic_cast(*it)) {
sv_setref_pv( sv, perl_class_name_ref(path), path );
- } else if (ExtrusionMultiPath* multipath = dynamic_cast(*it)) {
- sv_setref_pv( sv, perl_class_name_ref(multipath), multipath );
} else if (ExtrusionLoop* loop = dynamic_cast(*it)) {
sv_setref_pv( sv, perl_class_name_ref(loop), loop );
} else if (ExtrusionEntityCollection* collection = dynamic_cast(*it)) {
@@ -81,8 +79,6 @@ ExtrusionEntityCollection::append(...)
// append COPIES
if (ExtrusionPath* path = dynamic_cast(entity)) {
THIS->entities.push_back( new ExtrusionPath(*path) );
- } else if (ExtrusionMultiPath* multipath = dynamic_cast(entity)) {
- THIS->entities.push_back( new ExtrusionMultiPath(*multipath) );
} else if (ExtrusionLoop* loop = dynamic_cast(entity)) {
THIS->entities.push_back( new ExtrusionLoop(*loop) );
} else if(ExtrusionEntityCollection* collection = dynamic_cast(entity)) {
diff --git a/xs/xsp/ExtrusionMultiPath.xsp b/xs/xsp/ExtrusionMultiPath.xsp
deleted file mode 100644
index 5dd9382450..0000000000
--- a/xs/xsp/ExtrusionMultiPath.xsp
+++ /dev/null
@@ -1,38 +0,0 @@
-%module{Slic3r::XS};
-
-%{
-#include
-#include "libslic3r/ExtrusionEntity.hpp"
-%}
-
-%name{Slic3r::ExtrusionMultiPath} class ExtrusionMultiPath {
- ExtrusionMultiPath();
- ~ExtrusionMultiPath();
- Clone clone()
- %code{% RETVAL = THIS; %};
- void reverse();
- Clone first_point();
- Clone last_point();
- void append(ExtrusionPath* path)
- %code{% THIS->paths.push_back(*path); %};
- double length();
- Polygons polygons_covered_by_width();
- Polygons polygons_covered_by_spacing();
- Clone polyline()
- %code{% RETVAL = THIS->as_polyline(); %};
-%{
-
-SV*
-ExtrusionMultiPath::arrayref()
- CODE:
- AV* av = newAV();
- av_fill(av, THIS->paths.size()-1);
- for (ExtrusionPaths::iterator it = THIS->paths.begin(); it != THIS->paths.end(); ++it) {
- av_store(av, it - THIS->paths.begin(), perl_to_SV_ref(*it));
- }
- RETVAL = newRV_noinc((SV*)av);
- OUTPUT:
- RETVAL
-
-%}
-};
diff --git a/xs/xsp/ExtrusionPath.xsp b/xs/xsp/ExtrusionPath.xsp
index 078e6fe721..1dbc009174 100644
--- a/xs/xsp/ExtrusionPath.xsp
+++ b/xs/xsp/ExtrusionPath.xsp
@@ -95,22 +95,6 @@ ExtrusionPath::append(...)
THIS->polyline.points.push_back(p);
}
-ExtrusionEntityCollection*
-ExtrusionPath::intersect_expolygons(ExPolygonCollection* collection)
- CODE:
- RETVAL = new ExtrusionEntityCollection ();
- THIS->intersect_expolygons(*collection, RETVAL);
- OUTPUT:
- RETVAL
-
-ExtrusionEntityCollection*
-ExtrusionPath::subtract_expolygons(ExPolygonCollection* collection)
- CODE:
- RETVAL = new ExtrusionEntityCollection ();
- THIS->subtract_expolygons(*collection, RETVAL);
- OUTPUT:
- RETVAL
-
%}
};
diff --git a/xs/xsp/Flow.xsp b/xs/xsp/Flow.xsp
deleted file mode 100644
index 3056b40015..0000000000
--- a/xs/xsp/Flow.xsp
+++ /dev/null
@@ -1,60 +0,0 @@
-%module{Slic3r::XS};
-
-%{
-#include
-#include "libslic3r/Flow.hpp"
-%}
-
-%name{Slic3r::Flow} class Flow {
- ~Flow();
- %name{_new} Flow(float width, float height, float nozzle_diameter);
- Clone clone()
- %code{% RETVAL = THIS; %};
-
- float width();
- float height();
- float nozzle_diameter();
- bool bridge();
- float spacing();
- int scaled_width();
- int scaled_spacing();
- double mm3_per_mm();
-%{
-
-Flow*
-_new_from_width(CLASS, role, width, nozzle_diameter, height)
- char* CLASS;
- FlowRole role;
- std::string width;
- float nozzle_diameter;
- float height;
- CODE:
- ConfigOptionFloatOrPercent optwidth;
- optwidth.deserialize(width, ForwardCompatibilitySubstitutionRule::Disable);
- RETVAL = new Flow(Flow::new_from_config_width(role, optwidth, nozzle_diameter, height));
- OUTPUT:
- RETVAL
-
-%}
-};
-
-%package{Slic3r::Flow};
-%{
-
-IV
-_constant()
- ALIAS:
- FLOW_ROLE_EXTERNAL_PERIMETER = frExternalPerimeter
- FLOW_ROLE_PERIMETER = frPerimeter
- FLOW_ROLE_INFILL = frInfill
- FLOW_ROLE_SOLID_INFILL = frSolidInfill
- FLOW_ROLE_TOP_SOLID_INFILL = frTopSolidInfill
- FLOW_ROLE_SUPPORT_MATERIAL = frSupportMaterial
- FLOW_ROLE_SUPPORT_MATERIAL_INTERFACE = frSupportMaterialInterface
- PROTOTYPE:
- CODE:
- RETVAL = ix;
- OUTPUT: RETVAL
-
-%}
-
diff --git a/xs/xsp/Geometry.xsp b/xs/xsp/Geometry.xsp
index e59e8793b2..f6365a20a5 100644
--- a/xs/xsp/Geometry.xsp
+++ b/xs/xsp/Geometry.xsp
@@ -10,35 +10,8 @@
%package{Slic3r::Geometry};
-Pointfs arrange(size_t total_parts, Vec2d* part, coordf_t dist, BoundingBoxf* bb = NULL)
- %code{%
- Pointfs points;
- if (! Slic3r::Geometry::arrange(total_parts, *part, dist, bb, points))
- CONFESS("%zu parts won't fit in your print area!\n", total_parts);
- RETVAL = points;
- %};
-
%{
-bool
-directions_parallel(angle1, angle2)
- double angle1
- double angle2
- CODE:
- RETVAL = Slic3r::Geometry::directions_parallel(angle1, angle2);
- OUTPUT:
- RETVAL
-
-bool
-directions_parallel_within(angle1, angle2, max_diff)
- double angle1
- double angle2
- double max_diff
- CODE:
- RETVAL = Slic3r::Geometry::directions_parallel(angle1, angle2, max_diff);
- OUTPUT:
- RETVAL
-
Clone
convex_hull(points)
Points points
@@ -47,14 +20,6 @@ convex_hull(points)
OUTPUT:
RETVAL
-std::vector
-chained_path(points)
- Points points
- CODE:
- RETVAL = chain_points(points);
- OUTPUT:
- RETVAL
-
std::vector
chained_path_from(points, start_from)
Points points
@@ -72,14 +37,6 @@ rad2deg(angle)
OUTPUT:
RETVAL
-double
-rad2deg_dir(angle)
- double angle
- CODE:
- RETVAL = Slic3r::Geometry::rad2deg_dir(angle);
- OUTPUT:
- RETVAL
-
double
deg2rad(angle)
double angle
@@ -88,16 +45,6 @@ deg2rad(angle)
OUTPUT:
RETVAL
-Polygons
-simplify_polygons(polygons, tolerance)
- Polygons polygons
- double tolerance
- CODE:
- Slic3r::Geometry::simplify_polygons(polygons, tolerance, &RETVAL);
- OUTPUT:
- RETVAL
-
-
IV
_constant()
ALIAS:
diff --git a/xs/xsp/Layer.xsp b/xs/xsp/Layer.xsp
index b97e340bdb..e42486985d 100644
--- a/xs/xsp/Layer.xsp
+++ b/xs/xsp/Layer.xsp
@@ -3,7 +3,6 @@
%{
#include
#include "libslic3r/Layer.hpp"
-#include "libslic3r/ExPolygonCollection.hpp"
%}
%name{Slic3r::Layer::Region} class LayerRegion {
@@ -24,8 +23,6 @@
Ref fills()
%code%{ RETVAL = &THIS->fills; %};
- Clone flow(FlowRole role)
- %code%{ RETVAL = THIS->flow(role); %};
void prepare_fill_surfaces();
void make_perimeters(SurfaceCollection* slices, SurfaceCollection* fill_surfaces)
%code%{ THIS->make_perimeters(*slices, fill_surfaces); %};
@@ -59,15 +56,9 @@
Ref get_region(int idx);
Ref add_region(PrintRegion* print_region);
- ExPolygonCollection* slices()
- %code%{ RETVAL = new ExPolygonCollection(THIS->lslices); %};
-
int ptr()
%code%{ RETVAL = (int)(intptr_t)THIS; %};
- Ref as_support_layer()
- %code%{ RETVAL = dynamic_cast(THIS); %};
-
void make_slices();
void backup_untyped_slices();
void restore_untyped_slices();
@@ -79,41 +70,3 @@
void export_region_slices_to_svg_debug(const char *name);
void export_region_fill_surfaces_to_svg_debug(const char *name);
};
-
-%name{Slic3r::Layer::Support} class SupportLayer {
- // owned by PrintObject, no constructor/destructor
-
- Ref as_layer()
- %code%{ RETVAL = THIS; %};
-
- Ref support_islands()
- %code%{ RETVAL = &THIS->support_islands; %};
- Ref support_fills()
- %code%{ RETVAL = &THIS->support_fills; %};
-
- // copies of some Layer methods, because the parameter wrapper code
- // gets confused about getting a Layer::Support instead of a Layer
- int id();
- void set_id(int id);
- Ref object();
- bool slicing_errors()
- %code%{ RETVAL = THIS->slicing_errors; %};
- coordf_t slice_z()
- %code%{ RETVAL = THIS->slice_z; %};
- coordf_t print_z()
- %code%{ RETVAL = THIS->print_z; %};
- coordf_t height()
- %code%{ RETVAL = THIS->height; %};
-
- size_t region_count();
- Ref get_region(int idx);
- Ref add_region(PrintRegion* print_region);
-
- ExPolygonCollection* slices()
- %code%{ RETVAL = new ExPolygonCollection(THIS->lslices); %};
-
- void export_region_slices_to_svg(const char *path);
- void export_region_fill_surfaces_to_svg(const char *path);
- void export_region_slices_to_svg_debug(const char *name);
- void export_region_fill_surfaces_to_svg_debug(const char *name);
-};
diff --git a/xs/xsp/Line.xsp b/xs/xsp/Line.xsp
index 36181c3bab..67308721a3 100644
--- a/xs/xsp/Line.xsp
+++ b/xs/xsp/Line.xsp
@@ -76,17 +76,3 @@ Line::coincides_with(line_sv)
%}
};
-
-%name{Slic3r::Linef3} class Linef3 {
- Linef3(Vec3d* a, Vec3d* b)
- %code{% RETVAL = new Linef3(*a, *b); %};
- ~Linef3();
- Clone clone()
- %code{% RETVAL = THIS; %};
- Ref a()
- %code{% RETVAL = &THIS->a; %};
- Ref b()
- %code{% RETVAL = &THIS->b; %};
- Clone intersect_plane(double z);
- void scale(double factor);
-};
diff --git a/xs/xsp/Model.xsp b/xs/xsp/Model.xsp
index 34795681ef..2194089a54 100644
--- a/xs/xsp/Model.xsp
+++ b/xs/xsp/Model.xsp
@@ -71,7 +71,6 @@
%code%{ RETVAL = THIS->materials.size(); %};
bool add_default_instances();
- Clone bounding_box();
void center_instances_around_point(Vec2d* point)
%code%{ THIS->center_instances_around_point(*point); %};
void translate(double x, double y, double z);
@@ -80,11 +79,8 @@
ModelObjectPtrs* objects()
%code%{ RETVAL = &THIS->objects; %};
- bool arrange_objects(double dist, BoundingBoxf* bb = NULL) %code%{ ArrangeParams ap{scaled(dist)}; if (bb) arrange_objects(*THIS, scaled(*bb), ap); else arrange_objects(*THIS, InfiniteBed{}, ap); %};
- void duplicate(unsigned int copies_num, double dist, BoundingBoxf* bb = NULL) %code%{ ArrangeParams ap{scaled(dist)}; if (bb) duplicate(*THIS, copies_num, scaled(*bb), ap); else duplicate(*THIS, copies_num, InfiniteBed{}, ap); %};
- void duplicate_objects(unsigned int copies_num, double dist, BoundingBoxf* bb = NULL) %code%{ ArrangeParams ap{scaled(dist)}; if (bb) duplicate_objects(*THIS, copies_num, scaled(*bb), ap); else duplicate_objects(*THIS, copies_num, InfiniteBed{}, ap); %};
- void duplicate_objects_grid(unsigned int x, unsigned int y, double dist);
-
+ bool arrange_objects(double dist) %code%{ ArrangeParams ap{scaled(dist)}; arrange_objects(*THIS, InfiniteBed{}, ap); %};
+ void duplicate(unsigned int copies_num, double dist) %code%{ ArrangeParams ap{scaled(dist)}; duplicate(*THIS, copies_num, InfiniteBed{}, ap); %};
bool looks_like_multipart_object() const;
void convert_multipart_object(unsigned int max_extruders);
@@ -150,9 +146,6 @@ ModelMaterial::attributes()
void invalidate_bounding_box();
Clone mesh();
Clone raw_mesh();
- Clone instance_bounding_box(int idx)
- %code%{ RETVAL = THIS->instance_bounding_box(idx, true); %};
- Clone bounding_box();
%name{_add_volume} Ref add_volume(TriangleMesh* mesh)
%code%{ RETVAL = THIS->add_volume(*mesh); %};
@@ -290,7 +283,4 @@ ModelMaterial::attributes()
THIS->set_offset(X, (*offset)(0));
THIS->set_offset(Y, (*offset)(1));
%};
-
- void transform_mesh(TriangleMesh* mesh, bool dont_translate = false) const;
- void transform_polygon(Polygon* polygon) const;
};
diff --git a/xs/xsp/PerimeterGenerator.xsp b/xs/xsp/PerimeterGenerator.xsp
deleted file mode 100644
index a2f589d0b2..0000000000
--- a/xs/xsp/PerimeterGenerator.xsp
+++ /dev/null
@@ -1,40 +0,0 @@
-%module{Slic3r::XS};
-
-%{
-#include
-#include "libslic3r/PerimeterGenerator.hpp"
-#include "libslic3r/Layer.hpp"
-%}
-
-%name{Slic3r::Layer::PerimeterGenerator} class PerimeterGenerator {
- PerimeterGenerator(SurfaceCollection* slices, double layer_height, Flow* flow,
- StaticPrintConfig* region_config, StaticPrintConfig* object_config,
- StaticPrintConfig* print_config, ExtrusionEntityCollection* loops,
- ExtrusionEntityCollection* gap_fill,
- SurfaceCollection* fill_surfaces)
- %code{% RETVAL = new PerimeterGenerator(slices, layer_height, *flow,
- dynamic_cast(region_config),
- dynamic_cast(object_config),
- dynamic_cast(print_config),
- false,
- loops, gap_fill, fill_surfaces); %};
- ~PerimeterGenerator();
-
- void set_lower_slices(ExPolygonCollection* lower_slices)
- %code{% THIS->lower_slices = &lower_slices->expolygons; %};
- void set_layer_id(int layer_id)
- %code{% THIS->layer_id = layer_id; %};
- void set_perimeter_flow(Flow* flow)
- %code{% THIS->perimeter_flow = *flow; %};
- void set_ext_perimeter_flow(Flow* flow)
- %code{% THIS->ext_perimeter_flow = *flow; %};
- void set_overhang_flow(Flow* flow)
- %code{% THIS->overhang_flow = *flow; %};
- void set_solid_infill_flow(Flow* flow)
- %code{% THIS->solid_infill_flow = *flow; %};
-
- Ref config()
- %code{% RETVAL = THIS->config; %};
-
- void process();
-};
diff --git a/xs/xsp/PlaceholderParser.xsp b/xs/xsp/PlaceholderParser.xsp
deleted file mode 100644
index 5fa4e33aa1..0000000000
--- a/xs/xsp/PlaceholderParser.xsp
+++ /dev/null
@@ -1,33 +0,0 @@
-%module{Slic3r::XS};
-
-%{
-#include
-#include
-#include "libslic3r/PlaceholderParser.hpp"
-%}
-
-%name{Slic3r::GCode::PlaceholderParser} class PlaceholderParser {
- PlaceholderParser();
- ~PlaceholderParser();
-
- void apply_config(DynamicPrintConfig *config)
- %code%{ THIS->apply_config(*config); %};
- void set(std::string key, int value);
- std::string process(std::string str) const
- %code%{
- try {
- RETVAL = THIS->process(str, 0);
- } catch (std::exception& e) {
- croak("%s\n", e.what());
- }
- %};
-
- bool evaluate_boolean_expression(const char *str) const
- %code%{
- try {
- RETVAL = THIS->evaluate_boolean_expression(str, THIS->config());
- } catch (std::exception& e) {
- croak("%s\n", e.what());
- }
- %};
-};
diff --git a/xs/xsp/Polygon.xsp b/xs/xsp/Polygon.xsp
index 984eb16a91..873c4bcc93 100644
--- a/xs/xsp/Polygon.xsp
+++ b/xs/xsp/Polygon.xsp
@@ -23,7 +23,6 @@
%code{% RETVAL = THIS->split_at_vertex(*point); %};
Clone split_at_index(int index);
Clone split_at_first_point();
- Points equally_spaced_points(double distance);
double length();
double area();
bool is_counter_clockwise();
@@ -35,12 +34,8 @@
bool contains_point(Point* point)
%code{% RETVAL = THIS->contains(*point); %};
Polygons simplify(double tolerance);
- Polygons triangulate_convex()
- %code{% THIS->triangulate_convex(&RETVAL); %};
Clone centroid();
Clone bounding_box();
- Clone point_projection(Point* point)
- %code{% RETVAL = THIS->point_projection(*point); %};
Clone first_intersection(Line* line)
%code{%
Point p;
diff --git a/xs/xsp/Polyline.xsp b/xs/xsp/Polyline.xsp
index 7846ea5f4c..3534e329ed 100644
--- a/xs/xsp/Polyline.xsp
+++ b/xs/xsp/Polyline.xsp
@@ -3,7 +3,6 @@
%{
#include
#include "libslic3r/BoundingBox.hpp"
-#include "libslic3r/ClipperUtils.hpp"
#include "libslic3r/Polyline.hpp"
%}
@@ -23,7 +22,6 @@
Lines lines();
Clone first_point();
Clone last_point();
- Points equally_spaced_points(double distance);
double length();
bool is_valid();
void clip_end(double distance);
@@ -33,9 +31,7 @@
void simplify(double tolerance);
void split_at(Point* point, Polyline* p1, Polyline* p2)
%code{% THIS->split_at(*point, p1, p2); %};
- bool is_straight();
Clone bounding_box();
- void remove_duplicate_points();
%{
Polyline*
@@ -76,15 +72,5 @@ Polyline::rotate(angle, center_sv)
from_SV_check(center_sv, ¢er);
THIS->rotate(angle, center);
-Polygons
-Polyline::grow(delta, joinType = Slic3r::ClipperLib::jtSquare, miterLimit = 3)
- const float delta
- Slic3r::ClipperLib::JoinType joinType
- double miterLimit
- CODE:
- RETVAL = offset(*THIS, delta, joinType, miterLimit);
- OUTPUT:
- RETVAL
-
%}
};
diff --git a/xs/xsp/PolylineCollection.xsp b/xs/xsp/PolylineCollection.xsp
deleted file mode 100644
index d8bb41b497..0000000000
--- a/xs/xsp/PolylineCollection.xsp
+++ /dev/null
@@ -1,81 +0,0 @@
-%module{Slic3r::XS};
-
-%{
-#include
-
-#include "libslic3r.h"
-#include "Polyline.hpp"
-#include "ShortestPath.hpp"
-
-%}
-
-%name{Slic3r::Polyline::Collection} class PolylineCollection {
- ~PolylineCollection();
- Clone clone()
- %code{% RETVAL = THIS; %};
- void clear()
- %code{% THIS->polylines.clear(); %};
- PolylineCollection* chained_path(bool no_reverse)
- %code{%
- RETVAL = new PolylineCollection();
- RETVAL->polylines = chain_polylines(THIS->polylines, &THIS->polylines.front().first_point());
- %};
- PolylineCollection* chained_path_from(Point* start_near, bool no_reverse)
- %code{%
- RETVAL = new PolylineCollection();
- RETVAL->polylines = chain_polylines(THIS->polylines, start_near);
- %};
- int count()
- %code{% RETVAL = THIS->polylines.size(); %};
-%{
-
-PolylineCollection*
-PolylineCollection::new(...)
- CODE:
- RETVAL = new PolylineCollection ();
- // ST(0) is class name, others are Polylines
- RETVAL->polylines.resize(items-1);
- for (unsigned int i = 1; i < items; i++) {
- // Note: a COPY of the input is stored
- from_SV_check(ST(i), &RETVAL->polylines[i-1]);
- }
- OUTPUT:
- RETVAL
-
-SV*
-PolylineCollection::arrayref()
- CODE:
- AV* av = newAV();
- av_fill(av, THIS->polylines.size()-1);
- int i = 0;
- for (Polylines::iterator it = THIS->polylines.begin(); it != THIS->polylines.end(); ++it) {
- av_store(av, i++, perl_to_SV_ref(*it));
- }
- RETVAL = newRV_noinc((SV*)av);
- OUTPUT:
- RETVAL
-
-SV*
-PolylineCollection::pp()
- CODE:
- AV* av = newAV();
- av_fill(av, THIS->polylines.size()-1);
- int i = 0;
- for (Polylines::iterator it = THIS->polylines.begin(); it != THIS->polylines.end(); ++it) {
- av_store(av, i++, to_SV_pureperl(&*it));
- }
- RETVAL = newRV_noinc((SV*)av);
- OUTPUT:
- RETVAL
-
-void
-PolylineCollection::append(...)
- CODE:
- for (unsigned int i = 1; i < items; i++) {
- Polyline polyline;
- from_SV_check(ST(i), &polyline);
- THIS->polylines.push_back(polyline);
- }
-
-%}
-};
diff --git a/xs/xsp/Print.xsp b/xs/xsp/Print.xsp
index bffdd933fb..97cbdafe32 100644
--- a/xs/xsp/Print.xsp
+++ b/xs/xsp/Print.xsp
@@ -3,27 +3,6 @@
%{
#include
#include "libslic3r/Print.hpp"
-#include "libslic3r/PlaceholderParser.hpp"
-%}
-
-%package{Slic3r::Print::State};
-%{
-
-IV
-_constant()
- ALIAS:
- STEP_SLICE = posSlice
- STEP_PERIMETERS = posPerimeters
- STEP_PREPARE_INFILL = posPrepareInfill
- STEP_INFILL = posInfill
- STEP_SUPPORTMATERIAL = posSupportMaterial
- STEP_SKIRTBRIM = psSkirtBrim
- STEP_WIPE_TOWER = psWipeTower
- PROTOTYPE:
- CODE:
- RETVAL = ix;
- OUTPUT: RETVAL
-
%}
%name{Slic3r::Print::Region} class PrintRegion {
@@ -45,12 +24,6 @@ _constant()
size_t layer_count();
Ref get_layer(int idx);
- size_t support_layer_count();
- Ref get_support_layer(int idx);
-
- bool step_done(PrintObjectStep step)
- %code%{ RETVAL = THIS->is_step_done(step); %};
-
void slice();
};
@@ -62,16 +35,10 @@ _constant()
%code%{ RETVAL = const_cast(&THIS->model()); %};
Ref config()
%code%{ RETVAL = const_cast(static_cast(&THIS->config())); %};
- Ref placeholder_parser()
- %code%{ RETVAL = const_cast(&THIS->placeholder_parser()); %};
Ref skirt()
%code%{ RETVAL = const_cast(&THIS->skirt()); %};
Ref brim()
%code%{ RETVAL = const_cast(&THIS->brim()); %};
-// std::string estimated_normal_print_time()
-// %code%{ RETVAL = THIS->print_statistics().estimated_normal_print_time; %};
-// std::string estimated_silent_print_time()
-// %code%{ RETVAL = THIS->print_statistics().estimated_silent_print_time; %};
double total_used_filament()
%code%{ RETVAL = THIS->print_statistics().total_used_filament; %};
double total_extruded_volume()
@@ -96,25 +63,6 @@ _constant()
PrintRegionPtrs* regions()
%code%{ RETVAL = const_cast(&THIS->print_regions_mutable()); %};
- bool step_done(PrintStep step)
- %code%{ RETVAL = THIS->is_step_done(step); %};
- bool object_step_done(PrintObjectStep step)
- %code%{ RETVAL = THIS->is_step_done(step); %};
-
- SV* filament_stats()
- %code%{
- HV* hv = newHV();
- for (std::map::const_iterator it = THIS->print_statistics().filament_stats.begin(); it != THIS->print_statistics().filament_stats.end(); ++it) {
- // stringify extruder_id
- std::ostringstream ss;
- ss << it->first;
- std::string str = ss.str();
-
- (void)hv_store( hv, str.c_str(), str.length(), newSViv(it->second), 0 );
- RETVAL = newRV_noinc((SV*)hv);
- }
- %};
- bool has_support_material() const;
void auto_assign_extruders(ModelObject* model_object);
std::string output_filepath(std::string path = "")
%code%{
@@ -138,7 +86,6 @@ _constant()
mat.second->config.touch();
RETVAL = THIS->apply(*model, *config);
%};
- bool has_infinite_skirt();
std::vector extruders() const;
int validate() %code%{
std::string err = THIS->validate();
@@ -147,10 +94,7 @@ _constant()
RETVAL = 1;
%};
- void set_callback_event(int evt) %code%{
- %};
void set_status_silent();
- void set_status(int percent, const char *message);
void process() %code%{
try {
diff --git a/xs/xsp/Surface.xsp b/xs/xsp/Surface.xsp
index 8804b851bb..3fffea9ab8 100644
--- a/xs/xsp/Surface.xsp
+++ b/xs/xsp/Surface.xsp
@@ -3,7 +3,6 @@
%{
#include
#include "libslic3r/Surface.hpp"
-#include "libslic3r/ClipperUtils.hpp"
%}
%name{Slic3r::Surface} class Surface {
diff --git a/xs/xsp/SurfaceCollection.xsp b/xs/xsp/SurfaceCollection.xsp
index 19cf3f8286..0d31c5ae3b 100644
--- a/xs/xsp/SurfaceCollection.xsp
+++ b/xs/xsp/SurfaceCollection.xsp
@@ -42,20 +42,6 @@ SurfaceCollection::filter_by_type(surface_type)
OUTPUT:
RETVAL
-void
-SurfaceCollection::replace(index, surface)
- int index
- Surface* surface
- CODE:
- THIS->surfaces[index] = *surface;
-
-void
-SurfaceCollection::set_surface_type(index, surface_type)
- int index
- SurfaceType surface_type;
- CODE:
- THIS->surfaces[index].surface_type = surface_type;
-
SV*
SurfaceCollection::group()
CODE:
diff --git a/xs/xsp/TriangleMesh.xsp b/xs/xsp/TriangleMesh.xsp
index a9dbe654d3..5dc0df7465 100644
--- a/xs/xsp/TriangleMesh.xsp
+++ b/xs/xsp/TriangleMesh.xsp
@@ -28,7 +28,6 @@
void merge(TriangleMesh* mesh)
%code{% THIS->merge(*mesh); %};
Clone convex_hull();
- Clone bounding_box();
Clone center()
%code{% RETVAL = THIS->bounding_box().center(); %};
int facets_count();
@@ -62,22 +61,6 @@ TriangleMesh::ReadFromPerl(vertices, facets)
}
*THIS = TriangleMesh(std::move(out_vertices), std::move(out_indices));
-SV*
-TriangleMesh::stats()
- CODE:
- HV* hv = newHV();
- (void)hv_stores( hv, "number_of_facets", newSViv(THIS->facets_count()) );
- (void)hv_stores( hv, "number_of_parts", newSViv(THIS->stats().number_of_parts) );
- (void)hv_stores( hv, "volume", newSVnv(THIS->stats().volume) );
- (void)hv_stores( hv, "degenerate_facets", newSViv(THIS->stats().repaired_errors.degenerate_facets) );
- (void)hv_stores( hv, "edges_fixed", newSViv(THIS->stats().repaired_errors.edges_fixed) );
- (void)hv_stores( hv, "facets_removed", newSViv(THIS->stats().repaired_errors.facets_removed) );
- (void)hv_stores( hv, "facets_reversed", newSViv(THIS->stats().repaired_errors.facets_reversed) );
- (void)hv_stores( hv, "backwards_edges", newSViv(THIS->stats().repaired_errors.backwards_edges) );
- RETVAL = (SV*)newRV_noinc((SV*)hv);
- OUTPUT:
- RETVAL
-
SV*
TriangleMesh::vertices()
CODE:
@@ -128,78 +111,5 @@ TriangleMesh::size()
OUTPUT:
RETVAL
-SV*
-TriangleMesh::slice(z)
- std::vector z
- CODE:
- // convert doubles to floats
- std::vector z_f = cast(z);
-
- std::vector layers = slice_mesh_ex(THIS->its, z_f, 0.049f);
-
- AV* layers_av = newAV();
- size_t len = layers.size();
- if (len > 0) av_extend(layers_av, len-1);
- for (unsigned int i = 0; i < layers.size(); i++) {
- AV* expolygons_av = newAV();
- len = layers[i].size();
- if (len > 0) av_extend(expolygons_av, len-1);
- unsigned int j = 0;
- for (ExPolygons::iterator it = layers[i].begin(); it != layers[i].end(); ++it) {
- av_store(expolygons_av, j++, perl_to_SV_clone_ref(*it));
- }
- av_store(layers_av, i, newRV_noinc((SV*)expolygons_av));
- }
- RETVAL = (SV*)newRV_noinc((SV*)layers_av);
- OUTPUT:
- RETVAL
-
-void
-TriangleMesh::cut(z, upper_mesh, lower_mesh)
- float z;
- TriangleMesh* upper_mesh;
- TriangleMesh* lower_mesh;
- CODE:
- indexed_triangle_set upper, lower;
- cut_mesh(THIS->its, z, upper_mesh ? &upper : nullptr, lower_mesh ? &lower : nullptr);
- if (upper_mesh)
- *upper_mesh = TriangleMesh(upper);
- if (lower_mesh)
- *lower_mesh = TriangleMesh(lower);
-
-std::vector
-TriangleMesh::bb3()
- CODE:
- RETVAL.push_back(THIS->stats().min(0));
- RETVAL.push_back(THIS->stats().min(1));
- RETVAL.push_back(THIS->stats().max(0));
- RETVAL.push_back(THIS->stats().max(1));
- RETVAL.push_back(THIS->stats().min(2));
- RETVAL.push_back(THIS->stats().max(2));
- OUTPUT:
- RETVAL
-
-
-Clone
-cube(double x, double y, double z)
- CODE:
- RETVAL = make_cube(x,y,z);
- OUTPUT:
- RETVAL
-
-Clone
-cylinder(double r, double h)
- CODE:
- RETVAL = make_cylinder(r, h);
- OUTPUT:
- RETVAL
-
-Clone
-sphere(double rho)
- CODE:
- RETVAL = make_sphere(rho);
- OUTPUT:
- RETVAL
-
%}
};
diff --git a/xs/xsp/XS.xsp b/xs/xsp/XS.xsp
index 68ea282bc0..66a35366bd 100644
--- a/xs/xsp/XS.xsp
+++ b/xs/xsp/XS.xsp
@@ -35,129 +35,4 @@ set_logging_level(level)
CODE:
Slic3r::set_logging_level(level);
-void
-trace(level, message)
- unsigned int level;
- char *message;
- CODE:
- Slic3r::trace(level, message);
-
-void
-disable_multi_threading()
- CODE:
- Slic3r::disable_multi_threading();
-
-void
-set_var_dir(dir)
- char *dir;
- CODE:
- Slic3r::set_var_dir(dir);
-
-void
-set_local_dir(dir)
- char *dir;
- CODE:
- Slic3r::set_local_dir(dir);
-
-char*
-var_dir()
- CODE:
- RETVAL = const_cast(Slic3r::var_dir().c_str());
- OUTPUT: RETVAL
-
-void
-set_resources_dir(dir)
- char *dir;
- CODE:
- Slic3r::set_resources_dir(dir);
-
-char*
-resources_dir()
- CODE:
- RETVAL = const_cast(Slic3r::resources_dir().c_str());
- OUTPUT: RETVAL
-
-std::string
-var(file_name)
- const char *file_name;
- CODE:
- RETVAL = Slic3r::var(file_name);
- OUTPUT: RETVAL
-
-void
-set_data_dir(dir)
- char *dir;
- CODE:
- Slic3r::set_data_dir(dir);
-
-char*
-data_dir()
- CODE:
- RETVAL = const_cast(Slic3r::data_dir().c_str());
- OUTPUT: RETVAL
-
-local_encoded_string
-encode_path(src)
- const char *src;
- CODE:
- RETVAL = Slic3r::encode_path(src);
- OUTPUT: RETVAL
-
-std::string
-decode_path(src)
- const char *src;
- CODE:
- RETVAL = Slic3r::decode_path(src);
- OUTPUT: RETVAL
-
-std::string
-normalize_utf8_nfc(src)
- const char *src;
- CODE:
- RETVAL = Slic3r::normalize_utf8_nfc(src);
- OUTPUT: RETVAL
-
-std::string
-path_to_filename(src)
- const char *src;
- CODE:
- RETVAL = Slic3r::PerlUtils::path_to_filename(src);
- OUTPUT: RETVAL
-
-local_encoded_string
-path_to_filename_raw(src)
- const char *src;
- CODE:
- RETVAL = Slic3r::PerlUtils::path_to_filename(src);
- OUTPUT: RETVAL
-
-std::string
-path_to_stem(src)
- const char *src;
- CODE:
- RETVAL = Slic3r::PerlUtils::path_to_stem(src);
- OUTPUT: RETVAL
-
-std::string
-path_to_extension(src)
- const char *src;
- CODE:
- RETVAL = Slic3r::PerlUtils::path_to_extension(src);
- OUTPUT: RETVAL
-
-std::string
-path_to_parent_path(src)
- const char *src;
- CODE:
- RETVAL = Slic3r::PerlUtils::path_to_parent_path(src);
- OUTPUT: RETVAL
-
-void
-xspp_test_croak_hangs_on_strawberry()
- CODE:
- try {
- throw 1;
- } catch (...) {
- croak("xspp_test_croak_hangs_on_strawberry: exception catched\n");
- }
-%}
\ No newline at end of file
+%}
diff --git a/xs/xsp/my.map b/xs/xsp/my.map
index a660041bc8..5174bdfa95 100644
--- a/xs/xsp/my.map
+++ b/xs/xsp/my.map
@@ -1,7 +1,6 @@
coordf_t T_NV
std::string T_STD_STRING
-local_encoded_string T_STD_STRING_LOCAL_ENCODING
t_config_option_key T_STD_STRING
t_model_material_id T_STD_STRING
@@ -15,21 +14,10 @@ std::vector T_STD_VECTOR_UINT
std::vector T_STD_VECTOR_DOUBLE
-t_layer_height_ranges T_LAYER_HEIGHT_RANGES
-
-
BoundingBox* O_OBJECT_SLIC3R
Ref O_OBJECT_SLIC3R_T
Clone O_OBJECT_SLIC3R_T
-BoundingBoxf* O_OBJECT_SLIC3R
-Ref O_OBJECT_SLIC3R_T
-Clone O_OBJECT_SLIC3R_T
-
-BoundingBoxf3* O_OBJECT_SLIC3R
-Ref O_OBJECT_SLIC3R_T
-Clone O_OBJECT_SLIC3R_T
-
DynamicPrintConfig* O_OBJECT_SLIC3R
Ref O_OBJECT_SLIC3R_T
Clone O_OBJECT_SLIC3R_T
@@ -37,12 +25,6 @@ Clone O_OBJECT_SLIC3R_T
StaticPrintConfig* O_OBJECT_SLIC3R
Ref O_OBJECT_SLIC3R_T
-PrintObjectConfig* O_OBJECT_SLIC3R
-Ref O_OBJECT_SLIC3R_T
-
-PrintRegionConfig* O_OBJECT_SLIC3R
-Ref O_OBJECT_SLIC3R_T
-
GCodeConfig* O_OBJECT_SLIC3R
Ref O_OBJECT_SLIC3R_T
@@ -52,8 +34,6 @@ Ref O_OBJECT_SLIC3R_T
FullPrintConfig* O_OBJECT_SLIC3R
Ref O_OBJECT_SLIC3R_T
-ZTable* O_OBJECT
-
TriangleMesh* O_OBJECT_SLIC3R
Ref O_OBJECT_SLIC3R_T
Clone O_OBJECT_SLIC3R_T
@@ -78,18 +58,10 @@ Line* O_OBJECT_SLIC3R
Ref O_OBJECT_SLIC3R_T
Clone O_OBJECT_SLIC3R_T
-Linef3* O_OBJECT_SLIC3R
-Ref O_OBJECT_SLIC3R_T
-Clone O_OBJECT_SLIC3R_T
-
Polyline* O_OBJECT_SLIC3R
Ref O_OBJECT_SLIC3R_T
Clone O_OBJECT_SLIC3R_T
-PolylineCollection* O_OBJECT_SLIC3R
-Ref O_OBJECT_SLIC3R_T
-Clone O_OBJECT_SLIC3R_T
-
Polygon* O_OBJECT_SLIC3R
Ref O_OBJECT_SLIC3R_T
Clone O_OBJECT_SLIC3R_T
@@ -98,18 +70,10 @@ ExPolygon* O_OBJECT_SLIC3R
Ref O_OBJECT_SLIC3R_T
Clone O_OBJECT_SLIC3R_T
-ExPolygonCollection* O_OBJECT_SLIC3R
-Ref O_OBJECT_SLIC3R_T
-Clone O_OBJECT_SLIC3R_T
-
ExtrusionEntityCollection* O_OBJECT_SLIC3R
Ref O_OBJECT_SLIC3R_T
Clone O_OBJECT_SLIC3R_T
-ExtrusionMultiPath* O_OBJECT_SLIC3R
-Ref O_OBJECT_SLIC3R_T
-Clone O_OBJECT_SLIC3R_T
-
ExtrusionPath* O_OBJECT_SLIC3R
Ref O_OBJECT_SLIC3R_T
Clone O_OBJECT_SLIC3R_T
@@ -118,13 +82,6 @@ ExtrusionLoop* O_OBJECT_SLIC3R
Ref O_OBJECT_SLIC3R_T
Clone O_OBJECT_SLIC3R_T
-Flow* O_OBJECT_SLIC3R
-Ref O_OBJECT_SLIC3R_T
-Clone O_OBJECT_SLIC3R_T
-
-PrintState* O_OBJECT_SLIC3R
-Ref O_OBJECT_SLIC3R_T
-
Surface* O_OBJECT_SLIC3R
Ref O_OBJECT_SLIC3R_T
Clone O_OBJECT_SLIC3R_T
@@ -168,13 +125,6 @@ Ref O_OBJECT_SLIC3R_T
Layer* O_OBJECT_SLIC3R
Ref O_OBJECT_SLIC3R_T
-SupportLayer* O_OBJECT_SLIC3R
-Ref O_OBJECT_SLIC3R_T
-
-PlaceholderParser* O_OBJECT_SLIC3R
-Ref O_OBJECT_SLIC3R_T
-Clone O_OBJECT_SLIC3R_T
-
CoolingBuffer* O_OBJECT_SLIC3R
Ref O_OBJECT_SLIC3R_T
Clone O_OBJECT_SLIC3R_T
@@ -183,28 +133,11 @@ GCode* O_OBJECT_SLIC3R
Ref O_OBJECT_SLIC3R_T
Clone O_OBJECT_SLIC3R_T
-BridgeDetector* O_OBJECT_SLIC3R
-Ref O_OBJECT_SLIC3R_T
-Clone O_OBJECT_SLIC3R_T
-
-PerimeterGenerator* O_OBJECT_SLIC3R
-Ref