From 0571d22d5f6faf807857e9cc3ff7a60acfab6c86 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Mon, 12 Feb 2018 15:37:42 +0100 Subject: [PATCH 1/7] Fix of https://github.com/prusa3d/Slic3r/issues/707 This is a crash due to the recommended thin wall thickness hint. --- xs/src/slic3r/GUI/PresetHints.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/xs/src/slic3r/GUI/PresetHints.cpp b/xs/src/slic3r/GUI/PresetHints.cpp index 36f574329..4553ba476 100644 --- a/xs/src/slic3r/GUI/PresetHints.cpp +++ b/xs/src/slic3r/GUI/PresetHints.cpp @@ -238,6 +238,9 @@ std::string PresetHints::recommended_thin_wall_thickness(const PresetBundle &pre bool thin_walls = print_config.opt_bool("thin_walls"); float nozzle_diameter = float(printer_config.opt_float("nozzle_diameter", 0)); + if (layer_height <= 0.f) + return "Recommended object thin wall thickness: Not available due to invalid layer height."; + Flow external_perimeter_flow = Flow::new_from_config_width( frExternalPerimeter, *print_config.opt("external_perimeter_extrusion_width"), From adc9e749c4b6d82314a3693555991db19809fd94 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Mon, 12 Feb 2018 16:34:39 +0100 Subject: [PATCH 2/7] Clipper should always throw clipperExceptions, not strings. --- xs/src/clipper.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/xs/src/clipper.cpp b/xs/src/clipper.cpp index 5c63a6afe..e865288fb 100644 --- a/xs/src/clipper.cpp +++ b/xs/src/clipper.cpp @@ -561,7 +561,7 @@ inline void RangeTest(const IntPoint& Pt, bool& useFullRange) if (useFullRange) { if (Pt.X > hiRange || Pt.Y > hiRange || -Pt.X > hiRange || -Pt.Y > hiRange) - throw "Coordinate outside allowed range"; + throw clipperException("Coordinate outside allowed range"); } else if (Pt.X > loRange|| Pt.Y > loRange || -Pt.X > loRange || -Pt.Y > loRange) { @@ -2386,8 +2386,8 @@ void Clipper::ProcessHorizontal(TEdge *horzEdge) void Clipper::UpdateEdgeIntoAEL(TEdge *&e) { - if( !e->NextInLML ) throw - clipperException("UpdateEdgeIntoAEL: invalid call"); + if( !e->NextInLML ) + throw clipperException("UpdateEdgeIntoAEL: invalid call"); e->NextInLML->OutIdx = e->OutIdx; TEdge* AelPrev = e->PrevInAEL; From 47d904a628ec35a1a0f08ab2ad7bd664cc0c601f Mon Sep 17 00:00:00 2001 From: bubnikv Date: Mon, 12 Feb 2018 18:16:10 +0100 Subject: [PATCH 3/7] Changed the Slic3r coordinate type from long to int32 to match the point type on Windows / Linux / OSX to achieve the same behavior on all the 32 / 64bit systems. (Windows always treats the long as 32bit int, while Linux treats long as a 64bit int). --- xs/src/admesh/util.cpp | 6 ++---- xs/src/libslic3r/Point.hpp | 20 +------------------- xs/src/libslic3r/libslic3r.h | 4 ++-- xs/xsp/BoundingBox.xsp | 8 ++++---- xs/xsp/BridgeDetector.xsp | 4 ++-- xs/xsp/Flow.xsp | 4 ++-- xs/xsp/Point.xsp | 18 +++++++++--------- 7 files changed, 22 insertions(+), 42 deletions(-) diff --git a/xs/src/admesh/util.cpp b/xs/src/admesh/util.cpp index b0c31469d..f3bf59b56 100644 --- a/xs/src/admesh/util.cpp +++ b/xs/src/admesh/util.cpp @@ -171,12 +171,11 @@ stl_scale(stl_file *stl, float factor) { } static void calculate_normals(stl_file *stl) { - long i; float normal[3]; if (stl->error) return; - for(i = 0; i < stl->stats.number_of_facets; i++) { + for(uint32_t i = 0; i < stl->stats.number_of_facets; i++) { stl_calculate_normal(normal, &stl->facet_start[i]); stl_normalize_vector(normal); stl->facet_start[i].normal.x = normal[0]; @@ -381,7 +380,6 @@ stl_mirror_xz(stl_file *stl) { } static float get_volume(stl_file *stl) { - long i; stl_vertex p0; stl_vertex p; stl_normal n; @@ -396,7 +394,7 @@ static float get_volume(stl_file *stl) { p0.y = stl->facet_start[0].vertex[0].y; p0.z = stl->facet_start[0].vertex[0].z; - for(i = 0; i < stl->stats.number_of_facets; i++) { + for(uint32_t i = 0; i < stl->stats.number_of_facets; i++) { p.x = stl->facet_start[i].vertex[0].x - p0.x; p.y = stl->facet_start[i].vertex[0].y - p0.y; p.z = stl->facet_start[i].vertex[0].z - p0.z; diff --git a/xs/src/libslic3r/Point.hpp b/xs/src/libslic3r/Point.hpp index 77e07bec8..09c292b5a 100644 --- a/xs/src/libslic3r/Point.hpp +++ b/xs/src/libslic3r/Point.hpp @@ -32,8 +32,7 @@ public: coord_t x; coord_t y; Point(coord_t _x = 0, coord_t _y = 0): x(_x), y(_y) {}; - Point(int _x, int _y): x(_x), y(_y) {}; - Point(long long _x, long long _y): x(coord_t(_x)), y(coord_t(_y)) {}; // for Clipper + Point(int64_t _x, int64_t _y): x(coord_t(_x)), y(coord_t(_y)) {}; // for Clipper Point(double x, double y); static Point new_scale(coordf_t x, coordf_t y) { return Point(coord_t(scale_(x)), coord_t(scale_(y))); } @@ -271,23 +270,6 @@ template inline TO convert_to(const Pointf3 &src) { return TO(typen #include #include namespace boost { namespace polygon { - template <> - struct geometry_concept { typedef coordinate_concept type; }; - -/* Boost.Polygon already defines a specialization for coordinate_traits as of 1.60: - https://github.com/boostorg/polygon/commit/0ac7230dd1f8f34cb12b86c8bb121ae86d3d9b97 */ -#if BOOST_VERSION < 106000 - template <> - struct coordinate_traits { - typedef coord_t coordinate_type; - typedef long double area_type; - typedef long long manhattan_area_type; - typedef unsigned long long unsigned_area_type; - typedef long long coordinate_difference; - typedef long double coordinate_distance; - }; -#endif - template <> struct geometry_concept { typedef point_concept type; }; diff --git a/xs/src/libslic3r/libslic3r.h b/xs/src/libslic3r/libslic3r.h index 7c694b05e..e58b01582 100644 --- a/xs/src/libslic3r/libslic3r.h +++ b/xs/src/libslic3r/libslic3r.h @@ -17,8 +17,8 @@ #define SLIC3R_VERSION "1.39.0" #define SLIC3R_BUILD "UNKNOWN" -typedef long coord_t; -typedef double coordf_t; +typedef int32_t coord_t; +typedef double coordf_t; //FIXME This epsilon value is used for many non-related purposes: // For a threshold of a squared Euclidean distance, diff --git a/xs/xsp/BoundingBox.xsp b/xs/xsp/BoundingBox.xsp index a326c7501..df8e6baea 100644 --- a/xs/xsp/BoundingBox.xsp +++ b/xs/xsp/BoundingBox.xsp @@ -25,10 +25,10 @@ double radius(); Clone min_point() %code{% RETVAL = THIS->min; %}; Clone max_point() %code{% RETVAL = THIS->max; %}; - long x_min() %code{% RETVAL = THIS->min.x; %}; - long x_max() %code{% RETVAL = THIS->max.x; %}; - long y_min() %code{% RETVAL = THIS->min.y; %}; - long y_max() %code{% RETVAL = THIS->max.y; %}; + int x_min() %code{% RETVAL = THIS->min.x; %}; + int x_max() %code{% RETVAL = THIS->max.x; %}; + int y_min() %code{% RETVAL = THIS->min.y; %}; + int y_max() %code{% RETVAL = THIS->max.y; %}; std::string serialize() %code{% char buf[2048]; sprintf(buf, "%ld,%ld;%ld,%ld", THIS->min.x, THIS->min.y, THIS->max.x, THIS->max.y); RETVAL = buf; %}; bool defined() %code{% RETVAL = THIS->defined; %}; diff --git a/xs/xsp/BridgeDetector.xsp b/xs/xsp/BridgeDetector.xsp index c7ac409df..0039d3579 100644 --- a/xs/xsp/BridgeDetector.xsp +++ b/xs/xsp/BridgeDetector.xsp @@ -23,7 +23,7 @@ BridgeDetector* BridgeDetector::new(expolygon, lower_slices, extrusion_width) ExPolygon* expolygon; ExPolygonCollection* lower_slices; - long extrusion_width; + int extrusion_width; CODE: RETVAL = new BridgeDetector(*expolygon, *lower_slices, extrusion_width); OUTPUT: @@ -33,7 +33,7 @@ BridgeDetector* BridgeDetector::new_expolygons(expolygons, lower_slices, extrusion_width) ExPolygonCollection* expolygons; ExPolygonCollection* lower_slices; - long extrusion_width; + int extrusion_width; CODE: RETVAL = new BridgeDetector(expolygons->expolygons, *lower_slices, extrusion_width); OUTPUT: diff --git a/xs/xsp/Flow.xsp b/xs/xsp/Flow.xsp index d9b7a45c0..b57df5e37 100644 --- a/xs/xsp/Flow.xsp +++ b/xs/xsp/Flow.xsp @@ -26,8 +26,8 @@ float spacing(); float spacing_to(Flow* other) %code{% RETVAL = THIS->spacing(*other); %}; - long scaled_width(); - long scaled_spacing(); + int scaled_width(); + int scaled_spacing(); double mm3_per_mm(); %{ diff --git a/xs/xsp/Point.xsp b/xs/xsp/Point.xsp index d0f9260c7..b7aded6a0 100644 --- a/xs/xsp/Point.xsp +++ b/xs/xsp/Point.xsp @@ -8,7 +8,7 @@ %} %name{Slic3r::Point} class Point { - Point(long _x = 0, long _y = 0); + Point(int _x = 0, int _y = 0); ~Point(); Clone clone() %code{% RETVAL=THIS; %}; @@ -18,13 +18,13 @@ %code{% RETVAL = to_SV_pureperl(THIS); %}; SV* pp() %code{% RETVAL = to_SV_pureperl(THIS); %}; - long x() + int x() %code{% RETVAL = THIS->x; %}; - long y() + int y() %code{% RETVAL = THIS->y; %}; - void set_x(long val) + void set_x(int val) %code{% THIS->x = val; %}; - void set_y(long val) + void set_y(int val) %code{% THIS->y = val; %}; int nearest_point_index(Points points); Clone nearest_point(Points points) @@ -77,15 +77,15 @@ Point::coincides_with(point_sv) }; %name{Slic3r::Point3} class Point3 { - Point3(long _x = 0, long _y = 0, long _z = 0); + Point3(int _x = 0, int _y = 0, int _z = 0); ~Point3(); Clone clone() %code{% RETVAL = THIS; %}; - long x() + int x() %code{% RETVAL = THIS->x; %}; - long y() + int y() %code{% RETVAL = THIS->y; %}; - long z() + int z() %code{% RETVAL = THIS->z; %}; std::string serialize() %code{% char buf[2048]; sprintf(buf, "%ld,%ld,%ld", THIS->x, THIS->y, THIS->z); RETVAL = buf; %}; }; From 6f92424bab82f1795697b21e074e4652529271ff Mon Sep 17 00:00:00 2001 From: bubnikv Date: Mon, 12 Feb 2018 19:06:05 +0100 Subject: [PATCH 4/7] Fix of https://github.com/prusa3d/Slic3r/issues/709 A regression error has been introduced into Slic3r 1.38.xx series for the float/percent config value, where the value was considered unchanged if the percent sign has been added or removed. --- xs/src/libslic3r/Config.hpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/xs/src/libslic3r/Config.hpp b/xs/src/libslic3r/Config.hpp index e04f4df82..a58bb613a 100644 --- a/xs/src/libslic3r/Config.hpp +++ b/xs/src/libslic3r/Config.hpp @@ -582,6 +582,13 @@ public: ConfigOptionType type() const override { return static_type(); } ConfigOption* clone() const override { return new ConfigOptionFloatOrPercent(*this); } ConfigOptionFloatOrPercent& operator=(const ConfigOption *opt) { this->set(opt); return *this; } + bool operator==(const ConfigOption &rhs) const override + { + if (rhs.type() != this->type()) + throw std::runtime_error("ConfigOptionFloatOrPercent: Comparing incompatible types"); + assert(dynamic_cast(&rhs)); + return *this == *static_cast(&rhs); + } bool operator==(const ConfigOptionFloatOrPercent &rhs) const { return this->value == rhs.value && this->percent == rhs.percent; } double get_abs_value(double ratio_over) const From 81a80ebd618ada3494e6c996d0b607bf522dddb0 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Mon, 12 Feb 2018 20:44:06 +0100 Subject: [PATCH 5/7] Synchronized the GCodeSender with the upstream Slic3r, thanks @alexrj. Fixes https://github.com/prusa3d/Slic3r/issues/654 --- xs/src/libslic3r/GCodeSender.cpp | 120 ++++++++++++++++++------------- 1 file changed, 70 insertions(+), 50 deletions(-) diff --git a/xs/src/libslic3r/GCodeSender.cpp b/xs/src/libslic3r/GCodeSender.cpp index 504171288..bbeaf836d 100644 --- a/xs/src/libslic3r/GCodeSender.cpp +++ b/xs/src/libslic3r/GCodeSender.cpp @@ -7,16 +7,36 @@ #include #include -#if defined(__APPLE__) || defined(__linux) || defined(__OpenBSD__) +#if defined(__APPLE__) || defined(__OpenBSD__) #include #endif -#if __APPLE__ +#ifdef __APPLE__ #include #include #endif -#ifdef __linux +#ifdef __linux__ #include -#include +#include +#include "/usr/include/asm-generic/ioctls.h" + +/* The following definitions are kindly borrowed from: + /usr/include/asm-generic/termbits.h + Unfortunately we cannot just include that one because + it would redefine the "struct termios" already defined + the already included by Boost.ASIO. */ +#define K_NCCS 19 +struct termios2 { + tcflag_t c_iflag; + tcflag_t c_oflag; + tcflag_t c_cflag; + tcflag_t c_lflag; + cc_t c_line; + cc_t c_cc[K_NCCS]; + speed_t c_ispeed; + speed_t c_ospeed; +}; +#define BOTHER CBAUDEX + #endif //#define DEBUG_SERIAL @@ -47,26 +67,26 @@ GCodeSender::connect(std::string devname, unsigned int baud_rate) this->set_error_status(false); try { this->serial.open(devname); + + this->serial.set_option(boost::asio::serial_port_base::parity(boost::asio::serial_port_base::parity::odd)); + this->serial.set_option(boost::asio::serial_port_base::character_size(boost::asio::serial_port_base::character_size(8))); + this->serial.set_option(boost::asio::serial_port_base::flow_control(boost::asio::serial_port_base::flow_control::none)); + this->serial.set_option(boost::asio::serial_port_base::stop_bits(boost::asio::serial_port_base::stop_bits::one)); + this->set_baud_rate(baud_rate); + + this->serial.close(); + this->serial.open(devname); + this->serial.set_option(boost::asio::serial_port_base::parity(boost::asio::serial_port_base::parity::none)); + + // set baud rate again because set_option overwrote it + this->set_baud_rate(baud_rate); + this->open = true; + this->reset(); } catch (boost::system::system_error &) { this->set_error_status(true); return false; } - this->serial.set_option(boost::asio::serial_port_base::parity(boost::asio::serial_port_base::parity::odd)); - this->serial.set_option(boost::asio::serial_port_base::character_size(boost::asio::serial_port_base::character_size(8))); - this->serial.set_option(boost::asio::serial_port_base::flow_control(boost::asio::serial_port_base::flow_control::none)); - this->serial.set_option(boost::asio::serial_port_base::stop_bits(boost::asio::serial_port_base::stop_bits::one)); - this->set_baud_rate(baud_rate); - - this->serial.close(); - this->serial.open(devname); - this->serial.set_option(boost::asio::serial_port_base::parity(boost::asio::serial_port_base::parity::none)); - - // set baud rate again because set_option overwrote it - this->set_baud_rate(baud_rate); - this->open = true; - this->reset(); - // a reset firmware expect line numbers to start again from 1 this->sent = 0; this->last_sent.clear(); @@ -84,6 +104,11 @@ GCodeSender::connect(std::string devname, unsigned int baud_rate) boost::thread t(boost::bind(&boost::asio::io_service::run, &this->io)); this->background_thread.swap(t); + // always send a M105 to check for connection because firmware might be silent on connect + //FIXME Vojtech: This is being sent too early, leading to line number synchronization issues, + // from which the GCodeSender never recovers. + // this->send("M105", true); + return true; } @@ -104,27 +129,17 @@ GCodeSender::set_baud_rate(unsigned int baud_rate) ioctl(handle, IOSSIOSPEED, &newSpeed); ::tcsetattr(handle, TCSANOW, &ios); #elif __linux - termios ios; - ::tcgetattr(handle, &ios); - ::cfsetispeed(&ios, B38400); - ::cfsetospeed(&ios, B38400); - ::tcflush(handle, TCIFLUSH); - ::tcsetattr(handle, TCSANOW, &ios); - - struct serial_struct ss; - ioctl(handle, TIOCGSERIAL, &ss); - ss.flags = (ss.flags & ~ASYNC_SPD_MASK) | ASYNC_SPD_CUST; - ss.custom_divisor = (ss.baud_base + (baud_rate / 2)) / baud_rate; - //cout << "bbase " << ss.baud_base << " div " << ss.custom_divisor; - long closestSpeed = ss.baud_base / ss.custom_divisor; - //cout << " Closest speed " << closestSpeed << endl; - ss.reserved_char[0] = 0; - if (closestSpeed < baud_rate * 98 / 100 || closestSpeed > baud_rate * 102 / 100) { - printf("Failed to set baud rate\n"); - } - - ioctl(handle, TIOCSSERIAL, &ss); - printf("< set_baud_rate: %u\n", baud_rate); + termios2 ios; + if (ioctl(handle, TCGETS2, &ios)) + printf("Error in TCGETS2: %s\n", strerror(errno)); + ios.c_ispeed = ios.c_ospeed = baud_rate; + ios.c_cflag &= ~CBAUD; + ios.c_cflag |= BOTHER | CLOCAL | CREAD; + ios.c_cc[VMIN] = 1; // Minimum of characters to read, prevents eof errors when 0 bytes are read + ios.c_cc[VTIME] = 1; + if (ioctl(handle, TCSETS2, &ios)) + printf("Error in TCSETS2: %s\n", strerror(errno)); + #elif __OpenBSD__ struct termios ios; ::tcgetattr(handle, &ios); @@ -154,6 +169,7 @@ GCodeSender::disconnect() */ #ifdef DEBUG_SERIAL + fs << "DISCONNECTED" << std::endl << std::flush; fs.close(); #endif } @@ -292,17 +308,20 @@ GCodeSender::on_read(const boost::system::error_code& error, { this->set_error_status(false); if (error) { + #ifdef __APPLE__ if (error.value() == 45) { // OS X bug: http://osdir.com/ml/lib.boost.asio.user/2008-08/msg00004.html this->do_read(); - } else { - // printf("ERROR: [%d] %s\n", error.value(), error.message().c_str()); - // error can be true even because the serial port was closed. - // In this case it is not a real error, so ignore. - if (this->open) { - this->do_close(); - this->set_error_status(true); - } + return; + } + #endif + + // printf("ERROR: [%d] %s\n", error.value(), error.message().c_str()); + // error can be true even because the serial port was closed. + // In this case it is not a real error, so ignore. + if (this->open) { + this->do_close(); + this->set_error_status(true); } return; } @@ -339,7 +358,8 @@ GCodeSender::on_read(const boost::system::error_code& error, // extract the first number from line boost::algorithm::trim_left_if(line, !boost::algorithm::is_digit()); size_t toresend = boost::lexical_cast(line.substr(0, line.find_first_not_of("0123456789"))); - if (toresend >= this->sent - this->last_sent.size()) { + ++ toresend; // N is 0-based + if (toresend >= this->sent - this->last_sent.size() && toresend < this->last_sent.size()) { { boost::lock_guard l(this->queue_mutex); @@ -457,8 +477,8 @@ GCodeSender::do_send() if (line.empty()) return; // compute full line - this->sent++; std::string full_line = "N" + boost::lexical_cast(this->sent) + " " + line; + ++ this->sent; // calculate checksum int cs = 0; From e77111bf9891df61abbd1130d5aa8165a52a9058 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Tue, 13 Feb 2018 10:25:55 +0100 Subject: [PATCH 6/7] Fixed crash when importing .prusa files --- xs/src/libslic3r/Format/PRUS.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xs/src/libslic3r/Format/PRUS.cpp b/xs/src/libslic3r/Format/PRUS.cpp index b7ef33774..1809eaead 100644 --- a/xs/src/libslic3r/Format/PRUS.cpp +++ b/xs/src/libslic3r/Format/PRUS.cpp @@ -148,7 +148,7 @@ bool load_prus(const char *path, Model *model) if (scene_xml_data.size() < size_last + size_incr) scene_xml_data.resize(size_last + size_incr); } - size_last += size_last + zip.LastRead(); + size_last += zip.LastRead(); if (scene_xml_data.size() == size_last) scene_xml_data.resize(size_last + 1); else if (scene_xml_data.size() > size_last + 1) From e7f05f8516e5e7ab52bfc4af0d5bbbd1bc5ae43c Mon Sep 17 00:00:00 2001 From: bubnikv Date: Tue, 13 Feb 2018 11:18:58 +0100 Subject: [PATCH 7/7] Fix of "Crash while trying to slice with a raft" #686 This was an issue specific to multi-material print with raft and no support. --- xs/src/libslic3r/Print.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/xs/src/libslic3r/Print.cpp b/xs/src/libslic3r/Print.cpp index 0bc63f2f3..c689929c6 100644 --- a/xs/src/libslic3r/Print.cpp +++ b/xs/src/libslic3r/Print.cpp @@ -997,7 +997,8 @@ void Print::_make_wipe_tower() // Find the position in this->objects.first()->support_layers to insert these new support layers. double wipe_tower_new_layer_print_z_first = m_tool_ordering.layer_tools()[idx_begin].print_z; SupportLayerPtrs::iterator it_layer = this->objects.front()->support_layers.begin(); - for (; (*it_layer)->print_z - EPSILON < wipe_tower_new_layer_print_z_first; ++ it_layer) ; + SupportLayerPtrs::iterator it_end = this->objects.front()->support_layers.end(); + for (; it_layer != it_end && (*it_layer)->print_z - EPSILON < wipe_tower_new_layer_print_z_first; ++ it_layer); // Find the stopper of the sequence of wipe tower layers, which do not have a counterpart in an object or a support layer. for (size_t i = idx_begin; i < idx_end; ++ i) { ToolOrdering::LayerTools < = const_cast(m_tool_ordering.layer_tools()[i]); @@ -1005,9 +1006,9 @@ void Print::_make_wipe_tower() break; lt.has_support = true; // Insert the new support layer. - //FIXME the support layer ID is duplicated, but Vojtech hopes it is not being used anywhere anyway. double height = lt.print_z - m_tool_ordering.layer_tools()[i-1].print_z; - auto *new_layer = new SupportLayer((*it_layer)->id(), this->objects.front(), + //FIXME the support layer ID is set to -1, as Vojtech hopes it is not being used anyway. + auto *new_layer = new SupportLayer(size_t(-1), this->objects.front(), height, lt.print_z, lt.print_z - 0.5 * height); it_layer = this->objects.front()->support_layers.insert(it_layer, new_layer); ++ it_layer;