From 0c4e16589bee9878caf4cdfa8eac4e039dee02cc Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Mon, 20 Mar 2017 18:51:15 +0100 Subject: [PATCH 01/17] Prevent ExtUtils::CppGuess from linking to libstdc++ on OS X --- xs/Build.PL | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/xs/Build.PL b/xs/Build.PL index 87ba0c1ef6..619cc879fa 100644 --- a/xs/Build.PL +++ b/xs/Build.PL @@ -39,6 +39,19 @@ if ($^O eq 'darwin') { # that prevents this from happening, not needed with newer Boost versions. # See here for more details: https://svn.boost.org/trac/boost/ticket/7671 push @cflags, qw(-DBOOST_THREAD_DONT_USE_CHRONO -DBOOST_NO_CXX11_RVALUE_REFERENCES -DBOOST_THREAD_USES_MOVE); + + # ExtUtils::CppGuess has a hard-coded -lstdc++, so we filter it out + { + no strict 'refs'; + no warnings 'redefine'; + my $func = "ExtUtils::CppGuess::_get_lflags"; + my $orig = *$func{CODE}; + *{$func} = sub { + my $lflags = $orig->(@_); + $lflags =~ s/\s*-lstdc\+\+//; + return $lflags; + }; + } } if ($mswin) { # In case windows.h is included, we don't want the min / max macros to be active. From a69e4e39c9fa2ab62ea0dbe80f66c8d847b83b67 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Mon, 20 Mar 2017 19:28:08 +0100 Subject: [PATCH 02/17] Bugfix (untested): prevent cursor to go to the beginning while typing in a slider textctrl. #3779 --- lib/Slic3r/GUI/OptionsGroup/Field.pm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/Slic3r/GUI/OptionsGroup/Field.pm b/lib/Slic3r/GUI/OptionsGroup/Field.pm index d2cf76ce69..2bf3701d91 100644 --- a/lib/Slic3r/GUI/OptionsGroup/Field.pm +++ b/lib/Slic3r/GUI/OptionsGroup/Field.pm @@ -573,7 +573,8 @@ sub get_value { sub _update_textctrl { my ($self) = @_; - $self->textctrl->SetLabel($self->get_value); + $self->textctrl->ChangeValue($self->get_value); + $self->textctrl->SetInsertionPointEnd; } sub enable { From 9ad1360e445cd3043c4dc30ccad64b82b914f952 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Mon, 20 Mar 2017 22:22:38 +0100 Subject: [PATCH 03/17] Bugfix: when the Voronoi diagram contained very large coordinates we need to check whether they are greater than our allowed range and consider the Voronoi edges infinite in those cases, in order to prevent overflows. #3776 --- xs/src/libslic3r/ClipperUtils.hpp | 3 ++- xs/src/libslic3r/ExPolygon.cpp | 8 ++++++++ xs/src/libslic3r/ExPolygon.hpp | 3 +++ xs/src/libslic3r/Geometry.cpp | 10 +++++++++- 4 files changed, 22 insertions(+), 2 deletions(-) diff --git a/xs/src/libslic3r/ClipperUtils.hpp b/xs/src/libslic3r/ClipperUtils.hpp index 9e4e5e89ae..f766612156 100644 --- a/xs/src/libslic3r/ClipperUtils.hpp +++ b/xs/src/libslic3r/ClipperUtils.hpp @@ -19,7 +19,8 @@ namespace Slic3r { // How about 2^17=131072? // By the way, is the scalling needed at all? Cura runs all the computation with a fixed point precision of 1um, while Slic3r scales to 1nm, // further scaling by 10e5 brings us to -#define CLIPPER_OFFSET_SCALE 100000.0 +static const float CLIPPER_OFFSET_SCALE = 100000.0; +static const coord_t MAX_COORD = ClipperLib::hiRange / CLIPPER_OFFSET_SCALE; //----------------------------------------------------------- // legacy code from Clipper documentation diff --git a/xs/src/libslic3r/ExPolygon.cpp b/xs/src/libslic3r/ExPolygon.cpp index ec02acc356..93fbba4676 100644 --- a/xs/src/libslic3r/ExPolygon.cpp +++ b/xs/src/libslic3r/ExPolygon.cpp @@ -514,4 +514,12 @@ ExPolygon::dump_perl() const return ret.str(); } +std::ostream& +operator <<(std::ostream &s, const ExPolygons &expolygons) +{ + for (const ExPolygon &e : expolygons) + s << e.dump_perl() << std::endl; + return s; +} + } diff --git a/xs/src/libslic3r/ExPolygon.hpp b/xs/src/libslic3r/ExPolygon.hpp index 63cc560cd9..404a4385e3 100644 --- a/xs/src/libslic3r/ExPolygon.hpp +++ b/xs/src/libslic3r/ExPolygon.hpp @@ -4,6 +4,7 @@ #include "libslic3r.h" #include "Polygon.hpp" #include "Polyline.hpp" +#include #include namespace Slic3r { @@ -62,6 +63,8 @@ operator+(ExPolygons src1, const ExPolygons &src2) { return src1; }; +std::ostream& operator <<(std::ostream &s, const ExPolygons &expolygons); + } // start Boost diff --git a/xs/src/libslic3r/Geometry.cpp b/xs/src/libslic3r/Geometry.cpp index 0cc9a575c3..ccd645e2fa 100644 --- a/xs/src/libslic3r/Geometry.cpp +++ b/xs/src/libslic3r/Geometry.cpp @@ -7,13 +7,14 @@ #include #include #include +#include #include #include #include #include #include #include - +#define SLIC3R_DEBUG #ifdef SLIC3R_DEBUG #include "SVG.hpp" #endif @@ -609,6 +610,13 @@ MedialAxis::process_edge_neighbors(const VD::edge_type* edge, ThickPolyline* pol bool MedialAxis::validate_edge(const VD::edge_type* edge) { + // prevent overflows and detect almost-infinite edges + if (std::abs(edge->vertex0()->x()) > (double)MAX_COORD + || std::abs(edge->vertex0()->y()) > (double)MAX_COORD + || std::abs(edge->vertex1()->x()) > (double)MAX_COORD + || std::abs(edge->vertex1()->y()) > (double)MAX_COORD) + return false; + // construct the line representing this edge of the Voronoi diagram const Line line( Point( edge->vertex0()->x(), edge->vertex0()->y() ), From a301e6afa4154900a55f70f147639905d16394c2 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Mon, 20 Mar 2017 22:37:42 +0100 Subject: [PATCH 04/17] Removed two extra lines left in previous commit --- xs/src/libslic3r/Geometry.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/xs/src/libslic3r/Geometry.cpp b/xs/src/libslic3r/Geometry.cpp index ccd645e2fa..b8584000fa 100644 --- a/xs/src/libslic3r/Geometry.cpp +++ b/xs/src/libslic3r/Geometry.cpp @@ -7,14 +7,13 @@ #include #include #include -#include #include #include #include #include #include #include -#define SLIC3R_DEBUG + #ifdef SLIC3R_DEBUG #include "SVG.hpp" #endif From 61c8359995e785a638d2f39390c2998a889b4a93 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Mon, 20 Mar 2017 23:02:47 +0100 Subject: [PATCH 05/17] Ignore solid_infill_below_area when fill_density is already 100%. #3380 --- xs/src/libslic3r/LayerRegion.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/xs/src/libslic3r/LayerRegion.cpp b/xs/src/libslic3r/LayerRegion.cpp index b7d9058fe6..1baaa0bef5 100644 --- a/xs/src/libslic3r/LayerRegion.cpp +++ b/xs/src/libslic3r/LayerRegion.cpp @@ -231,12 +231,13 @@ LayerRegion::prepare_fill_surfaces() } // turn too small internal regions into solid regions according to the user setting - if (this->region()->config.fill_density.value > 0) { + const float &fill_density = this->region()->config.fill_density; + if (fill_density > 0 && fill_density < 100) { // scaling an area requires two calls! - double min_area = scale_(scale_(this->region()->config.solid_infill_below_area.value)); - for (Surfaces::iterator surface = this->fill_surfaces.surfaces.begin(); surface != this->fill_surfaces.surfaces.end(); ++surface) { - if (surface->surface_type == stInternal && surface->area() <= min_area) - surface->surface_type = stInternalSolid; + const double min_area = scale_(scale_(this->region()->config.solid_infill_below_area.value)); + for (Surface &surface : this->fill_surfaces.surfaces) { + if (surface.surface_type == stInternal && surface.area() <= min_area) + surface.surface_type = stInternalSolid; } } } From ecc171eca6971922441bf0d713ee400582373e47 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Tue, 21 Mar 2017 14:40:32 +0100 Subject: [PATCH 06/17] Bugfix: use_relative_e_distances and spiral vase were broken again after the port. #3784 --- xs/src/libslic3r/GCodeReader.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/xs/src/libslic3r/GCodeReader.cpp b/xs/src/libslic3r/GCodeReader.cpp index fcaaea9be8..1a0742864f 100644 --- a/xs/src/libslic3r/GCodeReader.cpp +++ b/xs/src/libslic3r/GCodeReader.cpp @@ -56,6 +56,9 @@ GCodeReader::parse(const std::string &gcode, callback_t callback) } } + if (gline.has('E') && this->_config.use_relative_e_distances) + this->E = 0; + if (callback) callback(*this, gline); // update coordinates From 8250839fd5200bad9b180c056055acf515b0ad6f Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Tue, 21 Mar 2017 16:40:31 +0100 Subject: [PATCH 07/17] constexpr party --- xs/src/clipper.hpp | 2 +- xs/src/libslic3r/ClipperUtils.hpp | 4 +- xs/src/libslic3r/Flow.hpp | 4 +- xs/src/libslic3r/GCode.cpp | 4 +- xs/src/libslic3r/GCodeSender.cpp | 4 +- xs/src/libslic3r/MotionPlanner.hpp | 6 +-- xs/src/libslic3r/SupportMaterial.hpp | 2 +- xs/src/libslic3r/libslic3r.h | 56 ++++++++++++++-------------- 8 files changed, 42 insertions(+), 40 deletions(-) diff --git a/xs/src/clipper.hpp b/xs/src/clipper.hpp index df1f8137d4..66876905c2 100755 --- a/xs/src/clipper.hpp +++ b/xs/src/clipper.hpp @@ -76,7 +76,7 @@ enum PolyFillType { pftEvenOdd, pftNonZero, pftPositive, pftNegative }; #else typedef signed long long cInt; static cInt const loRange = 0x3FFFFFFF; - static cInt const hiRange = 0x3FFFFFFFFFFFFFFFLL; + constexpr cInt hiRange = 0x3FFFFFFFFFFFFFFFLL; typedef signed long long long64; //used by Int128 class typedef unsigned long long ulong64; diff --git a/xs/src/libslic3r/ClipperUtils.hpp b/xs/src/libslic3r/ClipperUtils.hpp index f766612156..ddd551ca26 100644 --- a/xs/src/libslic3r/ClipperUtils.hpp +++ b/xs/src/libslic3r/ClipperUtils.hpp @@ -19,8 +19,8 @@ namespace Slic3r { // How about 2^17=131072? // By the way, is the scalling needed at all? Cura runs all the computation with a fixed point precision of 1um, while Slic3r scales to 1nm, // further scaling by 10e5 brings us to -static const float CLIPPER_OFFSET_SCALE = 100000.0; -static const coord_t MAX_COORD = ClipperLib::hiRange / CLIPPER_OFFSET_SCALE; +constexpr float CLIPPER_OFFSET_SCALE = 100000.0; +constexpr auto MAX_COORD = ClipperLib::hiRange / CLIPPER_OFFSET_SCALE; //----------------------------------------------------------- // legacy code from Clipper documentation diff --git a/xs/src/libslic3r/Flow.hpp b/xs/src/libslic3r/Flow.hpp index 2f041d03cd..fdfcac6950 100644 --- a/xs/src/libslic3r/Flow.hpp +++ b/xs/src/libslic3r/Flow.hpp @@ -7,8 +7,8 @@ namespace Slic3r { -#define BRIDGE_EXTRA_SPACING 0.05 -#define OVERLAP_FACTOR 1.0 +constexpr auto BRIDGE_EXTRA_SPACING = 0.05; +constexpr auto OVERLAP_FACTOR = 1.0; enum FlowRole { frExternalPerimeter, diff --git a/xs/src/libslic3r/GCode.cpp b/xs/src/libslic3r/GCode.cpp index 39af871b27..f6ae8f75a4 100644 --- a/xs/src/libslic3r/GCode.cpp +++ b/xs/src/libslic3r/GCode.cpp @@ -453,8 +453,8 @@ GCode::extrude(ExtrusionLoop loop, std::string description, double speed) paths.front().polyline.points[0], paths.front().polyline.points[1] ); - double distance = std::min( - scale_(EXTRUDER_CONFIG(nozzle_diameter)), + const double distance = std::min( + (double)scale_(EXTRUDER_CONFIG(nozzle_diameter)), first_segment.length() ); Point point = first_segment.point_at(distance); diff --git a/xs/src/libslic3r/GCodeSender.cpp b/xs/src/libslic3r/GCodeSender.cpp index 5fc33d9c90..c1568790ec 100644 --- a/xs/src/libslic3r/GCodeSender.cpp +++ b/xs/src/libslic3r/GCodeSender.cpp @@ -26,10 +26,10 @@ std::fstream fs; #endif -#define KEEP_SENT 20 - namespace Slic3r { +constexpr auto KEEP_SENT = 20; + namespace asio = boost::asio; GCodeSender::GCodeSender() diff --git a/xs/src/libslic3r/MotionPlanner.hpp b/xs/src/libslic3r/MotionPlanner.hpp index 1fbdb4123f..80d61213ec 100644 --- a/xs/src/libslic3r/MotionPlanner.hpp +++ b/xs/src/libslic3r/MotionPlanner.hpp @@ -9,11 +9,11 @@ #include #include -#define MP_INNER_MARGIN scale_(1.0) -#define MP_OUTER_MARGIN scale_(2.0) - namespace Slic3r { +constexpr coord_t MP_INNER_MARGIN = scale_(1.0); +constexpr coord_t MP_OUTER_MARGIN = scale_(2.0); + class MotionPlanner; class MotionPlannerEnv diff --git a/xs/src/libslic3r/SupportMaterial.hpp b/xs/src/libslic3r/SupportMaterial.hpp index edea226959..03703aa40f 100644 --- a/xs/src/libslic3r/SupportMaterial.hpp +++ b/xs/src/libslic3r/SupportMaterial.hpp @@ -4,7 +4,7 @@ namespace Slic3r { // how much we extend support around the actual contact area -#define SUPPORT_MATERIAL_MARGIN 1.5 +constexpr coordf_t SUPPORT_MATERIAL_MARGIN = 1.5; } diff --git a/xs/src/libslic3r/libslic3r.h b/xs/src/libslic3r/libslic3r.h index 6789d58ffc..50b4241de3 100644 --- a/xs/src/libslic3r/libslic3r.h +++ b/xs/src/libslic3r/libslic3r.h @@ -10,33 +10,6 @@ #include #include -#define SLIC3R_VERSION "1.3.0-dev" - -//FIXME This epsilon value is used for many non-related purposes: -// For a threshold of a squared Euclidean distance, -// for a trheshold in a difference of radians, -// for a threshold of a cross product of two non-normalized vectors etc. -#define EPSILON 1e-4 -// Scaling factor for a conversion from coord_t to coordf_t: 10e-6 -// This scaling generates a following fixed point representation with for a 32bit integer: -// 0..4294mm with 1nm resolution -#define SCALING_FACTOR 0.000001 -// RESOLUTION, SCALED_RESOLUTION: Used as an error threshold for a Douglas-Peucker polyline simplification algorithm. -#define RESOLUTION 0.0125 -#define SCALED_RESOLUTION (RESOLUTION / SCALING_FACTOR) -#define PI 3.141592653589793238 -// When extruding a closed loop, the loop is interrupted and shortened a bit to reduce the seam. -#define LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER 0.15 -// Maximum perimeter length for the loop to apply the small perimeter speed. -#define SMALL_PERIMETER_LENGTH (6.5 / SCALING_FACTOR) * 2 * PI -#define INSET_OVERLAP_TOLERANCE 0.4 -#define EXTERNAL_INFILL_MARGIN 3 -#define scale_(val) ((val) / SCALING_FACTOR) -#define unscale(val) ((val) * SCALING_FACTOR) -#define SCALED_EPSILON scale_(EPSILON) -typedef long coord_t; -typedef double coordf_t; - /* Implementation of CONFESS("foo"): */ #ifdef _MSC_VER #define CONFESS(...) confess_at(__FILE__, __LINE__, __FUNCTION__, __VA_ARGS__) @@ -61,6 +34,35 @@ void confess_at(const char *file, int line, const char *func, const char *pat, . namespace Slic3r { +constexpr auto SLIC3R_VERSION = "1.3.0-dev"; + +typedef long coord_t; +typedef double coordf_t; + +// Scaling factor for a conversion from coord_t to coordf_t: 10e-6 +// This scaling generates a following fixed point representation with for a 32bit integer: +// 0..4294mm with 1nm resolution +constexpr auto SCALING_FACTOR = 0.000001; +inline constexpr coord_t scale_(const coordf_t &val) { return val / SCALING_FACTOR; } +inline constexpr coordf_t unscale(const coord_t &val) { return val * SCALING_FACTOR; } + +//FIXME This epsilon value is used for many non-related purposes: +// For a threshold of a squared Euclidean distance, +// for a trheshold in a difference of radians, +// for a threshold of a cross product of two non-normalized vectors etc. +constexpr auto EPSILON = 1e-4; +constexpr auto SCALED_EPSILON = scale_(EPSILON); +// RESOLUTION, SCALED_RESOLUTION: Used as an error threshold for a Douglas-Peucker polyline simplification algorithm. +constexpr auto RESOLUTION = 0.0125; +constexpr auto SCALED_RESOLUTION = scale_(RESOLUTION); +constexpr auto PI = 3.141592653589793238; +// When extruding a closed loop, the loop is interrupted and shortened a bit to reduce the seam. +constexpr auto LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER = 0.15; +// Maximum perimeter length for the loop to apply the small perimeter speed. +constexpr coord_t SMALL_PERIMETER_LENGTH = scale_(6.5) * 2 * PI; +constexpr coordf_t INSET_OVERLAP_TOLERANCE = 0.4; +constexpr coordf_t EXTERNAL_INFILL_MARGIN = 3; + enum Axis { X=0, Y, Z }; template From ddad7ce25f59b34552ff2b119597366655be3754 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Tue, 21 Mar 2017 16:48:04 +0100 Subject: [PATCH 08/17] One more fix for slider. #3779 --- lib/Slic3r/GUI/OptionsGroup/Field.pm | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/Slic3r/GUI/OptionsGroup/Field.pm b/lib/Slic3r/GUI/OptionsGroup/Field.pm index 2bf3701d91..920d4cec11 100644 --- a/lib/Slic3r/GUI/OptionsGroup/Field.pm +++ b/lib/Slic3r/GUI/OptionsGroup/Field.pm @@ -548,11 +548,16 @@ sub BUILD { EVT_TEXT($self->parent, $textctrl, sub { my $value = $textctrl->GetValue; if ($value =~ /^-?\d+(\.\d*)?$/) { - $self->set_value($value); + # Update the slider without re-updating the text field being modified. + $self->disable_change_event(1); + $self->slider->SetValue($value*$self->scale); + $self->disable_change_event(0); + $self->_on_change($self->option->opt_id); } }); EVT_KILL_FOCUS($textctrl, sub { + $self->_update_textctrl; $self->_on_kill_focus($self->option->opt_id, @_); }); } @@ -573,6 +578,7 @@ sub get_value { sub _update_textctrl { my ($self) = @_; + $self->textctrl->ChangeValue($self->get_value); $self->textctrl->SetInsertionPointEnd; } From 856065537208bdb8a85a148c0946f58cbce3e49b Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Tue, 21 Mar 2017 17:33:49 +0100 Subject: [PATCH 09/17] Only reload the selected object and not all the objects of the input file. #3786 --- lib/Slic3r/GUI/Plater.pm | 29 +++++++++++++++++++++++------ xs/src/libslic3r/Model.cpp | 14 ++++++-------- 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm index fe00e0260c..b7393c0af7 100644 --- a/lib/Slic3r/GUI/Plater.pm +++ b/lib/Slic3r/GUI/Plater.pm @@ -632,7 +632,7 @@ sub add_tin { sub load_file { my $self = shift; - my ($input_file) = @_; + my ($input_file, $obj_idx) = @_; $Slic3r::GUI::Settings->{recent}{skein_directory} = dirname($input_file); wxTheApp->save_settings; @@ -657,7 +657,19 @@ sub load_file { $model->convert_multipart_object; } } - @obj_idx = $self->load_model_objects(@{$model->objects}); + + if (defined $obj_idx) { + return () if $obj_idx >= $model->objects_count; + @obj_idx = $self->load_model_objects($model->get_object($obj_idx)); + } else { + @obj_idx = $self->load_model_objects(@{$model->objects}); + } + + my $i = 0; + foreach my $obj_idx (@obj_idx) { + $self->{objects}[$obj_idx]->input_file($input_file); + $self->{objects}[$obj_idx]->input_file_obj_idx($i++); + } $self->statusbar->SetStatusText("Loaded " . basename($input_file)); } @@ -1488,13 +1500,14 @@ sub reload_from_disk { my ($obj_idx, $object) = $self->selected_object; return if !defined $obj_idx; - my $model_object = $self->{model}->objects->[$obj_idx]; - return if !$model_object->input_file - || !-e $model_object->input_file; + return if !$object->input_file + || !-e $object->input_file; - my @new_obj_idx = $self->load_file($model_object->input_file); + # Only reload the selected object and not all objects from the input file. + my @new_obj_idx = $self->load_file($object->input_file, $object->input_file_obj_idx); return if !@new_obj_idx; + my $model_object = $self->{model}->objects->[$obj_idx]; foreach my $new_obj_idx (@new_obj_idx) { my $o = $self->{model}->objects->[$new_obj_idx]; $o->clear_instances; @@ -1509,6 +1522,8 @@ sub reload_from_disk { $self->remove($obj_idx); + # TODO: refresh object list which contains wrong count and scale + # Trigger thumbnail generation again, because the remove() method altered # object indexes before background thumbnail generation called its completion # event, so the on_thumbnail_made callback is called with the wrong $obj_idx. @@ -2127,6 +2142,8 @@ use List::Util qw(first); use Slic3r::Geometry qw(X Y Z MIN MAX deg2rad); has 'name' => (is => 'rw', required => 1); +has 'input_file' => (is => 'rw'); +has 'input_file_obj_idx' => (is => 'rw'); has 'thumbnail' => (is => 'rw'); # ExPolygon::Collection in scaled model units with no transforms has 'transformed_thumbnail' => (is => 'rw'); has 'instance_thumbnails' => (is => 'ro', default => sub { [] }); # array of ExPolygon::Collection objects, each one representing the actual placed thumbnail of each instance in pixel units diff --git a/xs/src/libslic3r/Model.cpp b/xs/src/libslic3r/Model.cpp index ca9c0b2274..9182cf56b9 100644 --- a/xs/src/libslic3r/Model.cpp +++ b/xs/src/libslic3r/Model.cpp @@ -92,9 +92,8 @@ Model::delete_object(size_t idx) void Model::clear_objects() { - // int instead of size_t because it can be -1 when vector is empty - for (int i = this->objects.size()-1; i >= 0; --i) - this->delete_object(i); + while (!this->objects.empty()) + this->delete_object(0); } void @@ -467,9 +466,8 @@ ModelObject::delete_volume(size_t idx) void ModelObject::clear_volumes() { - // int instead of size_t because it can be -1 when vector is empty - for (int i = this->volumes.size()-1; i >= 0; --i) - this->delete_volume(i); + while (!this->volumes.empty()) + this->delete_volume(0); } ModelInstance* @@ -508,8 +506,8 @@ ModelObject::delete_last_instance() void ModelObject::clear_instances() { - for (size_t i = 0; i < this->instances.size(); ++i) - this->delete_instance(i); + while (!this->instances.empty()) + this->delete_last_instance(); } // this returns the bounding box of the *transformed* instances From 4c14c656f5c9adf712dfbcea0dc1b7c044131c37 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Tue, 21 Mar 2017 17:38:39 +0100 Subject: [PATCH 10/17] Updated MANIFEST --- xs/MANIFEST | 2 ++ 1 file changed, 2 insertions(+) diff --git a/xs/MANIFEST b/xs/MANIFEST index a2ffbba5a7..61a97afede 100644 --- a/xs/MANIFEST +++ b/xs/MANIFEST @@ -68,6 +68,8 @@ src/libslic3r/GCode/CoolingBuffer.cpp src/libslic3r/GCode/CoolingBuffer.hpp src/libslic3r/GCode/SpiralVase.cpp src/libslic3r/GCode/SpiralVase.hpp +src/libslic3r/GCodeReader.cpp +src/libslic3r/GCodeReader.hpp src/libslic3r/GCodeSender.cpp src/libslic3r/GCodeSender.hpp src/libslic3r/GCodeWriter.cpp From 488cc02f531d63e8d87a3a572853a391ae8a7647 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Thu, 23 Mar 2017 12:49:25 +0100 Subject: [PATCH 11/17] Try to fix OctoPrint issues. #3789 --- lib/Slic3r/GUI/Plater.pm | 87 +++++++++++++++++++++++----------------- 1 file changed, 50 insertions(+), 37 deletions(-) diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm index b7393c0af7..d7bb3195df 100644 --- a/lib/Slic3r/GUI/Plater.pm +++ b/lib/Slic3r/GUI/Plater.pm @@ -256,43 +256,10 @@ sub new { EVT_LEFT_UP($self->{btn_send_gcode}, sub { my (undef, $e) = @_; - my $filename = basename($self->{print}->output_filepath($main::opt{output} // '')); - - if (!$e->AltDown) { - # When the alt key is pressed, bypass the dialog. - my $dlg = Slic3r::GUI::Plater::OctoPrintSpoolDialog->new($self, $filename); - return unless $dlg->ShowModal == wxID_OK; - $filename = $dlg->{filename}; - } - - if (!$Slic3r::GUI::Settings->{octoprint}{overwrite}) { - my $progress = Wx::ProgressDialog->new('Querying OctoPrint…', - "Checking whether file already exists…", 100, $self, 0); - $progress->Pulse; - - my $ua = LWP::UserAgent->new; - $ua->timeout(5); - my $res = $ua->get("http://" . $self->{config}->octoprint_host . "/api/files/local"); - $progress->Destroy; - if ($res->is_success) { - if ($res->decoded_content =~ /"name":\s*"\Q$filename\E"/) { - my $dialog = Wx::MessageDialog->new($self, - "It looks like a file with the same name already exists in the server. " - . "Shall I overwrite it?", - 'OctoPrint', wxICON_WARNING | wxYES | wxNO); - if ($dialog->ShowModal() == wxID_NO) { - return; - } - } - } else { - my $message = "Error while connecting to the OctoPrint server: " . $res->status_line; - Slic3r::GUI::show_error($self, $message); - return; - } - } - - $self->{send_gcode_file_print} = $Slic3r::GUI::Settings->{octoprint}{start}; - $self->{send_gcode_file} = $self->export_gcode(Wx::StandardPaths::Get->GetTempDir() . "/" . $filename); + my $alt = $e->AltDown; + wxTheApp->CallAfter(sub { + $self->prepare_send($alt); + }); }); EVT_BUTTON($self, $self->{btn_export_stl}, \&export_stl); @@ -1452,6 +1419,52 @@ sub do_print { $self->GetFrame->select_tab(1); } +sub prepare_send { + my ($self, $skip_dialog) = @_; + + return if !$self->{btn_send_gcode}->IsEnabled; + my $filename = basename($self->{print}->output_filepath($main::opt{output} // '')); + + if (!$skip_dialog) { + # When the alt key is pressed, bypass the dialog. + my $dlg = Slic3r::GUI::Plater::OctoPrintSpoolDialog->new($self, $filename); + return unless $dlg->ShowModal == wxID_OK; + $filename = $dlg->{filename}; + } + + if (!$Slic3r::GUI::Settings->{octoprint}{overwrite}) { + my $progress = Wx::ProgressDialog->new('Querying OctoPrint…', + "Checking whether file already exists…", 100, $self, 0); + $progress->Pulse; + + my $ua = LWP::UserAgent->new; + $ua->timeout(5); + my $res = $ua->get( + "http://" . $self->{config}->octoprint_host . "/api/files/local", + 'X-Api-Key' => $self->{config}->octoprint_apikey, + ); + $progress->Destroy; + if ($res->is_success) { + if ($res->decoded_content =~ /"name":\s*"\Q$filename\E"/) { + my $dialog = Wx::MessageDialog->new($self, + "It looks like a file with the same name already exists in the server. " + . "Shall I overwrite it?", + 'OctoPrint', wxICON_WARNING | wxYES | wxNO); + if ($dialog->ShowModal() == wxID_NO) { + return; + } + } + } else { + my $message = "Error while connecting to the OctoPrint server: " . $res->status_line; + Slic3r::GUI::show_error($self, $message); + return; + } + } + + $self->{send_gcode_file_print} = $Slic3r::GUI::Settings->{octoprint}{start}; + $self->{send_gcode_file} = $self->export_gcode(Wx::StandardPaths::Get->GetTempDir() . "/" . $filename); +} + sub send_gcode { my ($self) = @_; From 0de3a72eb40a408d64ecfb5fa7ca461718fc4ba8 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Thu, 23 Mar 2017 12:59:05 +0100 Subject: [PATCH 12/17] Bugfix: canceling the "Set Copies" dialog didn't work. #3787 --- lib/Slic3r/GUI/Plater.pm | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm index d7bb3195df..30745ab806 100644 --- a/lib/Slic3r/GUI/Plater.pm +++ b/lib/Slic3r/GUI/Plater.pm @@ -840,6 +840,7 @@ sub set_number_of_copies { # prompt user my $copies = Wx::GetNumberFromUser("", "Enter the number of copies of the selected object:", "Copies", $model_object->instances_count, 0, 1000, $self); + return if $copies == -1; my $diff = $copies - $model_object->instances_count; if ($diff == 0) { # no variation From 84a5075fceccddd7a24fda88200a2f2e2f620b98 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Thu, 23 Mar 2017 13:57:18 +0100 Subject: [PATCH 13/17] Bugfix: excessive copies were created when converting a multi-object AMF file into a multi-part object. #3788 --- lib/Slic3r/Model.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Slic3r/Model.pm b/lib/Slic3r/Model.pm index 99c69cd4a3..0b6cefd75c 100644 --- a/lib/Slic3r/Model.pm +++ b/lib/Slic3r/Model.pm @@ -74,7 +74,7 @@ sub convert_multipart_object { my $volume = $object->add_volume($v); $volume->set_name($v->object->name); } - $object->add_instance($_) for map @{$_->instances}, @objects; + $object->add_instance($_) for @{$objects[0]->instances}; $self->delete_object($_) for reverse 0..($self->objects_count-2); } From bd2117d3462965d7c508b646b3d03235024a36f1 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Thu, 23 Mar 2017 14:10:41 +0100 Subject: [PATCH 14/17] Align objects imported from AMF to ground. #3785 --- lib/Slic3r/GUI/Plater.pm | 3 +++ xs/src/libslic3r/Model.cpp | 14 ++++++++++++++ xs/src/libslic3r/Model.hpp | 1 + xs/xsp/Model.xsp | 1 + 4 files changed, 19 insertions(+) diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm index 30745ab806..d43f1cf528 100644 --- a/lib/Slic3r/GUI/Plater.pm +++ b/lib/Slic3r/GUI/Plater.pm @@ -671,6 +671,9 @@ sub load_model_objects { # add a default instance and center object around origin $o->center_around_origin; # also aligns object to Z = 0 $o->add_instance(offset => $bed_centerf); + } else { + # if object has defined positions we still need to ensure it's aligned to Z = 0 + $o->align_to_ground; } { diff --git a/xs/src/libslic3r/Model.cpp b/xs/src/libslic3r/Model.cpp index 9182cf56b9..b1694190e3 100644 --- a/xs/src/libslic3r/Model.cpp +++ b/xs/src/libslic3r/Model.cpp @@ -597,6 +597,20 @@ ModelObject::instance_bounding_box(size_t instance_idx) const return bb; } +void +ModelObject::align_to_ground() +{ + // calculate the displacements needed to + // center this object around the origin + BoundingBoxf3 bb; + for (const ModelVolume* v : this->volumes) + if (!v->modifier) + bb.merge(v->mesh.bounding_box()); + + this->translate(0, 0, -bb.min.z); + this->origin_translation.translate(0, 0, -bb.min.z); +} + void ModelObject::center_around_origin() { diff --git a/xs/src/libslic3r/Model.hpp b/xs/src/libslic3r/Model.hpp index 9c8e0d1e20..1b6c6d6c20 100644 --- a/xs/src/libslic3r/Model.hpp +++ b/xs/src/libslic3r/Model.hpp @@ -149,6 +149,7 @@ class ModelObject TriangleMesh raw_mesh() const; BoundingBoxf3 raw_bounding_box() const; BoundingBoxf3 instance_bounding_box(size_t instance_idx) const; + void align_to_ground(); void center_around_origin(); void translate(const Vectorf3 &vector); void translate(coordf_t x, coordf_t y, coordf_t z); diff --git a/xs/xsp/Model.xsp b/xs/xsp/Model.xsp index c5c7006068..53f6cc8f3c 100644 --- a/xs/xsp/Model.xsp +++ b/xs/xsp/Model.xsp @@ -207,6 +207,7 @@ ModelMaterial::attributes() bool needed_repair() const; int materials_count() const; int facets_count(); + void align_to_ground(); void center_around_origin(); void translate(double x, double y, double z); void scale_xyz(Pointf3* versor) From 3ee628c29f1168f56896555f09a1f29dc9b53ac6 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Thu, 23 Mar 2017 14:23:28 +0100 Subject: [PATCH 15/17] Ported couple Model methods to C++ --- lib/Slic3r/Model.pm | 27 --------------------------- xs/src/libslic3r/Model.cpp | 38 ++++++++++++++++++++++++++++++++++++++ xs/src/libslic3r/Model.hpp | 2 ++ xs/xsp/Model.xsp | 2 ++ 4 files changed, 42 insertions(+), 27 deletions(-) diff --git a/lib/Slic3r/Model.pm b/lib/Slic3r/Model.pm index 0b6cefd75c..cba64323a4 100644 --- a/lib/Slic3r/Model.pm +++ b/lib/Slic3r/Model.pm @@ -52,33 +52,6 @@ sub set_material { return $material; } -sub looks_like_multipart_object { - my ($self) = @_; - - return 0 if $self->objects_count == 1; - return 0 if any { $_->volumes_count > 1 } @{$self->objects}; - return 0 if any { @{$_->config->get_keys} > 1 } @{$self->objects}; - - my %heights = map { $_ => 1 } map $_->mesh->bounding_box->z_min, map @{$_->volumes}, @{$self->objects}; - return scalar(keys %heights) > 1; -} - -sub convert_multipart_object { - my ($self) = @_; - - my @objects = @{$self->objects}; - my $object = $self->add_object( - input_file => $objects[0]->input_file, - ); - foreach my $v (map @{$_->volumes}, @objects) { - my $volume = $object->add_volume($v); - $volume->set_name($v->object->name); - } - $object->add_instance($_) for @{$objects[0]->instances}; - - $self->delete_object($_) for reverse 0..($self->objects_count-2); -} - # Extends C++ class Slic3r::ModelMaterial package Slic3r::Model::Material; diff --git a/xs/src/libslic3r/Model.cpp b/xs/src/libslic3r/Model.cpp index b1694190e3..5243799caa 100644 --- a/xs/src/libslic3r/Model.cpp +++ b/xs/src/libslic3r/Model.cpp @@ -2,6 +2,7 @@ #include "Geometry.hpp" #include "IO.hpp" #include +#include #include #include @@ -372,6 +373,43 @@ Model::print_info() const (*o)->print_info(); } +bool +Model::looks_like_multipart_object() const +{ + if (this->objects.size() == 1) return false; + for (const ModelObject* o : this->objects) { + if (o->volumes.size() > 1) return false; + if (o->config.keys().size() > 1) return false; + } + + std::set heights; + for (const ModelObject* o : this->objects) + for (const ModelVolume* v : o->volumes) + heights.insert(v->mesh.bounding_box().min.z); + return heights.size() > 1; +} + +void +Model::convert_multipart_object() +{ + if (this->objects.empty()) return; + + ModelObject* object = this->add_object(); + object->input_file = this->objects.front()->input_file; + + for (const ModelObject* o : this->objects) { + for (const ModelVolume* v : o->volumes) { + ModelVolume* v2 = object->add_volume(*v); + v2->name = o->name; + } + } + for (const ModelInstance* i : this->objects.front()->instances) + object->add_instance(*i); + + while (this->objects.size() > 1) + this->delete_object(0); +} + ModelMaterial::ModelMaterial(Model *model) : model(model) {} ModelMaterial::ModelMaterial(Model *model, const ModelMaterial &other) : attributes(other.attributes), config(other.config), model(model) diff --git a/xs/src/libslic3r/Model.hpp b/xs/src/libslic3r/Model.hpp index 1b6c6d6c20..36571ff5d7 100644 --- a/xs/src/libslic3r/Model.hpp +++ b/xs/src/libslic3r/Model.hpp @@ -74,6 +74,8 @@ class Model void duplicate_objects(size_t copies_num, coordf_t dist, const BoundingBoxf* bb = NULL); void duplicate_objects_grid(size_t x, size_t y, coordf_t dist); void print_info() const; + bool looks_like_multipart_object() const; + void convert_multipart_object(); }; // Material, which may be shared across multiple ModelObjects of a single Model. diff --git a/xs/xsp/Model.xsp b/xs/xsp/Model.xsp index 53f6cc8f3c..cb415ad140 100644 --- a/xs/xsp/Model.xsp +++ b/xs/xsp/Model.xsp @@ -95,6 +95,8 @@ void duplicate_objects(unsigned int copies_num, double dist, BoundingBoxf* bb = NULL); void duplicate_objects_grid(unsigned int x, unsigned int y, double dist); void print_info(); + bool looks_like_multipart_object(); + void convert_multipart_object(); void repair(); }; From b755e2424f30af3b856593102ecc3d0b7900c0dc Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Thu, 23 Mar 2017 14:26:56 +0100 Subject: [PATCH 16/17] Removed warning --- xs/t/15_config.t | 1 + 1 file changed, 1 insertion(+) diff --git a/xs/t/15_config.t b/xs/t/15_config.t index 214baad9f2..f6efc8a5d7 100644 --- a/xs/t/15_config.t +++ b/xs/t/15_config.t @@ -286,6 +286,7 @@ foreach my $config (Slic3r::Config->new, Slic3r::Config::Static::new_FullPrintCo is_deeply $config->get('retract_speed'), [0.4, 0.5], 'read_cli(): floats array'; } { + no warnings 'qw'; my $config = $parse->(qw(--extruder-offset 0,0 --extruder-offset 10x5)); is_deeply [ map $_->pp, @{$config->get('extruder_offset')} ], [[0,0], [10,5]], 'read_cli(): points array'; From e359cd0a4a2254526b9f3d08ff5773122731dff1 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Thu, 23 Mar 2017 14:46:45 +0100 Subject: [PATCH 17/17] Support Mac Retina displays --- package/osx/plist.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/package/osx/plist.sh b/package/osx/plist.sh index 898ae3be2d..38e03edbcb 100644 --- a/package/osx/plist.sh +++ b/package/osx/plist.sh @@ -91,6 +91,8 @@ cat << EOF >> $plistfile LSMinimumSystemVersion 10.7 + NSPrincipalClass + NSApplication EOF