From 7380787b3a53252beb4650ccd1edb8ce2027a1db Mon Sep 17 00:00:00 2001 From: YuSanka Date: Wed, 4 May 2022 12:44:31 +0200 Subject: [PATCH 1/4] Settings Tab: Fix for https://dev.prusa3d.com/browse/SPE-1229 --- src/slic3r/GUI/Tab.cpp | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) 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 From a627614b58bbc6bde9cb1afabaebfbd629492723 Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Wed, 4 May 2022 15:05:56 +0200 Subject: [PATCH 2/4] Perl unit tests for perimeters and multi-material were rewritten to C++. Perl binding was slimmed down, namely Clipper is no more linked by Perl. --- lib/Slic3r.pm | 83 --- lib/Slic3r/Config.pm | 41 -- lib/Slic3r/ExPolygon.pm | 7 - lib/Slic3r/Geometry/Clipper.pm | 13 - lib/Slic3r/Layer.pm | 3 - lib/Slic3r/Line.pm | 5 - lib/Slic3r/Model.pm | 7 - lib/Slic3r/Polygon.pm | 7 +- lib/Slic3r/Print/Object.pm | 6 - lib/Slic3r/Print/State.pm | 12 - src/libslic3r/GCodeReader.cpp | 64 ++- src/libslic3r/GCodeReader.hpp | 2 + src/libslic3r/Polyline.cpp | 2 +- src/libslic3r/Polyline.hpp | 9 - src/libslic3r/PrintConfig.hpp | 10 + src/libslic3r/Utils.hpp | 21 - src/libslic3r/utils.cpp | 63 --- t/dynamic.t | 93 ---- t/geometry.t | 9 +- t/multi.t | 221 -------- t/perimeters.t | 444 ---------------- t/slice.t | 152 ------ t/support.t | 272 ---------- tests/fff_print/CMakeLists.txt | 2 + tests/fff_print/test_extrusion_entity.cpp | 9 +- tests/fff_print/test_multi.cpp | 268 ++++++++++ tests/fff_print/test_perimeters.cpp | 599 ++++++++++++++++++++++ tests/fff_print/test_support_material.cpp | 259 ++++++++++ tests/libslic3r/test_clipper_utils.cpp | 5 + xs/CMakeLists.txt | 4 - xs/lib/Slic3r/XS.pm | 49 -- xs/src/perlglue.cpp | 5 - xs/t/01_trianglemesh.t | 7 +- xs/t/13_polylinecollection.t | 35 -- xs/xsp/Clipper.xsp | 73 --- xs/xsp/Geometry.xsp | 8 - xs/xsp/Layer.xsp | 41 -- xs/xsp/PerimeterGenerator.xsp | 40 -- xs/xsp/PlaceholderParser.xsp | 33 -- xs/xsp/Polygon.xsp | 1 - xs/xsp/Polyline.xsp | 14 - xs/xsp/PolylineCollection.xsp | 81 --- xs/xsp/Print.xsp | 56 -- xs/xsp/Surface.xsp | 1 - xs/xsp/TriangleMesh.xsp | 89 ---- xs/xsp/XS.xsp | 127 +---- xs/xsp/my.map | 113 ---- xs/xsp/typemap.xspt | 39 -- 48 files changed, 1194 insertions(+), 2310 deletions(-) delete mode 100644 lib/Slic3r/Geometry/Clipper.pm delete mode 100644 lib/Slic3r/Print/State.pm delete mode 100644 t/dynamic.t delete mode 100644 t/multi.t delete mode 100644 t/perimeters.t delete mode 100644 t/slice.t delete mode 100644 t/support.t create mode 100644 tests/fff_print/test_multi.cpp create mode 100644 tests/fff_print/test_perimeters.cpp delete mode 100644 xs/t/13_polylinecollection.t delete mode 100644 xs/xsp/Clipper.xsp delete mode 100644 xs/xsp/PerimeterGenerator.xsp delete mode 100644 xs/xsp/PlaceholderParser.xsp delete mode 100644 xs/xsp/PolylineCollection.xsp diff --git a/lib/Slic3r.pm b/lib/Slic3r.pm index d9274bea93..cd8f151f8f 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 @@ -60,82 +55,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..aeaca998fd 100644 --- a/lib/Slic3r/Config.pm +++ b/lib/Slic3r/Config.pm @@ -23,47 +23,6 @@ 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'; diff --git a/lib/Slic3r/ExPolygon.pm b/lib/Slic3r/ExPolygon.pm index 4ab1bc8ab4..6090a073be 100644 --- a/lib/Slic3r/ExPolygon.pm +++ b/lib/Slic3r/ExPolygon.pm @@ -4,13 +4,6 @@ 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; 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..35da7afe7d 100644 --- a/lib/Slic3r/Print/Object.pm +++ b/lib/Slic3r/Print/Object.pm @@ -5,7 +5,6 @@ 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 +12,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/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/Polyline.cpp b/src/libslic3r/Polyline.cpp index 1255d5473d..43c5afe737 100644 --- a/src/libslic3r/Polyline.cpp +++ b/src/libslic3r/Polyline.cpp @@ -196,7 +196,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..be2e2dbef6 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -211,6 +211,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. 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/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/geometry.t b/t/geometry.t index 874dab9877..12a1ca743b 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 => 26; BEGIN { use FindBin; @@ -125,13 +125,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..28f75bf2cd 100644 --- a/tests/fff_print/CMakeLists.txt +++ b/tests/fff_print/CMakeLists.txt @@ -10,6 +10,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_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_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..24d949be68 100644 --- a/tests/libslic3r/test_clipper_utils.cpp +++ b/tests/libslic3r/test_clipper_utils.cpp @@ -301,6 +301,11 @@ SCENARIO("Various Clipper operations - t/clipper.t", "[ClipperUtils]") { } } } + 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..ab11e4989b 100644 --- a/xs/CMakeLists.txt +++ b/xs/CMakeLists.txt @@ -45,7 +45,6 @@ set(XSP_DIR ${CMAKE_CURRENT_SOURCE_DIR}/xsp) 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 @@ -59,12 +58,9 @@ set(XS_XSP_FILES ${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..9a0181b652 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,11 +43,6 @@ 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 }, @@ -197,31 +177,6 @@ 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 @@ -240,13 +195,11 @@ for my $class (qw( 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 @@ -264,10 +217,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..e9f84b8c08 100644 --- a/xs/src/perlglue.cpp +++ b/xs/src/perlglue.cpp @@ -13,15 +13,11 @@ 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"); @@ -46,7 +42,6 @@ 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(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/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/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/Geometry.xsp b/xs/xsp/Geometry.xsp index e59e8793b2..6e808fd8c2 100644 --- a/xs/xsp/Geometry.xsp +++ b/xs/xsp/Geometry.xsp @@ -47,14 +47,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 diff --git a/xs/xsp/Layer.xsp b/xs/xsp/Layer.xsp index b97e340bdb..4ab7fe1887 100644 --- a/xs/xsp/Layer.xsp +++ b/xs/xsp/Layer.xsp @@ -65,9 +65,6 @@ 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 +76,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/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..bc4d412d95 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(); 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/TriangleMesh.xsp b/xs/xsp/TriangleMesh.xsp index a9dbe654d3..91b3b40a1d 100644 --- a/xs/xsp/TriangleMesh.xsp +++ b/xs/xsp/TriangleMesh.xsp @@ -62,22 +62,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 +112,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..131f82e799 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,9 +14,6 @@ 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 @@ -52,8 +48,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 @@ -86,10 +80,6 @@ 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 @@ -122,9 +112,6 @@ 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 +155,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 @@ -187,21 +167,10 @@ BridgeDetector* O_OBJECT_SLIC3R Ref O_OBJECT_SLIC3R_T Clone O_OBJECT_SLIC3R_T -PerimeterGenerator* O_OBJECT_SLIC3R -Ref O_OBJECT_SLIC3R_T -Clone O_OBJECT_SLIC3R_T - -PrintObjectSupportMaterial* O_OBJECT_SLIC3R -Ref O_OBJECT_SLIC3R_T -Clone O_OBJECT_SLIC3R_T - Axis T_UV ExtrusionLoopRole T_UV ExtrusionRole T_UV -ExtrusionSimulationType T_UV FlowRole T_UV -PrintStep T_UV -PrintObjectStep T_UV SurfaceType T_UV Slic3r::ClipperLib::JoinType T_UV Slic3r::ClipperLib::PolyFillType T_UV @@ -226,7 +195,6 @@ ModelInstancePtrs* T_PTR_ARRAYREF_PTR PrintRegionPtrs* T_PTR_ARRAYREF_PTR PrintObjectPtrs* T_PTR_ARRAYREF_PTR LayerPtrs* T_PTR_ARRAYREF_PTR -SupportLayerPtrs* T_PTR_ARRAYREF_PTR # we return these types whenever we want the items to be returned # by reference and not marked ::Ref because they're newly allocated @@ -244,14 +212,6 @@ T_STD_STRING $var = std::string(c, len); } -INPUT -T_STD_STRING_LOCAL_ENCODING - { - size_t len; - const char * c = SvPV($arg, len); - $var = std::string(c, len); - } - T_STD_VECTOR_STD_STRING if (SvROK($arg) && SvTYPE(SvRV($arg))==SVt_PVAV) { AV* av = (AV*)SvRV($arg); @@ -359,61 +319,11 @@ T_ARRAYREF ${$ALIAS?\q[GvNAME(CvGV(cv))]:\qq[\"$pname\"]}, \"$var\"); -T_LAYER_HEIGHT_RANGES - { - if (!SvROK($arg) || SvTYPE(SvRV($arg)) != SVt_PVAV) { - Perl_croak(aTHX_ \"%s: %s is not an array reference\", - ${$ALIAS?\q[GvNAME(CvGV(cv))]:\qq[\"$pname\"]}, - \"$var\"); - } - - AV* av = (AV*)SvRV($arg); - const unsigned int len = av_len(av)+1; - t_layer_height_ranges tmp_ranges; - for (unsigned int i = 0; i < len; i++) { - SV* elem = *av_fetch(av, i, 0); - if (!SvROK(elem) || SvTYPE(SvRV(elem)) != SVt_PVAV) { - Perl_croak( - aTHX_ \"%s: %s contains something that is not an array reference\", - ${$ALIAS?\q[GvNAME(CvGV(cv))]:\qq[\"$pname\"]}, - \"$var\"); - } - - AV* elemAV = (AV*)SvRV(elem); - if (av_len(elemAV) + 1 != 3) { - Perl_croak( - aTHX_ \"%s: %s contains an array that isn't 3 elements long\", - ${$ALIAS?\q[GvNAME(CvGV(cv))]:\qq[\"$pname\"]}, - \"$var\"); - } - - coordf_t vals[3]; - for (unsigned int j = 0; j < 3; ++j) { - SV *elem_elem = *av_fetch(elemAV, j, 0); - if (!looks_like_number(elem_elem)) { - Perl_croak( - aTHX_ \"%s: layer ranges and heights must be numbers\", - ${$ALIAS?\q[GvNAME(CvGV(cv))]:\qq[\"$pname\"]}); - } - - vals[j] = SvNV(elem_elem); - } - - tmp_ranges[t_layer_height_range(vals[0], vals[1])] = vals[2]; - } - - $var = tmp_ranges; - } - - OUTPUT T_STD_STRING $arg = newSVpvn_utf8( $var.c_str(), $var.length(), true ); -T_STD_STRING_LOCAL_ENCODING - $arg = newSVpvn( $var.c_str(), $var.length() ); - T_STD_VECTOR_STD_STRING AV* av = newAV(); $arg = newRV_noinc((SV*)av); @@ -517,26 +427,3 @@ T_PTR_ARRAYREF av_store(av, i++, to_SV(*it)); } -T_LAYER_HEIGHT_RANGES - AV* av = newAV(); - $arg = newRV_noinc((SV*)av); - sv_2mortal($arg); - const unsigned int len = $var.size(); - if (len > 0) av_extend(av, len-1); - // map is sorted, so we can just copy it in order - int i = 0; - for (${type}::iterator it = $var.begin(); it != $var.end(); ++it) { - const coordf_t range_values[] = { - it->first.first, // key's first = minz - it->first.second, // key's second = maxz - it->second, // value = height - }; - - AV *rangeAV = newAV(); - av_extend(rangeAV, 2); - for (int j = 0; j < 3; ++j) { - av_store(rangeAV, j, newSVnv(range_values[j])); - } - - av_store(av, i++, (SV*)newRV_noinc((SV*)rangeAV)); - } diff --git a/xs/xsp/typemap.xspt b/xs/xsp/typemap.xspt index cc71094459..b59f4b74c2 100644 --- a/xs/xsp/typemap.xspt +++ b/xs/xsp/typemap.xspt @@ -12,7 +12,6 @@ %typemap{std::vector}; %typemap{std::vector*}; %typemap{std::vector}; -%typemap{t_layer_height_ranges}; %typemap{void*}; %typemap{SV*}; %typemap{AV*}; @@ -88,18 +87,12 @@ %typemap{TriangleMesh*}; %typemap{Ref}{simple}; %typemap{Clone}{simple}; -%typemap{PolylineCollection*}; -%typemap{Ref}{simple}; -%typemap{Clone}{simple}; %typemap{BridgeDetector*}; %typemap{Ref}{simple}; %typemap{Clone}{simple}; %typemap{SurfaceCollection*}; %typemap{Ref}{simple}; %typemap{Clone}{simple}; -%typemap{PerimeterGenerator*}; -%typemap{Ref}{simple}; -%typemap{Clone}{simple}; %typemap{Surface*}; %typemap{Ref}{simple}; @@ -124,17 +117,6 @@ %typemap{Layer*}; %typemap{Ref}{simple}; -%typemap{SupportLayer*}; -%typemap{Ref}{simple}; - -%typemap{PrintObjectSupportMaterial*}; -%typemap{Ref}{simple}; -%typemap{Clone}{simple}; - -%typemap{PlaceholderParser*}; -%typemap{Ref}{simple}; -%typemap{Clone}{simple}; - %typemap{CoolingBuffer*}; %typemap{Ref}{simple}; %typemap{Clone}{simple}; @@ -181,13 +163,10 @@ %typemap{ModelInstancePtrs*}; %typemap{Ref}{simple}; %typemap{Clone}{simple}; -%typemap{PresetHints*}; -%typemap{Ref}{simple}; %typemap{PrintRegionPtrs*}; %typemap{PrintObjectPtrs*}; %typemap{LayerPtrs*}; -%typemap{SupportLayerPtrs*}; %typemap{Axis}{parsed}{ %cpp_type{Axis}; @@ -213,27 +192,9 @@ $CVar = (ExtrusionRole)SvUV($PerlVar); %}; }; -%typemap{ExtrusionSimulationType}{parsed}{ - %cpp_type{ExtrusionSimulationType}; - %precall_code{% - $CVar = (ExtrusionSimulationType)SvUV($PerlVar); - %}; -}; %typemap{FlowRole}{parsed}{ %cpp_type{FlowRole}; %precall_code{% $CVar = (FlowRole)SvUV($PerlVar); %}; }; -%typemap{PrintStep}{parsed}{ - %cpp_type{PrintStep}; - %precall_code{% - $CVar = (PrintStep)SvUV($PerlVar); - %}; -}; -%typemap{PrintObjectStep}{parsed}{ - %cpp_type{PrintObjectStep}; - %precall_code{% - $CVar = (PrintObjectStep)SvUV($PerlVar); - %}; -}; From 576c167bd52ea4f377a83c093be9d927a7cd2c75 Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Wed, 4 May 2022 18:21:08 +0200 Subject: [PATCH 3/4] Ported "avoid crossing perimeters" and bridging unit tests from Perl to C++. Further reduced Perl bindings. Got rid of the ExPolygonCollection wrapper, replaced with ExPolygons. --- lib/Slic3r/ExPolygon.pm | 7 - lib/Slic3r/Geometry.pm | 170 ------------------ src/libslic3r/CMakeLists.txt | 2 - src/libslic3r/ClipperUtils.cpp | 6 +- src/libslic3r/ClipperUtils.hpp | 16 +- src/libslic3r/EdgeGrid.cpp | 5 - src/libslic3r/EdgeGrid.hpp | 5 +- src/libslic3r/ExPolygon.hpp | 2 +- src/libslic3r/ExPolygonCollection.cpp | 136 -------------- src/libslic3r/ExPolygonCollection.hpp | 41 ----- src/libslic3r/ExtrusionEntity.cpp | 10 +- src/libslic3r/ExtrusionEntity.hpp | 11 +- src/libslic3r/GCode.cpp | 2 +- src/libslic3r/Geometry.cpp | 7 - src/libslic3r/Geometry.hpp | 1 - src/libslic3r/Geometry/ConvexHull.cpp | 11 ++ src/libslic3r/Geometry/ConvexHull.hpp | 1 + src/libslic3r/Layer.hpp | 5 +- src/libslic3r/Polyline.cpp | 1 - src/libslic3r/SLA/SupportPointGenerator.cpp | 7 +- src/libslic3r/SupportMaterial.cpp | 2 +- t/angles.t | 93 ---------- t/avoid_crossing_perimeters.t | 22 --- t/bridges.t | 137 -------------- t/collinear.t | 87 --------- t/geometry.t | 64 +------ tests/fff_print/CMakeLists.txt | 2 + .../test_avoid_crossing_perimeters.cpp | 16 ++ tests/fff_print/test_bridges.cpp | 133 ++++++++++++++ tests/fff_print/test_fill.cpp | 3 +- tests/libslic3r/test_clipper_utils.cpp | 2 +- xs/CMakeLists.txt | 2 - xs/lib/Slic3r/XS.pm | 7 - xs/src/perlglue.cpp | 2 - xs/t/04_expolygon.t | 26 +-- xs/xsp/BridgeDetector.xsp | 43 ----- xs/xsp/ExPolygonCollection.xsp | 81 --------- xs/xsp/ExtrusionPath.xsp | 16 -- xs/xsp/Geometry.xsp | 8 - xs/xsp/Layer.xsp | 4 - xs/xsp/my.map | 8 - xs/xsp/typemap.xspt | 6 - 42 files changed, 204 insertions(+), 1006 deletions(-) delete mode 100644 src/libslic3r/ExPolygonCollection.cpp delete mode 100644 src/libslic3r/ExPolygonCollection.hpp delete mode 100644 t/angles.t delete mode 100644 t/avoid_crossing_perimeters.t delete mode 100644 t/bridges.t delete mode 100644 t/collinear.t create mode 100644 tests/fff_print/test_avoid_crossing_perimeters.cpp create mode 100644 tests/fff_print/test_bridges.cpp delete mode 100644 xs/xsp/BridgeDetector.xsp delete mode 100644 xs/xsp/ExPolygonCollection.xsp diff --git a/lib/Slic3r/ExPolygon.pm b/lib/Slic3r/ExPolygon.pm index 6090a073be..1b55849ebf 100644 --- a/lib/Slic3r/ExPolygon.pm +++ b/lib/Slic3r/ExPolygon.pm @@ -9,11 +9,4 @@ sub bounding_box { 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/Geometry.pm b/lib/Slic3r/Geometry.pm index ca262fc766..b3c57fcd08 100644 --- a/lib/Slic3r/Geometry.pm +++ b/lib/Slic3r/Geometry.pm @@ -9,13 +9,6 @@ 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 @@ -26,7 +19,6 @@ our @EXPORT_OK = qw( chained_path_from deg2rad rad2deg - rad2deg_dir ); use constant PI => 4 * atan2(1, 1); @@ -43,136 +35,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) = @_; @@ -199,36 +61,4 @@ sub size_2D { ); } -# 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/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/Geometry.cpp b/src/libslic3r/Geometry.cpp index 00fac6c381..6eae832778 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 82ffbd8d19..2ca4ef8844 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 43c5afe737..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 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/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/geometry.t b/t/geometry.t index 12a1ca743b..981621ee8d 100644 --- a/t/geometry.t +++ b/t/geometry.t @@ -2,7 +2,7 @@ use Test::More; use strict; use warnings; -plan tests => 26; +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'; -} #========================================================== diff --git a/tests/fff_print/CMakeLists.txt b/tests/fff_print/CMakeLists.txt index 28f75bf2cd..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 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_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/libslic3r/test_clipper_utils.cpp b/tests/libslic3r/test_clipper_utils.cpp index 24d949be68..048ebba107 100644 --- a/tests/libslic3r/test_clipper_utils.cpp +++ b/tests/libslic3r/test_clipper_utils.cpp @@ -294,7 +294,7 @@ 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())); diff --git a/xs/CMakeLists.txt b/xs/CMakeLists.txt index ab11e4989b..8551aaff14 100644 --- a/xs/CMakeLists.txt +++ b/xs/CMakeLists.txt @@ -44,10 +44,8 @@ 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}/Config.xsp ${XSP_DIR}/ExPolygon.xsp - ${XSP_DIR}/ExPolygonCollection.xsp ${XSP_DIR}/ExtrusionEntityCollection.xsp ${XSP_DIR}/ExtrusionLoop.xsp ${XSP_DIR}/ExtrusionMultiPath.xsp diff --git a/xs/lib/Slic3r/XS.pm b/xs/lib/Slic3r/XS.pm index 9a0181b652..5578a70abc 100644 --- a/xs/lib/Slic3r/XS.pm +++ b/xs/lib/Slic3r/XS.pm @@ -48,11 +48,6 @@ 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 }, @@ -179,7 +174,6 @@ sub new { package main; for my $class (qw( - Slic3r::BridgeDetector Slic3r::Config Slic3r::Config::Full Slic3r::Config::GCode @@ -188,7 +182,6 @@ for my $class (qw( Slic3r::Config::PrintRegion Slic3r::Config::Static Slic3r::ExPolygon - Slic3r::ExPolygon::Collection Slic3r::ExtrusionLoop Slic3r::ExtrusionMultiPath Slic3r::ExtrusionPath diff --git a/xs/src/perlglue.cpp b/xs/src/perlglue.cpp index e9f84b8c08..e513ec4627 100644 --- a/xs/src/perlglue.cpp +++ b/xs/src/perlglue.cpp @@ -4,7 +4,6 @@ namespace Slic3r { REGISTER_CLASS(ExPolygon, "ExPolygon"); -REGISTER_CLASS(ExPolygonCollection, "ExPolygon::Collection"); REGISTER_CLASS(ExtrusionMultiPath, "ExtrusionMultiPath"); REGISTER_CLASS(ExtrusionPath, "ExtrusionPath"); REGISTER_CLASS(ExtrusionLoop, "ExtrusionLoop"); @@ -29,7 +28,6 @@ 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"); 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/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/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/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/Geometry.xsp b/xs/xsp/Geometry.xsp index 6e808fd8c2..23daa4510f 100644 --- a/xs/xsp/Geometry.xsp +++ b/xs/xsp/Geometry.xsp @@ -64,14 +64,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 diff --git a/xs/xsp/Layer.xsp b/xs/xsp/Layer.xsp index 4ab7fe1887..da35734ffd 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 { @@ -59,9 +58,6 @@ 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; %}; diff --git a/xs/xsp/my.map b/xs/xsp/my.map index 131f82e799..fce0c47ad8 100644 --- a/xs/xsp/my.map +++ b/xs/xsp/my.map @@ -88,10 +88,6 @@ 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 @@ -163,10 +159,6 @@ 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 - Axis T_UV ExtrusionLoopRole T_UV ExtrusionRole T_UV diff --git a/xs/xsp/typemap.xspt b/xs/xsp/typemap.xspt index b59f4b74c2..d4801fc393 100644 --- a/xs/xsp/typemap.xspt +++ b/xs/xsp/typemap.xspt @@ -54,9 +54,6 @@ %typemap{ExPolygon*}; %typemap{Ref}{simple}; %typemap{Clone}{simple}; -%typemap{ExPolygonCollection*}; -%typemap{Ref}{simple}; -%typemap{Clone}{simple}; %typemap{Flow*}; %typemap{Ref}{simple}; %typemap{Clone}{simple}; @@ -87,9 +84,6 @@ %typemap{TriangleMesh*}; %typemap{Ref}{simple}; %typemap{Clone}{simple}; -%typemap{BridgeDetector*}; -%typemap{Ref}{simple}; -%typemap{Clone}{simple}; %typemap{SurfaceCollection*}; %typemap{Ref}{simple}; %typemap{Clone}{simple}; From aa3231e2c5ed8a5d8c2125161a2f5f298964dbee Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Wed, 4 May 2022 19:10:34 +0200 Subject: [PATCH 4/4] Further slimming of Perl bindings. --- lib/Slic3r.pm | 1 - lib/Slic3r/Config.pm | 3 -- lib/Slic3r/Flow.pm | 13 ------ lib/Slic3r/Geometry.pm | 10 ----- lib/Slic3r/Print/Object.pm | 1 - src/libslic3r/PrintConfig.hpp | 6 --- t/gaps.t | 1 - xs/CMakeLists.txt | 2 - xs/lib/Slic3r/XS.pm | 32 -------------- xs/src/perlglue.cpp | 9 +--- xs/xsp/BoundingBox.xsp | 66 ---------------------------- xs/xsp/Config.xsp | 4 -- xs/xsp/ExtrusionEntityCollection.xsp | 4 -- xs/xsp/ExtrusionMultiPath.xsp | 38 ---------------- xs/xsp/Flow.xsp | 60 ------------------------- xs/xsp/Geometry.xsp | 37 ---------------- xs/xsp/Layer.xsp | 2 - xs/xsp/Line.xsp | 14 ------ xs/xsp/Model.xsp | 14 +----- xs/xsp/Polygon.xsp | 4 -- xs/xsp/SurfaceCollection.xsp | 14 ------ xs/xsp/TriangleMesh.xsp | 1 - xs/xsp/my.map | 28 ------------ xs/xsp/typemap.xspt | 19 -------- 24 files changed, 3 insertions(+), 380 deletions(-) delete mode 100644 lib/Slic3r/Flow.pm delete mode 100644 xs/xsp/ExtrusionMultiPath.xsp delete mode 100644 xs/xsp/Flow.xsp diff --git a/lib/Slic3r.pm b/lib/Slic3r.pm index cd8f151f8f..1e94e0f482 100644 --- a/lib/Slic3r.pm +++ b/lib/Slic3r.pm @@ -35,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; diff --git a/lib/Slic3r/Config.pm b/lib/Slic3r/Config.pm index aeaca998fd..dadf76a0ab 100644 --- a/lib/Slic3r/Config.pm +++ b/lib/Slic3r/Config.pm @@ -28,8 +28,5 @@ 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/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 b3c57fcd08..2e4f5a0972 100644 --- a/lib/Slic3r/Geometry.pm +++ b/lib/Slic3r/Geometry.pm @@ -12,7 +12,6 @@ our @EXPORT_OK = qw( scale unscale scaled_epsilon - size_2D X Y Z convex_hull @@ -52,13 +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]), - ); -} - 1; diff --git a/lib/Slic3r/Print/Object.pm b/lib/Slic3r/Print/Object.pm index 35da7afe7d..b4e53245ae 100644 --- a/lib/Slic3r/Print/Object.pm +++ b/lib/Slic3r/Print/Object.pm @@ -4,7 +4,6 @@ use strict; use warnings; use List::Util qw(min max sum first); -use Slic3r::Flow ':roles'; use Slic3r::Surface ':types'; sub layers { diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index be2e2dbef6..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: @@ -464,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, @@ -528,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, @@ -619,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, @@ -705,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), @@ -784,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/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/xs/CMakeLists.txt b/xs/CMakeLists.txt index 8551aaff14..1a58aab122 100644 --- a/xs/CMakeLists.txt +++ b/xs/CMakeLists.txt @@ -48,9 +48,7 @@ set(XS_XSP_FILES ${XSP_DIR}/ExPolygon.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 diff --git a/xs/lib/Slic3r/XS.pm b/xs/lib/Slic3r/XS.pm index 5578a70abc..1675ac1935 100644 --- a/xs/lib/Slic3r/XS.pm +++ b/xs/lib/Slic3r/XS.pm @@ -74,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 }, @@ -108,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 { @@ -175,26 +151,18 @@ sub new { package main; for my $class (qw( Slic3r::Config - Slic3r::Config::Full Slic3r::Config::GCode Slic3r::Config::Print - Slic3r::Config::PrintObject - Slic3r::Config::PrintRegion Slic3r::Config::Static Slic3r::ExPolygon Slic3r::ExtrusionLoop - Slic3r::ExtrusionMultiPath Slic3r::ExtrusionPath Slic3r::ExtrusionPath::Collection - Slic3r::Flow Slic3r::GCode Slic3r::Geometry::BoundingBox - Slic3r::Geometry::BoundingBoxf - Slic3r::Geometry::BoundingBoxf3 Slic3r::Layer Slic3r::Layer::Region Slic3r::Line - Slic3r::Linef3 Slic3r::Model Slic3r::Model::Instance Slic3r::Model::Material diff --git a/xs/src/perlglue.cpp b/xs/src/perlglue.cpp index e513ec4627..4e293a2f9f 100644 --- a/xs/src/perlglue.cpp +++ b/xs/src/perlglue.cpp @@ -4,17 +4,14 @@ namespace Slic3r { REGISTER_CLASS(ExPolygon, "ExPolygon"); -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(LayerRegion, "Layer::Region"); REGISTER_CLASS(Line, "Line"); -REGISTER_CLASS(Linef3, "Linef3"); REGISTER_CLASS(Polygon, "Polygon"); REGISTER_CLASS(Polyline, "Polyline"); REGISTER_CLASS(Print, "Print"); @@ -26,20 +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(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(FullPrintConfig, "Config::Full"); REGISTER_CLASS(TriangleMesh, "TriangleMesh"); SV* ConfigBase__as_hash(ConfigBase* THIS) 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/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/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/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 23daa4510f..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 @@ -72,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 da35734ffd..e42486985d 100644 --- a/xs/xsp/Layer.xsp +++ b/xs/xsp/Layer.xsp @@ -23,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); %}; 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/Polygon.xsp b/xs/xsp/Polygon.xsp index bc4d412d95..873c4bcc93 100644 --- a/xs/xsp/Polygon.xsp +++ b/xs/xsp/Polygon.xsp @@ -34,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/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 91b3b40a1d..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(); diff --git a/xs/xsp/my.map b/xs/xsp/my.map index fce0c47ad8..5174bdfa95 100644 --- a/xs/xsp/my.map +++ b/xs/xsp/my.map @@ -18,14 +18,6 @@ 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 @@ -33,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 @@ -72,10 +58,6 @@ 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 @@ -92,10 +74,6 @@ 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 @@ -104,10 +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 - Surface* O_OBJECT_SLIC3R Ref O_OBJECT_SLIC3R_T Clone O_OBJECT_SLIC3R_T @@ -164,8 +138,6 @@ ExtrusionLoopRole T_UV ExtrusionRole T_UV FlowRole T_UV SurfaceType T_UV -Slic3r::ClipperLib::JoinType T_UV -Slic3r::ClipperLib::PolyFillType T_UV # we return these types whenever we want the items to be cloned Points T_ARRAYREF diff --git a/xs/xsp/typemap.xspt b/xs/xsp/typemap.xspt index d4801fc393..243e80dbcd 100644 --- a/xs/xsp/typemap.xspt +++ b/xs/xsp/typemap.xspt @@ -30,21 +30,11 @@ %typemap{BoundingBox*}; %typemap{Ref}{simple}; %typemap{Clone}{simple}; -%typemap{BoundingBoxf*}; -%typemap{Ref}{simple}; -%typemap{Clone}{simple}; -%typemap{BoundingBoxf3*}; -%typemap{Ref}{simple}; -%typemap{Clone}{simple}; %typemap{DynamicPrintConfig*}; %typemap{Ref}{simple}; %typemap{Clone}{simple}; %typemap{StaticPrintConfig*}; %typemap{Ref}{simple}; -%typemap{PrintObjectConfig*}; -%typemap{Ref}{simple}; -%typemap{PrintRegionConfig*}; -%typemap{Ref}{simple}; %typemap{GCodeConfig*}; %typemap{Ref}{simple}; %typemap{PrintConfig*}; @@ -54,15 +44,9 @@ %typemap{ExPolygon*}; %typemap{Ref}{simple}; %typemap{Clone}{simple}; -%typemap{Flow*}; -%typemap{Ref}{simple}; -%typemap{Clone}{simple}; %typemap{Line*}; %typemap{Ref}{simple}; %typemap{Clone}{simple}; -%typemap{Linef3*}; -%typemap{Ref}{simple}; -%typemap{Clone}{simple}; %typemap{Polyline*}; %typemap{Ref}{simple}; %typemap{Clone}{simple}; @@ -72,9 +56,6 @@ %typemap{ExtrusionEntityCollection*}; %typemap{Ref}{simple}; %typemap{Clone}{simple}; -%typemap{ExtrusionMultiPath*}; -%typemap{Ref}{simple}; -%typemap{Clone}{simple}; %typemap{ExtrusionPath*}; %typemap{Ref}{simple}; %typemap{Clone}{simple};