From 28a6bd7c3013ebf9c57353c600fc9a60f0f75ad2 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Mon, 21 Oct 2019 08:48:38 +0200 Subject: #3075 - Fixed Reload from disk command for .amf files --- src/libslic3r/Format/AMF.cpp | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/libslic3r/Format/AMF.cpp b/src/libslic3r/Format/AMF.cpp index 2d77d3daa..181d6cb99 100644 --- a/src/libslic3r/Format/AMF.cpp +++ b/src/libslic3r/Format/AMF.cpp @@ -584,8 +584,16 @@ void AMFParserContext::endElement(const char * /* name */) stl_get_size(&stl); mesh.repair(); m_volume->set_mesh(std::move(mesh)); - // pass false if the mesh offset has been already taken from the data - m_volume->center_geometry_after_creation(m_volume->source.input_file.empty()); + if (m_volume->source.input_file.empty() && (m_volume->type() == ModelVolumeType::MODEL_PART)) + { + m_volume->source.object_idx = (int)m_model.objects.size() - 1; + m_volume->source.volume_idx = (int)m_model.objects.back()->volumes.size() - 1; + m_volume->center_geometry_after_creation(); + } + else + // pass false if the mesh offset has been already taken from the data + m_volume->center_geometry_after_creation(m_volume->source.input_file.empty()); + m_volume->calculate_convex_hull(); m_volume_facets.clear(); m_volume = nullptr; @@ -799,6 +807,15 @@ bool load_amf_file(const char *path, DynamicPrintConfig *config, Model *model) if (result) ctx.endDocument(); + for (ModelObject* o : model->objects) + { + for (ModelVolume* v : o->volumes) + { + if (v->source.input_file.empty() && (v->type() == ModelVolumeType::MODEL_PART)) + v->source.input_file = path; + } + } + return result; } -- cgit v1.2.3 From 2d610f9b84df1be44682e2fd1a94f05592f39841 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Mon, 21 Oct 2019 10:12:42 +0200 Subject: #3082 - Workaround to fix incorrect object position after applying gcode line G92 into custom gcode --- src/libslic3r/GCode/Analyzer.cpp | 24 ++++++++++++++++++++++++ src/libslic3r/GCode/Analyzer.hpp | 3 +++ 2 files changed, 27 insertions(+) (limited to 'src') diff --git a/src/libslic3r/GCode/Analyzer.cpp b/src/libslic3r/GCode/Analyzer.cpp index 78f6c6806..3f0b8735f 100644 --- a/src/libslic3r/GCode/Analyzer.cpp +++ b/src/libslic3r/GCode/Analyzer.cpp @@ -285,6 +285,11 @@ void GCodeAnalyzer::_process_gcode_line(GCodeReader&, const GCodeReader::GCodeLi _processM108orM135(line); break; } + case 132: // Recall stored home offsets + { + _processM132(line); + break; + } case 401: // Repetier: Store x, y and z position { _processM401(line); @@ -504,6 +509,25 @@ void GCodeAnalyzer::_processM108orM135(const GCodeReader::GCodeLine& line) } } +void GCodeAnalyzer::_processM132(const GCodeReader::GCodeLine& line) +{ + // This command is used by Makerbot to load the current home position from EEPROM + // see: https://github.com/makerbot/s3g/blob/master/doc/GCodeProtocol.md + // Using this command to reset the axis origin to zero helps in fixing: https://github.com/prusa3d/PrusaSlicer/issues/3082 + + if (line.has_x()) + _set_axis_origin(X, 0.0f); + + if (line.has_y()) + _set_axis_origin(Y, 0.0f); + + if (line.has_z()) + _set_axis_origin(Z, 0.0f); + + if (line.has_e()) + _set_axis_origin(E, 0.0f); +} + void GCodeAnalyzer::_processM401(const GCodeReader::GCodeLine& line) { if (m_gcode_flavor != gcfRepetier) diff --git a/src/libslic3r/GCode/Analyzer.hpp b/src/libslic3r/GCode/Analyzer.hpp index e90175c49..df4f6f652 100644 --- a/src/libslic3r/GCode/Analyzer.hpp +++ b/src/libslic3r/GCode/Analyzer.hpp @@ -182,6 +182,9 @@ private: // Set tool (MakerWare and Sailfish flavor) void _processM108orM135(const GCodeReader::GCodeLine& line); + // Recall stored home offsets + void _processM132(const GCodeReader::GCodeLine& line); + // Repetier: Store x, y and z position void _processM401(const GCodeReader::GCodeLine& line); -- cgit v1.2.3 From 0d89fd84db41e582381a310904765b4f37aacfdb Mon Sep 17 00:00:00 2001 From: YuSanka Date: Tue, 22 Oct 2019 10:26:51 +0200 Subject: Fixed a case when (under OSX) after some manipulation with an object or a part and then add some setting from 3dScene, "Revert button(s)" are still appear(s) in right panel --- src/slic3r/GUI/GUI_ObjectManipulation.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp index 0b3f2b098..4ecab8a0f 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp @@ -632,7 +632,11 @@ void ObjectManipulation::update_reset_buttons_visibility() show_drop_to_bed = (std::abs(min_z) > EPSILON); } - wxGetApp().CallAfter([this, show_rotation, show_scale, show_drop_to_bed]{ + wxGetApp().CallAfter([this, show_rotation, show_scale, show_drop_to_bed] { + // There is a case (under OSX), when this function is called after the Manipulation panel is hidden + // So, let check if Manipulation panel is still shown for this moment + if (!this->IsShown()) + return; m_reset_rotation_button->Show(show_rotation); m_reset_scale_button->Show(show_scale); m_drop_to_bed_button->Show(show_drop_to_bed); -- cgit v1.2.3 From 8dea6c2fd8fb31502a6c5ab38298a046c436b8d9 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Tue, 22 Oct 2019 12:39:22 +0200 Subject: Fixed a crash with the following repro: 1) Start PrusaSlicer 2) Select printer: Original Prusa i3 MK2.5 3) Load any stl file 4) In Printer Settings turn on "Support stealth mode" 5) Press "Slice now" -> crash All the "machine_XXXXX" vectors in the print config contain a single value instead of two leading to a vector subscript out of range when read into GCode::_do_export() --- src/libslic3r/GCode.cpp | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 3a72657c3..26d9c90f8 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -778,22 +778,26 @@ void GCode::_do_export(Print &print, FILE *file) { m_silent_time_estimator.reset(); m_silent_time_estimator.set_dialect(print.config().gcode_flavor); - m_silent_time_estimator.set_max_acceleration((float)print.config().machine_max_acceleration_extruding.values[1]); - m_silent_time_estimator.set_retract_acceleration((float)print.config().machine_max_acceleration_retracting.values[1]); - m_silent_time_estimator.set_minimum_feedrate((float)print.config().machine_min_extruding_rate.values[1]); - m_silent_time_estimator.set_minimum_travel_feedrate((float)print.config().machine_min_travel_rate.values[1]); - m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::X, (float)print.config().machine_max_acceleration_x.values[1]); - m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Y, (float)print.config().machine_max_acceleration_y.values[1]); - m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Z, (float)print.config().machine_max_acceleration_z.values[1]); - m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::E, (float)print.config().machine_max_acceleration_e.values[1]); - m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::X, (float)print.config().machine_max_feedrate_x.values[1]); - m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Y, (float)print.config().machine_max_feedrate_y.values[1]); - m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Z, (float)print.config().machine_max_feedrate_z.values[1]); - m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::E, (float)print.config().machine_max_feedrate_e.values[1]); - m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::X, (float)print.config().machine_max_jerk_x.values[1]); - m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Y, (float)print.config().machine_max_jerk_y.values[1]); - m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Z, (float)print.config().machine_max_jerk_z.values[1]); - m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::E, (float)print.config().machine_max_jerk_e.values[1]); + /* "Stealth mode" values can be just a copy of "normal mode" values + * (when they aren't input for a printer preset). + * Thus, use back value from values, instead of second one, which could be absent + */ + m_silent_time_estimator.set_max_acceleration((float)print.config().machine_max_acceleration_extruding.values.back()); + m_silent_time_estimator.set_retract_acceleration((float)print.config().machine_max_acceleration_retracting.values.back()); + m_silent_time_estimator.set_minimum_feedrate((float)print.config().machine_min_extruding_rate.values.back()); + m_silent_time_estimator.set_minimum_travel_feedrate((float)print.config().machine_min_travel_rate.values.back()); + m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::X, (float)print.config().machine_max_acceleration_x.values.back()); + m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Y, (float)print.config().machine_max_acceleration_y.values.back()); + m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Z, (float)print.config().machine_max_acceleration_z.values.back()); + m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::E, (float)print.config().machine_max_acceleration_e.values.back()); + m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::X, (float)print.config().machine_max_feedrate_x.values.back()); + m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Y, (float)print.config().machine_max_feedrate_y.values.back()); + m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Z, (float)print.config().machine_max_feedrate_z.values.back()); + m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::E, (float)print.config().machine_max_feedrate_e.values.back()); + m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::X, (float)print.config().machine_max_jerk_x.values.back()); + m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Y, (float)print.config().machine_max_jerk_y.values.back()); + m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Z, (float)print.config().machine_max_jerk_z.values.back()); + m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::E, (float)print.config().machine_max_jerk_e.values.back()); if (print.config().single_extruder_multi_material) { // As of now the fields are shown at the UI dialog in the same combo box as the ramming values, so they // are considered to be active for the single extruder multi-material printers only. -- cgit v1.2.3 From 9f9a40100f13a0b8e8b0703a9b034184c47244ed Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Tue, 22 Oct 2019 16:32:21 +0200 Subject: Solve build fail in RelWithDebInfo config with several imported targets. --- src/qhull/CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/qhull/CMakeLists.txt b/src/qhull/CMakeLists.txt index 9ca0bdff2..ab9aba9af 100644 --- a/src/qhull/CMakeLists.txt +++ b/src/qhull/CMakeLists.txt @@ -18,11 +18,13 @@ if(Qhull_FOUND) message(STATUS "Using qhull from system.") if(SLIC3R_STATIC) + slic3r_remap_configs("Qhull::qhullcpp;Qhull::qhullstatic_r" RelWithDebInfo Release) target_link_libraries(qhull INTERFACE Qhull::qhullcpp Qhull::qhullstatic_r) else() + slic3r_remap_configs("Qhull::qhullcpp;Qhull::qhull_r" RelWithDebInfo Release) target_link_libraries(qhull INTERFACE Qhull::qhullcpp Qhull::qhull_r) endif() - + else(Qhull_FOUND) project(qhull) -- cgit v1.2.3 From cf94482731746fda6bbd83c5aa5862105549c319 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Wed, 23 Oct 2019 15:07:41 +0200 Subject: Fix of Voronoi debug output. --- src/libslic3r/Geometry.cpp | 35 +++++++++++++++++------------------ src/libslic3r/Geometry.hpp | 4 +--- 2 files changed, 18 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/libslic3r/Geometry.cpp b/src/libslic3r/Geometry.cpp index e926b9997..46d7ef154 100644 --- a/src/libslic3r/Geometry.cpp +++ b/src/libslic3r/Geometry.cpp @@ -663,7 +663,6 @@ namespace Voronoi { namespace Internal { typedef boost::polygon::point_data point_type; typedef boost::polygon::segment_data segment_type; typedef boost::polygon::rectangle_data rect_type; -// typedef voronoi_builder VB; typedef boost::polygon::voronoi_diagram VD; typedef VD::cell_type cell_type; typedef VD::cell_type::source_index_type source_index_type; @@ -710,15 +709,15 @@ namespace Voronoi { namespace Internal { if (cell1.contains_point() && cell2.contains_point()) { point_type p1 = retrieve_point(segments, cell1); point_type p2 = retrieve_point(segments, cell2); - origin.x((p1(0) + p2(0)) * 0.5); - origin.y((p1(1) + p2(1)) * 0.5); - direction.x(p1(1) - p2(1)); - direction.y(p2(0) - p1(0)); + origin.x((p1.x() + p2.x()) * 0.5); + origin.y((p1.y() + p2.y()) * 0.5); + direction.x(p1.y() - p2.y()); + direction.y(p2.x() - p1.x()); } else { origin = cell1.contains_segment() ? retrieve_point(segments, cell2) : retrieve_point(segments, cell1); segment_type segment = cell1.contains_segment() ? segments[cell1.source_index()] : segments[cell2.source_index()]; - coordinate_type dx = high(segment)(0) - low(segment)(0); - coordinate_type dy = high(segment)(1) - low(segment)(1); + coordinate_type dx = high(segment).x() - low(segment).x(); + coordinate_type dy = high(segment).y() - low(segment).y(); if ((low(segment) == origin) ^ cell1.contains_point()) { direction.x(dy); direction.y(-dx); @@ -727,19 +726,19 @@ namespace Voronoi { namespace Internal { direction.y(dx); } } - coordinate_type koef = bbox_max_size / (std::max)(fabs(direction(0)), fabs(direction(1))); + coordinate_type koef = bbox_max_size / (std::max)(fabs(direction.x()), fabs(direction.y())); if (edge.vertex0() == NULL) { clipped_edge->push_back(point_type( - origin(0) - direction(0) * koef, - origin(1) - direction(1) * koef)); + origin.x() - direction.x() * koef, + origin.y() - direction.y() * koef)); } else { clipped_edge->push_back( point_type(edge.vertex0()->x(), edge.vertex0()->y())); } if (edge.vertex1() == NULL) { clipped_edge->push_back(point_type( - origin(0) + direction(0) * koef, - origin(1) + direction(1) * koef)); + origin.x() + direction.x() * koef, + origin.y() + direction.y() * koef)); } else { clipped_edge->push_back( point_type(edge.vertex1()->x(), edge.vertex1()->y())); @@ -759,7 +758,7 @@ namespace Voronoi { namespace Internal { } /* namespace Internal */ } // namespace Voronoi -static inline void dump_voronoi_to_svg(const Lines &lines, /* const */ voronoi_diagram &vd, const ThickPolylines *polylines, const char *path) +static inline void dump_voronoi_to_svg(const Lines &lines, /* const */ boost::polygon::voronoi_diagram &vd, const ThickPolylines *polylines, const char *path) { const double scale = 0.2; const std::string inputSegmentPointColor = "lightseagreen"; @@ -803,7 +802,7 @@ static inline void dump_voronoi_to_svg(const Lines &lines, /* const */ voronoi_d Voronoi::Internal::point_type(double(it->b(0)), double(it->b(1))))); // Color exterior edges. - for (voronoi_diagram::const_edge_iterator it = vd.edges().begin(); it != vd.edges().end(); ++it) + for (boost::polygon::voronoi_diagram::const_edge_iterator it = vd.edges().begin(); it != vd.edges().end(); ++it) if (!it->is_finite()) Voronoi::Internal::color_exterior(&(*it)); @@ -818,11 +817,11 @@ static inline void dump_voronoi_to_svg(const Lines &lines, /* const */ voronoi_d #if 1 // Draw voronoi vertices. - for (voronoi_diagram::const_vertex_iterator it = vd.vertices().begin(); it != vd.vertices().end(); ++it) + for (boost::polygon::voronoi_diagram::const_vertex_iterator it = vd.vertices().begin(); it != vd.vertices().end(); ++it) if (! internalEdgesOnly || it->color() != Voronoi::Internal::EXTERNAL_COLOR) - svg.draw(Point(coord_t((*it)(0)), coord_t((*it)(1))), voronoiPointColor, voronoiPointRadius); + svg.draw(Point(coord_t(it->x()), coord_t(it->y())), voronoiPointColor, voronoiPointRadius); - for (voronoi_diagram::const_edge_iterator it = vd.edges().begin(); it != vd.edges().end(); ++it) { + for (boost::polygon::voronoi_diagram::const_edge_iterator it = vd.edges().begin(); it != vd.edges().end(); ++it) { if (primaryEdgesOnly && !it->is_primary()) continue; if (internalEdgesOnly && (it->color() == Voronoi::Internal::EXTERNAL_COLOR)) @@ -845,7 +844,7 @@ static inline void dump_voronoi_to_svg(const Lines &lines, /* const */ voronoi_d color = voronoiLineColorSecondary; } for (std::size_t i = 0; i + 1 < samples.size(); ++i) - svg.draw(Line(Point(coord_t(samples[i](0)), coord_t(samples[i](1))), Point(coord_t(samples[i+1](0)), coord_t(samples[i+1](1)))), color, voronoiLineWidth); + svg.draw(Line(Point(coord_t(samples[i].x()), coord_t(samples[i].y())), Point(coord_t(samples[i+1].x()), coord_t(samples[i+1].y()))), color, voronoiLineWidth); } #endif diff --git a/src/libslic3r/Geometry.hpp b/src/libslic3r/Geometry.hpp index 44303711b..d996658f2 100644 --- a/src/libslic3r/Geometry.hpp +++ b/src/libslic3r/Geometry.hpp @@ -11,8 +11,6 @@ #include #include "boost/polygon/voronoi.hpp" -using boost::polygon::voronoi_builder; -using boost::polygon::voronoi_diagram; namespace ClipperLib { class PolyNode; @@ -192,7 +190,7 @@ class MedialAxis { void build(Polylines* polylines); private: - class VD : public voronoi_diagram { + class VD : public boost::polygon::voronoi_diagram { public: typedef double coord_type; typedef boost::polygon::point_data point_type; -- cgit v1.2.3 From 62c90abbc03887c7cf03297d3ec2c7c68ee15755 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Fri, 25 Oct 2019 13:09:10 +0200 Subject: Fix of SPE-1041: set_state function for gizmos is called even if they are turned on/off by the undo/redo action --- src/slic3r/GUI/Gizmos/GLGizmosManager.hpp | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'src') diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp index f649c98b2..0defb1348 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp @@ -114,8 +114,17 @@ public: m_serializing = true; + // Following is needed to know which to be turn on, but not actually modify + // m_current prematurely, so activate_gizmo is not confused. + EType old_current = m_current; ar(m_current); + EType new_current = m_current; + m_current = old_current; + // activate_gizmo call sets m_current and calls set_state for the gizmo + // it does nothing in case the gizmo is already activated + // it can safely be called for Undefined gizmo + activate_gizmo(new_current); if (m_current != Undefined) m_gizmos[m_current]->load(ar); } -- cgit v1.2.3 From 4554da29abc153c48284235ed73f2aa7d4eefc8e Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Fri, 25 Oct 2019 13:09:25 +0200 Subject: Add OpenVDB to dependencies * Add Linux openvdb integration * Add Mac openvdb integration and enable in ALL * Create openvdb sandbox to test integration. * Additional fixes in the patches * Remove slabasebed sandbox as it has no relevance now * Provide FindOpenVDB module and fix build issues --- src/libslic3r/CMakeLists.txt | 1 + src/qhull/CMakeLists.txt | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index cbaa24e9c..fb13acc85 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -222,6 +222,7 @@ target_link_libraries(libslic3r qhull semver TBB::tbb + OpenVDB::openvdb ${CMAKE_DL_LIBS} ) diff --git a/src/qhull/CMakeLists.txt b/src/qhull/CMakeLists.txt index 9ca0bdff2..ab9aba9af 100644 --- a/src/qhull/CMakeLists.txt +++ b/src/qhull/CMakeLists.txt @@ -18,11 +18,13 @@ if(Qhull_FOUND) message(STATUS "Using qhull from system.") if(SLIC3R_STATIC) + slic3r_remap_configs("Qhull::qhullcpp;Qhull::qhullstatic_r" RelWithDebInfo Release) target_link_libraries(qhull INTERFACE Qhull::qhullcpp Qhull::qhullstatic_r) else() + slic3r_remap_configs("Qhull::qhullcpp;Qhull::qhull_r" RelWithDebInfo Release) target_link_libraries(qhull INTERFACE Qhull::qhullcpp Qhull::qhull_r) endif() - + else(Qhull_FOUND) project(qhull) -- cgit v1.2.3 From bcc2c21d5fd9e9dc088f61ab84a5ca9b668e9e40 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Fri, 25 Oct 2019 13:23:05 +0200 Subject: Disable OpenVDB until deps get updated --- src/libslic3r/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index fb13acc85..8b162a1d5 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -222,7 +222,7 @@ target_link_libraries(libslic3r qhull semver TBB::tbb - OpenVDB::openvdb + # OpenVDB::openvdb ${CMAKE_DL_LIBS} ) -- cgit v1.2.3 From 5e8572a196a3a50bb0733d1922cc24ddc37bebfa Mon Sep 17 00:00:00 2001 From: bubnikv Date: Fri, 25 Oct 2019 13:34:37 +0200 Subject: New functions for variable offsets of polygons / expolygons. Test cases for the above. Improvements of older test cases. --- src/libslic3r/ClipperUtils.cpp | 314 +++++++++++++++++++++++++++++++++++++++-- src/libslic3r/ClipperUtils.hpp | 5 + src/libslic3r/ExPolygon.hpp | 9 ++ src/libslic3r/Polygon.hpp | 9 ++ 4 files changed, 328 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/libslic3r/ClipperUtils.cpp b/src/libslic3r/ClipperUtils.cpp index b863b4712..55bb4b446 100644 --- a/src/libslic3r/ClipperUtils.cpp +++ b/src/libslic3r/ClipperUtils.cpp @@ -107,8 +107,7 @@ void AddOuterPolyNodeToExPolygons(ClipperLib::PolyNode& polynode, ExPolygons* ex } } -ExPolygons -PolyTreeToExPolygons(ClipperLib::PolyTree& polytree) +ExPolygons PolyTreeToExPolygons(ClipperLib::PolyTree& polytree) { ExPolygons retval; for (int i = 0; i < polytree.ChildCount(); ++i) @@ -151,8 +150,7 @@ Slic3r::Polylines ClipperPaths_to_Slic3rPolylines(const ClipperLib::Paths &input return retval; } -ExPolygons -ClipperPaths_to_Slic3rExPolygons(const ClipperLib::Paths &input) +ExPolygons ClipperPaths_to_Slic3rExPolygons(const ClipperLib::Paths &input) { // init Clipper ClipperLib::Clipper clipper; @@ -167,8 +165,7 @@ ClipperPaths_to_Slic3rExPolygons(const ClipperLib::Paths &input) return PolyTreeToExPolygons(polytree); } -ClipperLib::Path -Slic3rMultiPoint_to_ClipperPath(const MultiPoint &input) +ClipperLib::Path Slic3rMultiPoint_to_ClipperPath(const MultiPoint &input) { ClipperLib::Path retval; for (Points::const_iterator pit = input.points.begin(); pit != input.points.end(); ++pit) @@ -176,8 +173,7 @@ Slic3rMultiPoint_to_ClipperPath(const MultiPoint &input) return retval; } -ClipperLib::Path -Slic3rMultiPoint_to_ClipperPath_reversed(const Slic3r::MultiPoint &input) +ClipperLib::Path Slic3rMultiPoint_to_ClipperPath_reversed(const Slic3r::MultiPoint &input) { ClipperLib::Path output; output.reserve(input.points.size()); @@ -521,7 +517,7 @@ T _clipper_do(const ClipperLib::ClipType clipType, // Fix of #117: A large fractal pyramid takes ages to slice // The Clipper library has difficulties processing overlapping polygons. -// Namely, the function Clipper::JoinCommonEdges() has potentially a terrible time complexity if the output +// Namely, the function ClipperLib::JoinCommonEdges() has potentially a terrible time complexity if the output // of the operation is of the PolyTree type. // This function implmenets a following workaround: // 1) Peform the Clipper operation with the output to Paths. This method handles overlaps in a reasonable time. @@ -918,4 +914,304 @@ Polygons top_level_islands(const Slic3r::Polygons &polygons) return out; } +// Outer offset shall not split the input contour into multiples. It is expected, that the solution will be non empty and it will contain just a single polygon. +ClipperLib::Paths fix_after_outer_offset(const ClipperLib::Path &input, ClipperLib::PolyFillType filltype, bool reverse_result) +{ + ClipperLib::Paths solution; + if (! input.empty()) { + ClipperLib::Clipper clipper; + clipper.AddPath(input, ClipperLib::ptSubject, true); + clipper.ReverseSolution(reverse_result); + clipper.Execute(ClipperLib::ctUnion, solution, filltype, filltype); + } + return solution; +} + +// Inner offset may split the source contour into multiple contours, but one shall not be inside the other. +ClipperLib::Paths fix_after_inner_offset(const ClipperLib::Path &input, ClipperLib::PolyFillType filltype, bool reverse_result) +{ + ClipperLib::Paths solution; + if (! input.empty()) { + ClipperLib::Clipper clipper; + clipper.AddPath(input, ClipperLib::ptSubject, true); + ClipperLib::IntRect r = clipper.GetBounds(); + r.left -= 10; r.top -= 10; r.right += 10; r.bottom += 10; + if (filltype == ClipperLib::pftPositive) + clipper.AddPath({ ClipperLib::IntPoint(r.left, r.bottom), ClipperLib::IntPoint(r.left, r.top), ClipperLib::IntPoint(r.right, r.top), ClipperLib::IntPoint(r.right, r.bottom) }, ClipperLib::ptSubject, true); + else + clipper.AddPath({ ClipperLib::IntPoint(r.left, r.bottom), ClipperLib::IntPoint(r.right, r.bottom), ClipperLib::IntPoint(r.right, r.top), ClipperLib::IntPoint(r.left, r.top) }, ClipperLib::ptSubject, true); + clipper.ReverseSolution(reverse_result); + clipper.Execute(ClipperLib::ctUnion, solution, filltype, filltype); + if (! solution.empty()) + solution.erase(solution.begin()); + } + return solution; +} + +ClipperLib::Path mittered_offset_path_scaled(const Points &contour, const std::vector &deltas, double miter_limit) +{ + assert(contour.size() == deltas.size()); +#ifndef NDEBUG + // Verify that the deltas are either all positive, or all negative. + bool positive = false; + bool negative = false; + for (float delta : deltas) + if (delta < 0.f) + negative = true; + else if (delta > 0.f) + positive = true; + assert(! (negative && positive)); +#endif /* NDEBUG */ + + ClipperLib::Path out; + + if (deltas.size() > 2) + { + out.reserve(contour.size() * 2); + + // Clamp miter limit to 2. + miter_limit = (miter_limit > 2.) ? 2. / (miter_limit * miter_limit) : 0.5; + + // perpenduclar vector + auto perp = [](const Vec2d &v) -> Vec2d { return Vec2d(v.y(), - v.x()); }; + + // Add a new point to the output, scale by CLIPPER_OFFSET_SCALE and round to ClipperLib::cInt. + auto add_offset_point = [&out](Vec2d pt) { + pt *= double(CLIPPER_OFFSET_SCALE); + pt += Vec2d(0.5 - (pt.x() < 0), 0.5 - (pt.y() < 0)); + out.emplace_back(ClipperLib::cInt(pt.x()), ClipperLib::cInt(pt.y())); + }; + + // Minimum edge length, squared. + double lmin = *std::max_element(deltas.begin(), deltas.end()) * CLIPPER_OFFSET_SHORTEST_EDGE_FACTOR; + double l2min = lmin * lmin; + // Minimum angle to consider two edges to be parallel. + double sin_min_parallel = EPSILON + 1. / double(CLIPPER_OFFSET_SCALE); + + // Find the last point further from pt by l2min. + Vec2d pt = contour.front().cast(); + size_t iprev = contour.size() - 1; + Vec2d ptprev; + for (; iprev > 0; -- iprev) { + ptprev = contour[iprev].cast(); + if ((ptprev - pt).squaredNorm() > l2min) + break; + } + + if (iprev != 0) { + size_t ilast = iprev; + // Normal to the (pt - ptprev) segment. + Vec2d nprev = perp(pt - ptprev).normalized(); + for (size_t i = 0; ; ) { + // Find the next point further from pt by l2min. + size_t j = i + 1; + Vec2d ptnext; + for (; j <= ilast; ++ j) { + ptnext = contour[j].cast(); + double l2 = (ptnext - pt).squaredNorm(); + if (l2 > l2min) + break; + } + if (j > ilast) + ptnext = contour.front().cast(); + + // Normal to the (ptnext - pt) segment. + Vec2d nnext = perp(ptnext - pt).normalized(); + + double delta = deltas[i]; + double sin_a = clamp(-1., 1., cross2(nprev, nnext)); + double convex = sin_a * delta; + if (convex <= - sin_min_parallel) { + // Concave corner. + add_offset_point(pt + nprev * delta); + add_offset_point(pt); + add_offset_point(pt + nnext * delta); + } else if (convex < sin_min_parallel) { + // Nearly parallel. + add_offset_point((nprev.dot(nnext) > 0.) ? (pt + nprev * delta) : pt); + } else { + // Convex corner + double dot = nprev.dot(nnext); + double r = 1. + dot; + if (r >= miter_limit) + add_offset_point(pt + (nprev + nnext) * (delta / r)); + else { + double dx = std::tan(std::atan2(sin_a, dot) / 4.); + Vec2d newpt1 = pt + (nprev - perp(nprev) * dx) * delta; + Vec2d newpt2 = pt + (nnext + perp(nnext) * dx) * delta; +#ifndef NDEBUG + Vec2d vedge = 0.5 * (newpt1 + newpt2) - pt; + double dist_norm = vedge.norm(); + assert(std::abs(dist_norm - delta) < EPSILON); +#endif /* NDEBUG */ + add_offset_point(newpt1); + add_offset_point(newpt2); + } + } + + if (i == ilast) + break; + + ptprev = pt; + nprev = nnext; + pt = ptnext; + i = j; + } + } + } + + return out; +} + +Polygons variable_offset_inner(const ExPolygon &expoly, const std::vector> &deltas, double miter_limit) +{ +#ifndef NDEBUG + // Verify that the deltas are all non positive. + for (const std::vector &ds : deltas) + for (float delta : ds) + assert(delta <= 0.); + assert(expoly.holes.size() + 1 == deltas.size()); +#endif /* NDEBUG */ + + // 1) Offset the outer contour. + ClipperLib::Paths contours = fix_after_inner_offset(mittered_offset_path_scaled(expoly.contour.points, deltas.front(), miter_limit), ClipperLib::pftNegative, true); + + // 2) Offset the holes one by one, collect the results. + ClipperLib::Paths holes; + holes.reserve(expoly.holes.size()); + for (const Polygon& hole : expoly.holes) + append(holes, fix_after_outer_offset(mittered_offset_path_scaled(hole, deltas[1 + &hole - expoly.holes.data()], miter_limit), ClipperLib::pftPositive, false)); + + // 3) Subtract holes from the contours. + ClipperLib::Paths output; + if (holes.empty()) + output = std::move(contours); + else { + ClipperLib::Clipper clipper; + clipper.Clear(); + clipper.AddPaths(contours, ClipperLib::ptSubject, true); + clipper.AddPaths(holes, ClipperLib::ptClip, true); + clipper.Execute(ClipperLib::ctDifference, output, ClipperLib::pftNonZero, ClipperLib::pftNonZero); + } + + // 4) Unscale the output. + unscaleClipperPolygons(output); + return ClipperPaths_to_Slic3rPolygons(output); +} + +Polygons variable_offset_outer(const ExPolygon &expoly, const std::vector> &deltas, double miter_limit) +{ +#ifndef NDEBUG + // Verify that the deltas are all non positive. +for (const std::vector& ds : deltas) + for (float delta : ds) + assert(delta >= 0.); + assert(expoly.holes.size() + 1 == deltas.size()); +#endif /* NDEBUG */ + + // 1) Offset the outer contour. + ClipperLib::Paths contours = fix_after_outer_offset(mittered_offset_path_scaled(expoly.contour.points, deltas.front(), miter_limit), ClipperLib::pftPositive, false); + + // 2) Offset the holes one by one, collect the results. + ClipperLib::Paths holes; + holes.reserve(expoly.holes.size()); + for (const Polygon& hole : expoly.holes) + append(holes, fix_after_inner_offset(mittered_offset_path_scaled(hole, deltas[1 + &hole - expoly.holes.data()], miter_limit), ClipperLib::pftPositive, true)); + + // 3) Subtract holes from the contours. + ClipperLib::Paths output; + if (holes.empty()) + output = std::move(contours); + else { + ClipperLib::Clipper clipper; + clipper.Clear(); + clipper.AddPaths(contours, ClipperLib::ptSubject, true); + clipper.AddPaths(holes, ClipperLib::ptClip, true); + clipper.Execute(ClipperLib::ctDifference, output, ClipperLib::pftNonZero, ClipperLib::pftNonZero); + } + + // 4) Unscale the output. + unscaleClipperPolygons(output); + return ClipperPaths_to_Slic3rPolygons(output); +} + +ExPolygons variable_offset_outer_ex(const ExPolygon &expoly, const std::vector> &deltas, double miter_limit) +{ +#ifndef NDEBUG + // Verify that the deltas are all non positive. +for (const std::vector& ds : deltas) + for (float delta : ds) + assert(delta >= 0.); + assert(expoly.holes.size() + 1 == deltas.size()); +#endif /* NDEBUG */ + + // 1) Offset the outer contour. + ClipperLib::Paths contours = fix_after_outer_offset(mittered_offset_path_scaled(expoly.contour.points, deltas.front(), miter_limit), ClipperLib::pftPositive, false); + + // 2) Offset the holes one by one, collect the results. + ClipperLib::Paths holes; + holes.reserve(expoly.holes.size()); + for (const Polygon& hole : expoly.holes) + append(holes, fix_after_inner_offset(mittered_offset_path_scaled(hole, deltas[1 + &hole - expoly.holes.data()], miter_limit), ClipperLib::pftPositive, true)); + + // 3) Subtract holes from the contours. + unscaleClipperPolygons(contours); + ExPolygons output; + if (holes.empty()) { + output.reserve(contours.size()); + for (ClipperLib::Path &path : contours) + output.emplace_back(ClipperPath_to_Slic3rPolygon(path)); + } else { + ClipperLib::Clipper clipper; + unscaleClipperPolygons(holes); + clipper.AddPaths(contours, ClipperLib::ptSubject, true); + clipper.AddPaths(holes, ClipperLib::ptClip, true); + ClipperLib::PolyTree polytree; + clipper.Execute(ClipperLib::ctDifference, polytree, ClipperLib::pftNonZero, ClipperLib::pftNonZero); + output = PolyTreeToExPolygons(polytree); + } + + return output; +} + + +ExPolygons variable_offset_inner_ex(const ExPolygon &expoly, const std::vector> &deltas, double miter_limit) +{ +#ifndef NDEBUG + // Verify that the deltas are all non positive. +for (const std::vector& ds : deltas) + for (float delta : ds) + assert(delta <= 0.); + assert(expoly.holes.size() + 1 == deltas.size()); +#endif /* NDEBUG */ + + // 1) Offset the outer contour. + ClipperLib::Paths contours = fix_after_inner_offset(mittered_offset_path_scaled(expoly.contour.points, deltas.front(), miter_limit), ClipperLib::pftNegative, false); + + // 2) Offset the holes one by one, collect the results. + ClipperLib::Paths holes; + holes.reserve(expoly.holes.size()); + for (const Polygon& hole : expoly.holes) + append(holes, fix_after_outer_offset(mittered_offset_path_scaled(hole, deltas[1 + &hole - expoly.holes.data()], miter_limit), ClipperLib::pftNegative, true)); + + // 3) Subtract holes from the contours. + unscaleClipperPolygons(contours); + ExPolygons output; + if (holes.empty()) { + output.reserve(contours.size()); + for (ClipperLib::Path &path : contours) + output.emplace_back(ClipperPath_to_Slic3rPolygon(path)); + } else { + ClipperLib::Clipper clipper; + unscaleClipperPolygons(holes); + clipper.AddPaths(contours, ClipperLib::ptSubject, true); + clipper.AddPaths(holes, ClipperLib::ptClip, true); + ClipperLib::PolyTree polytree; + clipper.Execute(ClipperLib::ctDifference, polytree, ClipperLib::pftNonZero, ClipperLib::pftNonZero); + output = PolyTreeToExPolygons(polytree); + } + + return output; +} + } diff --git a/src/libslic3r/ClipperUtils.hpp b/src/libslic3r/ClipperUtils.hpp index d8f8a8f94..5a41a6a90 100644 --- a/src/libslic3r/ClipperUtils.hpp +++ b/src/libslic3r/ClipperUtils.hpp @@ -238,6 +238,11 @@ void safety_offset(ClipperLib::Paths* paths); Polygons top_level_islands(const Slic3r::Polygons &polygons); +Polygons variable_offset_inner(const ExPolygon &expoly, const std::vector> &deltas, double miter_limit = 2.); +Polygons variable_offset_outer(const ExPolygon &expoly, const std::vector> &deltas, double miter_limit = 2.); +ExPolygons variable_offset_outer_ex(const ExPolygon &expoly, const std::vector> &deltas, double miter_limit = 2.); +ExPolygons variable_offset_inner_ex(const ExPolygon &expoly, const std::vector> &deltas, double miter_limit = 2.); + } #endif diff --git a/src/libslic3r/ExPolygon.hpp b/src/libslic3r/ExPolygon.hpp index c510b848f..08c4f7a07 100644 --- a/src/libslic3r/ExPolygon.hpp +++ b/src/libslic3r/ExPolygon.hpp @@ -301,6 +301,15 @@ inline bool expolygons_contain(ExPolygons &expolys, const Point &pt) return false; } +inline ExPolygons expolygons_simplify(const ExPolygons &expolys, double tolerance) +{ + ExPolygons out; + out.reserve(expolys.size()); + for (const ExPolygon &exp : expolys) + exp.simplify(tolerance, &out); + return out; +} + extern BoundingBox get_extents(const ExPolygon &expolygon); extern BoundingBox get_extents(const ExPolygons &expolygons); extern BoundingBox get_extents_rotated(const ExPolygon &poly, double angle); diff --git a/src/libslic3r/Polygon.hpp b/src/libslic3r/Polygon.hpp index 19be3068b..ad1b32feb 100644 --- a/src/libslic3r/Polygon.hpp +++ b/src/libslic3r/Polygon.hpp @@ -102,6 +102,15 @@ inline void polygons_append(Polygons &dst, Polygons &&src) } } +inline Polygons polygons_simplify(const Polygons &polys, double tolerance) +{ + Polygons out; + out.reserve(polys.size()); + for (const Polygon &p : polys) + polygons_append(out, p.simplify(tolerance)); + return out; +} + inline void polygons_rotate(Polygons &polys, double angle) { const double cos_angle = cos(angle); -- cgit v1.2.3 From f8dc74374c9f64e0f09c01b811deb3b4457598df Mon Sep 17 00:00:00 2001 From: bubnikv Date: Fri, 25 Oct 2019 17:07:55 +0200 Subject: Ported various clipper unit tests from Perl to C++, the clipper Perl unit tests were removed. --- src/libslic3r/ExPolygon.hpp | 5 +++++ src/libslic3r/Polygon.hpp | 7 ++++++- 2 files changed, 11 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/libslic3r/ExPolygon.hpp b/src/libslic3r/ExPolygon.hpp index 08c4f7a07..7833c9c91 100644 --- a/src/libslic3r/ExPolygon.hpp +++ b/src/libslic3r/ExPolygon.hpp @@ -28,6 +28,8 @@ public: explicit ExPolygon(Polygon &&contour, Polygon &&hole) : contour(std::move(contour)) { holes.emplace_back(std::move(hole)); } explicit ExPolygon(const Points &contour, const Points &hole) : contour(contour) { holes.emplace_back(hole); } explicit ExPolygon(Points &&contour, Polygon &&hole) : contour(std::move(contour)) { holes.emplace_back(std::move(hole)); } + ExPolygon(std::initializer_list contour) : contour(contour) {} + ExPolygon(std::initializer_list contour, std::initializer_list hole) : contour(contour), holes({ hole }) {} ExPolygon& operator=(const ExPolygon &other) { contour = other.contour; holes = other.holes; return *this; } ExPolygon& operator=(ExPolygon &&other) { contour = std::move(other.contour); holes = std::move(other.holes); return *this; } @@ -77,6 +79,9 @@ public: Lines lines() const; }; +inline bool operator==(const ExPolygon &lhs, const ExPolygon &rhs) { return lhs.contour == rhs.contour && lhs.holes == rhs.holes; } +inline bool operator!=(const ExPolygon &lhs, const ExPolygon &rhs) { return lhs.contour != rhs.contour || lhs.holes != rhs.holes; } + // Count a nuber of polygons stored inside the vector of expolygons. // Useful for allocating space for polygons when converting expolygons to polygons. inline size_t number_polygons(const ExPolygons &expolys) diff --git a/src/libslic3r/Polygon.hpp b/src/libslic3r/Polygon.hpp index ad1b32feb..4d53e97e1 100644 --- a/src/libslic3r/Polygon.hpp +++ b/src/libslic3r/Polygon.hpp @@ -22,7 +22,8 @@ public: const Point& operator[](Points::size_type idx) const { return this->points[idx]; } Polygon() {} - explicit Polygon(const Points &points): MultiPoint(points) {} + explicit Polygon(const Points &points) : MultiPoint(points) {} + Polygon(std::initializer_list points) : MultiPoint(points) {} Polygon(const Polygon &other) : MultiPoint(other.points) {} Polygon(Polygon &&other) : MultiPoint(std::move(other.points)) {} static Polygon new_scale(const std::vector &points) { @@ -66,6 +67,10 @@ public: Point point_projection(const Point &point) const; }; +inline bool operator==(const Polygon &lhs, const Polygon &rhs) { return lhs.points == rhs.points; } +inline bool operator!=(const Polygon &lhs, const Polygon &rhs) { return lhs.points != rhs.points; } + + extern BoundingBox get_extents(const Polygon &poly); extern BoundingBox get_extents(const Polygons &polygons); extern BoundingBox get_extents_rotated(const Polygon &poly, double angle); -- cgit v1.2.3 From 9e8ce66f70ce29a4badd54a6e3d8688ed36f903f Mon Sep 17 00:00:00 2001 From: bubnikv Date: Fri, 25 Oct 2019 19:06:40 +0200 Subject: Fix / improvement of unit tests. --- src/libslic3r/GCode/SpiralVase.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/libslic3r/GCode/SpiralVase.hpp b/src/libslic3r/GCode/SpiralVase.hpp index 7872b1d3c..e35ca640c 100644 --- a/src/libslic3r/GCode/SpiralVase.hpp +++ b/src/libslic3r/GCode/SpiralVase.hpp @@ -1,8 +1,8 @@ #ifndef slic3r_SpiralVase_hpp_ #define slic3r_SpiralVase_hpp_ -#include "libslic3r.h" -#include "GCodeReader.hpp" +#include "../libslic3r.h" +#include "../GCodeReader.hpp" namespace Slic3r { -- cgit v1.2.3 From 8b5561aec7e6e2411396b3bf6b67cb333319687f Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Tue, 29 Oct 2019 10:40:34 +0100 Subject: Fixed several warnings --- src/libslic3r/LayerRegion.cpp | 1 - src/libslic3r/PolygonTrimmer.cpp | 1 - src/slic3r/Config/Version.cpp | 5 ++--- src/slic3r/GUI/BackgroundSlicingProcess.cpp | 1 + src/slic3r/GUI/GLCanvas3D.cpp | 2 +- src/slic3r/GUI/GUI_App.hpp | 9 ++++----- src/slic3r/GUI/GUI_ObjectList.cpp | 4 ++-- src/slic3r/GUI/OptionsGroup.cpp | 2 +- src/slic3r/GUI/Plater.cpp | 4 ++-- src/slic3r/GUI/wxExtensions.cpp | 2 +- 10 files changed, 14 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/libslic3r/LayerRegion.cpp b/src/libslic3r/LayerRegion.cpp index 658bcf709..35acaf998 100644 --- a/src/libslic3r/LayerRegion.cpp +++ b/src/libslic3r/LayerRegion.cpp @@ -88,7 +88,6 @@ void LayerRegion::make_perimeters(const SurfaceCollection &slices, SurfaceCollec void LayerRegion::process_external_surfaces(const Layer *lower_layer, const Polygons *lower_layer_covered) { - const Surfaces &surfaces = this->fill_surfaces.surfaces; const bool has_infill = this->region()->config().fill_density.value > 0.; const float margin = float(scale_(EXTERNAL_INFILL_MARGIN)); diff --git a/src/libslic3r/PolygonTrimmer.cpp b/src/libslic3r/PolygonTrimmer.cpp index 3e3c9b498..a2779b666 100644 --- a/src/libslic3r/PolygonTrimmer.cpp +++ b/src/libslic3r/PolygonTrimmer.cpp @@ -12,7 +12,6 @@ TrimmedLoop trim_loop(const Polygon &loop, const EdgeGrid::Grid &grid) TrimmedLoop out; if (loop.size() >= 2) { - size_t cnt = loop.points.size(); struct Visitor { Visitor(const EdgeGrid::Grid &grid, const Slic3r::Point *pt_prev, const Slic3r::Point *pt_this) : grid(grid), pt_prev(pt_prev), pt_this(pt_this) {} diff --git a/src/slic3r/Config/Version.cpp b/src/slic3r/Config/Version.cpp index 3f8f960f1..da522dd5e 100644 --- a/src/slic3r/Config/Version.cpp +++ b/src/slic3r/Config/Version.cpp @@ -235,9 +235,9 @@ size_t Index::load(const boost::filesystem::path &path) value = left_trim(value + 1); *key_end = 0; boost::optional semver; - if (maybe_semver) + if (maybe_semver) semver = Semver::parse(key); - if (key_value_pair) { + if (key_value_pair) { if (semver) throw file_parser_error("Key cannot be a semantic version", path, idx_line);\ // Verify validity of the key / value pair. @@ -288,7 +288,6 @@ Index::const_iterator Index::find(const Semver &ver) const Index::const_iterator Index::recommended() const { - int idx = -1; const_iterator highest = this->end(); for (const_iterator it = this->begin(); it != this->end(); ++ it) if (it->is_current_slic3r_supported() && diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.cpp b/src/slic3r/GUI/BackgroundSlicingProcess.cpp index a1db6884e..6c138d4d0 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.cpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.cpp @@ -55,6 +55,7 @@ bool BackgroundSlicingProcess::select_technology(PrinterTechnology tech) switch (tech) { case ptFFF: m_print = m_fff_print; break; case ptSLA: m_print = m_sla_print; break; + default: assert(false); break; } changed = true; } diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index c55d64b47..268b4dc30 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1926,7 +1926,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re if (it->new_geometry()) { // New volume. unsigned int old_id = find_old_volume_id(it->composite_id); - if (old_id != -1) + if (old_id != (unsigned int)-1) map_glvolume_old_to_new[old_id] = m_volumes.volumes.size(); m_volumes.load_object_volume(&model_object, obj_idx, volume_idx, instance_idx, m_color_by, m_initialized); m_volumes.volumes.back()->geometry_id = key.geometry_id; diff --git a/src/slic3r/GUI/GUI_App.hpp b/src/slic3r/GUI/GUI_App.hpp index c5ddc0152..9bfc34543 100644 --- a/src/slic3r/GUI/GUI_App.hpp +++ b/src/slic3r/GUI/GUI_App.hpp @@ -87,7 +87,7 @@ class GUI_App : public wxApp wxFont m_bold_font; wxFont m_normal_font; - size_t m_em_unit; // width of a "m"-symbol in pixels for current system font + int m_em_unit; // width of a "m"-symbol in pixels for current system font // Note: for 100% Scale m_em_unit = 10 -> it's a good enough coefficient for a size setting of controls std::unique_ptr m_wxLocale; @@ -105,7 +105,7 @@ public: bool initialized() const { return m_initialized; } GUI_App(); - ~GUI_App(); + ~GUI_App() override; static unsigned get_colour_approx_luma(const wxColour &colour); static bool dark_mode(); @@ -124,8 +124,7 @@ public: const wxFont& small_font() { return m_small_font; } const wxFont& bold_font() { return m_bold_font; } const wxFont& normal_font() { return m_normal_font; } - size_t em_unit() const { return m_em_unit; } - void set_em_unit(const size_t em_unit) { m_em_unit = em_unit; } + int em_unit() const { return m_em_unit; } float toolbar_icon_scale(const bool is_limited = false) const; void recreate_GUI(); @@ -155,7 +154,7 @@ public: // Translate the language code to a code, for which Prusa Research maintains translations. Defaults to "en_US". wxString current_language_code_safe() const; - virtual bool OnExceptionInMainLoop(); + virtual bool OnExceptionInMainLoop() override; #ifdef __APPLE__ // wxWidgets override to get an event on open files. diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index dc48a218c..a88980a8d 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -445,7 +445,7 @@ void ObjectList::update_extruder_values_for_items(const size_t max_extruder) auto object = (*m_objects)[i]; wxString extruder; if (!object->config.has("extruder") || - object->config.option("extruder")->value > max_extruder) + size_t(object->config.option("extruder")->value) > max_extruder) extruder = _(L("default")); else extruder = wxString::Format("%d", object->config.option("extruder")->value); @@ -457,7 +457,7 @@ void ObjectList::update_extruder_values_for_items(const size_t max_extruder) item = m_objects_model->GetItemByVolumeId(i, id); if (!item) continue; if (!object->volumes[id]->config.has("extruder") || - object->volumes[id]->config.option("extruder")->value > max_extruder) + size_t(object->volumes[id]->config.option("extruder")->value) > max_extruder) extruder = _(L("default")); else extruder = wxString::Format("%d", object->volumes[id]->config.option("extruder")->value); diff --git a/src/slic3r/GUI/OptionsGroup.cpp b/src/slic3r/GUI/OptionsGroup.cpp index 698c1e034..8b6f5bc30 100644 --- a/src/slic3r/GUI/OptionsGroup.cpp +++ b/src/slic3r/GUI/OptionsGroup.cpp @@ -233,7 +233,7 @@ void OptionsGroup::append_line(const Line& line, wxStaticText** full_Label/* = n add_undo_buttuns_to_sizer(sizer, field); if (is_window_field(field)) - sizer->Add(field->getWindow(), option.opt.full_width ? 1 : 0, //(option.opt.full_width ? wxEXPAND : 0) | + sizer->Add(field->getWindow(), option.opt.full_width ? 1 : 0, //(option.opt.full_width ? wxEXPAND : 0) | wxBOTTOM | wxTOP | (option.opt.full_width ? wxEXPAND : wxALIGN_CENTER_VERTICAL), (wxOSX || !staticbox) ? 0 : 2); if (is_sizer_field(field)) sizer->Add(field->getSizer(), 1, /*(*/option.opt.full_width ? wxEXPAND : /*0) |*/ wxALIGN_CENTER_VERTICAL, 0); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index cca164ca3..90529f88c 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -4791,7 +4791,7 @@ bool Plater::undo_redo_string_getter(const bool is_undo, int idx, const char** o const std::vector& ss_stack = p->undo_redo_stack().snapshots(); const int idx_in_ss_stack = p->get_active_snapshot_index() + (is_undo ? -(++idx) : idx); - if (0 < idx_in_ss_stack && idx_in_ss_stack < ss_stack.size() - 1) { + if (0 < idx_in_ss_stack && (size_t)idx_in_ss_stack < ss_stack.size() - 1) { *out_text = ss_stack[idx_in_ss_stack].name.c_str(); return true; } @@ -4804,7 +4804,7 @@ void Plater::undo_redo_topmost_string_getter(const bool is_undo, std::string& ou const std::vector& ss_stack = p->undo_redo_stack().snapshots(); const int idx_in_ss_stack = p->get_active_snapshot_index() + (is_undo ? -1 : 0); - if (0 < idx_in_ss_stack && idx_in_ss_stack < ss_stack.size() - 1) { + if (0 < idx_in_ss_stack && (size_t)idx_in_ss_stack < ss_stack.size() - 1) { out_text = ss_stack[idx_in_ss_stack].name; return; } diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index 06e37fb4f..eb47fd208 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -1020,7 +1020,7 @@ wxDataViewItem ObjectDataViewModel::Delete(const wxDataViewItem &item) node_parent->GetChildren().Remove(node); if (id > 0) { - if(id == node_parent->GetChildCount()) id--; + if (size_t(id) == node_parent->GetChildCount()) id--; ret_item = wxDataViewItem(node_parent->GetChildren().Item(id)); } -- cgit v1.2.3 From ffcf25e5cb0fab7b527c9bbffe34fc65d9a6d38b Mon Sep 17 00:00:00 2001 From: YuSanka Date: Tue, 29 Oct 2019 13:07:57 +0100 Subject: Fix for #3108 --- src/slic3r/GUI/Field.cpp | 40 +++++++++++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/slic3r/GUI/Field.cpp b/src/slic3r/GUI/Field.cpp index 07d75c947..42e3448fc 100644 --- a/src/slic3r/GUI/Field.cpp +++ b/src/slic3r/GUI/Field.cpp @@ -150,7 +150,13 @@ void Field::get_value_by_opt_type(wxString& str, const bool check_value/* = true case coFloat:{ if (m_opt.type == coPercent && !str.IsEmpty() && str.Last() == '%') str.RemoveLast(); - else if (check_value && !str.IsEmpty() && str.Last() == '%') { + else if (!str.IsEmpty() && str.Last() == '%') + { + if (!check_value) { + m_value.clear(); + break; + } + wxString label = m_Label->GetLabel(); if (label.Last() == '\n') label.RemoveLast(); while (label.Last() == ' ') label.RemoveLast(); @@ -169,13 +175,21 @@ void Field::get_value_by_opt_type(wxString& str, const bool check_value/* = true { if (m_opt.nullable && str == na_value()) val = ConfigOptionFloatsNullable::nil_value(); - else if (check_value && !str.ToCDouble(&val)) + else if (!str.ToCDouble(&val)) { + if (!check_value) { + m_value.clear(); + break; + } show_error(m_parent, _(L("Invalid numeric input."))); set_value(double_to_string(val), true); } - if (check_value && (m_opt.min > val || val > m_opt.max)) + if (m_opt.min > val || val > m_opt.max) { + if (!check_value) { + m_value.clear(); + break; + } show_error(m_parent, _(L("Input value is out of range"))); if (m_opt.min > val) val = m_opt.min; if (val > m_opt.max) val = m_opt.max; @@ -192,15 +206,24 @@ void Field::get_value_by_opt_type(wxString& str, const bool check_value/* = true double val = 0.; // Replace the first occurence of comma in decimal number. str.Replace(",", ".", false); - if (check_value && !str.ToCDouble(&val)) + if (!str.ToCDouble(&val)) { + if (!check_value) { + m_value.clear(); + break; + } show_error(m_parent, _(L("Invalid numeric input."))); set_value(double_to_string(val), true); } - else if (check_value && ((m_opt.sidetext.rfind("mm/s") != std::string::npos && val > m_opt.max) || + else if (((m_opt.sidetext.rfind("mm/s") != std::string::npos && val > m_opt.max) || (m_opt.sidetext.rfind("mm ") != std::string::npos && val > 1)) && (m_value.empty() || std::string(str.ToUTF8().data()) != boost::any_cast(m_value))) { + if (!check_value) { + m_value.clear(); + break; + } + const std::string sidetext = m_opt.sidetext.rfind("mm/s") != std::string::npos ? "mm/s" : "mm"; const wxString stVal = double_to_string(val, 2); const wxString msg_text = wxString::Format(_(L("Do you mean %s%% instead of %s %s?\n" @@ -351,6 +374,7 @@ bool TextCtrl::value_was_changed() boost::any val = m_value; wxString ret_str = static_cast(window)->GetValue(); // update m_value! + // ret_str might be changed inside get_value_by_opt_type get_value_by_opt_type(ret_str); switch (m_opt.type) { @@ -396,8 +420,10 @@ void TextCtrl::set_value(const boost::any& value, bool change_event/* = false*/) if (!change_event) { wxString ret_str = static_cast(window)->GetValue(); - // update m_value to correct work of next value_was_changed(), - // but don't check/change inputed value and don't show a warning message + /* Update m_value to correct work of next value_was_changed(). + * But after checking of entered value, don't fix the "incorrect" value and don't show a warning message, + * just clear m_value in this case. + */ get_value_by_opt_type(ret_str, false); } } -- cgit v1.2.3 From b3f53c96c7a5cad8ccaf60b0047d1b195826a32b Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Wed, 30 Oct 2019 08:28:40 +0100 Subject: Fixed update of 3D preview layout after changing printer after slicing --- src/slic3r/GUI/GUI_Preview.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp index b6350bcab..d89ac1bcb 100644 --- a/src/slic3r/GUI/GUI_Preview.cpp +++ b/src/slic3r/GUI/GUI_Preview.cpp @@ -375,6 +375,8 @@ void Preview::load_print(bool keep_z_range) load_print_as_fff(keep_z_range); else if (tech == ptSLA) load_print_as_sla(); + + Layout(); } void Preview::reload_print(bool keep_volumes) -- cgit v1.2.3 From ba39ee6f12821af35a1c5623d772f1f0a5c98e1b Mon Sep 17 00:00:00 2001 From: bubnikv Date: Wed, 30 Oct 2019 10:18:56 +0100 Subject: EdgeGrid::signed_distance_edges() to provide the pedal point. Removed 20_print.t test. --- src/libslic3r/EdgeGrid.cpp | 138 ++++++++++++++++++++++++++++++++++++++++++++- src/libslic3r/EdgeGrid.hpp | 14 ++++- 2 files changed, 148 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/libslic3r/EdgeGrid.cpp b/src/libslic3r/EdgeGrid.cpp index a97210da6..5e19c3b08 100644 --- a/src/libslic3r/EdgeGrid.cpp +++ b/src/libslic3r/EdgeGrid.cpp @@ -113,6 +113,7 @@ void EdgeGrid::Grid::create(const ExPolygonCollection &expolygons, coord_t resol // m_contours has been initialized. Now fill in the edge grid. void EdgeGrid::Grid::create_from_m_contours(coord_t resolution) { + assert(resolution > 0); // 1) Measure the bounding box. for (size_t i = 0; i < m_contours.size(); ++ i) { const Slic3r::Points &pts = *m_contours[i]; @@ -1017,8 +1018,139 @@ float EdgeGrid::Grid::signed_distance_bilinear(const Point &pt) const return f; } - -bool EdgeGrid::Grid::signed_distance_edges(const Point &pt, coord_t search_radius, coordf_t &result_min_dist, bool *pon_segment) const { + +EdgeGrid::Grid::ClosestPointResult EdgeGrid::Grid::closest_point(const Point &pt, coord_t search_radius) const +{ + BoundingBox bbox; + bbox.min = bbox.max = Point(pt(0) - m_bbox.min(0), pt(1) - m_bbox.min(1)); + bbox.defined = true; + // Upper boundary, round to grid and test validity. + bbox.max(0) += search_radius; + bbox.max(1) += search_radius; + ClosestPointResult result; + if (bbox.max(0) < 0 || bbox.max(1) < 0) + return result; + bbox.max(0) /= m_resolution; + bbox.max(1) /= m_resolution; + if ((size_t)bbox.max(0) >= m_cols) + bbox.max(0) = m_cols - 1; + if ((size_t)bbox.max(1) >= m_rows) + bbox.max(1) = m_rows - 1; + // Lower boundary, round to grid and test validity. + bbox.min(0) -= search_radius; + bbox.min(1) -= search_radius; + if (bbox.min(0) < 0) + bbox.min(0) = 0; + if (bbox.min(1) < 0) + bbox.min(1) = 0; + bbox.min(0) /= m_resolution; + bbox.min(1) /= m_resolution; + // Is the interval empty? + if (bbox.min(0) > bbox.max(0) || + bbox.min(1) > bbox.max(1)) + return result; + // Traverse all cells in the bounding box. + double d_min = double(search_radius); + // Signum of the distance field at pt. + int sign_min = 0; + double l2_seg_min = 1.; + for (int r = bbox.min(1); r <= bbox.max(1); ++ r) { + for (int c = bbox.min(0); c <= bbox.max(0); ++ c) { + const Cell &cell = m_cells[r * m_cols + c]; + for (size_t i = cell.begin; i < cell.end; ++ i) { + const size_t contour_idx = m_cell_data[i].first; + const Slic3r::Points &pts = *m_contours[contour_idx]; + size_t ipt = m_cell_data[i].second; + // End points of the line segment. + const Slic3r::Point &p1 = pts[ipt]; + const Slic3r::Point &p2 = pts[(ipt + 1 == pts.size()) ? 0 : ipt + 1]; + const Slic3r::Point v_seg = p2 - p1; + const Slic3r::Point v_pt = pt - p1; + // dot(p2-p1, pt-p1) + int64_t t_pt = int64_t(v_seg(0)) * int64_t(v_pt(0)) + int64_t(v_seg(1)) * int64_t(v_pt(1)); + // l2 of seg + int64_t l2_seg = int64_t(v_seg(0)) * int64_t(v_seg(0)) + int64_t(v_seg(1)) * int64_t(v_seg(1)); + if (t_pt < 0) { + // Closest to p1. + double dabs = sqrt(int64_t(v_pt(0)) * int64_t(v_pt(0)) + int64_t(v_pt(1)) * int64_t(v_pt(1))); + if (dabs < d_min) { + // Previous point. + const Slic3r::Point &p0 = pts[(ipt == 0) ? (pts.size() - 1) : ipt - 1]; + Slic3r::Point v_seg_prev = p1 - p0; + int64_t t2_pt = int64_t(v_seg_prev(0)) * int64_t(v_pt(0)) + int64_t(v_seg_prev(1)) * int64_t(v_pt(1)); + if (t2_pt > 0) { + // Inside the wedge between the previous and the next segment. + d_min = dabs; + // Set the signum depending on whether the vertex is convex or reflex. + int64_t det = int64_t(v_seg_prev(0)) * int64_t(v_seg(1)) - int64_t(v_seg_prev(1)) * int64_t(v_seg(0)); + assert(det != 0); + sign_min = (det > 0) ? 1 : -1; + result.contour_idx = contour_idx; + result.start_point_idx = ipt; + result.t = 0.; +#ifndef NDEBUG + Vec2d vfoot = (p1 - pt).cast(); + double dist_foot = vfoot.norm(); + double dist_foot_err = dist_foot - d_min; + assert(std::abs(dist_foot_err) < 1e-7 * d_min); +#endif /* NDEBUG */ + } + } + } + else if (t_pt > l2_seg) { + // Closest to p2. Then p2 is the starting point of another segment, which shall be discovered in the same cell. + continue; + } else { + // Closest to the segment. + assert(t_pt >= 0 && t_pt <= l2_seg); + int64_t d_seg = int64_t(v_seg(1)) * int64_t(v_pt(0)) - int64_t(v_seg(0)) * int64_t(v_pt(1)); + double d = double(d_seg) / sqrt(double(l2_seg)); + double dabs = std::abs(d); + if (dabs < d_min) { + d_min = dabs; + sign_min = (d_seg < 0) ? -1 : ((d_seg == 0) ? 0 : 1); + l2_seg_min = l2_seg; + result.contour_idx = contour_idx; + result.start_point_idx = ipt; + result.t = t_pt; +#ifndef NDEBUG + Vec2d foot = p1.cast() * (1. - result.t / l2_seg_min) + p2.cast() * (result.t / l2_seg_min); + Vec2d vfoot = foot - pt.cast(); + double dist_foot = vfoot.norm(); + double dist_foot_err = dist_foot - d_min; + assert(std::abs(dist_foot_err) < 1e-7 * d_min); +#endif /* NDEBUG */ + } + } + } + } + } + if (result.contour_idx != -1 && d_min <= double(search_radius)) { + result.distance = d_min * sign_min; + result.t /= l2_seg_min; + assert(result.t >= 0. && result.t < 1.); +#ifndef NDEBUG + { + const Slic3r::Points &pts = *m_contours[result.contour_idx]; + const Slic3r::Point &p1 = pts[result.start_point_idx]; + const Slic3r::Point &p2 = pts[(result.start_point_idx + 1 == pts.size()) ? 0 : result.start_point_idx + 1]; + Vec2d vfoot; + if (result.t == 0) + vfoot = p1.cast() - pt.cast(); + else + vfoot = p1.cast() * (1. - result.t) + p2.cast() * result.t - pt.cast(); + double dist_foot = vfoot.norm(); + double dist_foot_err = dist_foot - std::abs(result.distance); + assert(std::abs(dist_foot_err) < 1e-7 * std::abs(result.distance)); + } +#endif /* NDEBUG */ + } else + result = ClosestPointResult(); + return result; +} + +bool EdgeGrid::Grid::signed_distance_edges(const Point &pt, coord_t search_radius, coordf_t &result_min_dist, bool *pon_segment) const +{ BoundingBox bbox; bbox.min = bbox.max = Point(pt(0) - m_bbox.min(0), pt(1) - m_bbox.min(1)); bbox.defined = true; @@ -1047,7 +1179,7 @@ bool EdgeGrid::Grid::signed_distance_edges(const Point &pt, coord_t search_radiu bbox.min(1) > bbox.max(1)) return false; // Traverse all cells in the bounding box. - float d_min = search_radius; + double d_min = double(search_radius); // Signum of the distance field at pt. int sign_min = 0; bool on_segment = false; diff --git a/src/libslic3r/EdgeGrid.hpp b/src/libslic3r/EdgeGrid.hpp index cad20e07b..38a7d8542 100644 --- a/src/libslic3r/EdgeGrid.hpp +++ b/src/libslic3r/EdgeGrid.hpp @@ -46,7 +46,19 @@ public: float signed_distance_bilinear(const Point &pt) const; // Calculate a signed distance to the contours in search_radius from the point. - bool signed_distance_edges(const Point &pt, coord_t search_radius, coordf_t &result_min_dist, bool *pon_segment = NULL) const; + struct ClosestPointResult { + size_t contour_idx = size_t(-1); + size_t start_point_idx = size_t(-1); + // Signed distance to the closest point. + double distance = std::numeric_limits::max(); + // Parameter of the closest point on edge starting with start_point_idx <0, 1) + double t = 0.; + + bool valid() const { return contour_idx != size_t(-1); } + }; + ClosestPointResult closest_point(const Point &pt, coord_t search_radius) const; + + bool signed_distance_edges(const Point &pt, coord_t search_radius, coordf_t &result_min_dist, bool *pon_segment = nullptr) const; // Calculate a signed distance to the contours in search_radius from the point. If no edge is found in search_radius, // return an interpolated value from m_signed_distance_field, if it exists. -- cgit v1.2.3 From d632d91e798686a6e46abd7ba2a823eda7ac64ae Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Thu, 31 Oct 2019 15:05:39 +0100 Subject: WipeTower.cpp: The M220 B/R gcode is only emitted for Marlin firmware flavor The extended gcode is now only supported by Prusa (https://github.com/prusa3d/PrusaSlicer/issues/3114) A pull request https://github.com/MarlinFirmware/Marlin/pull/15739 aims to extend the gcode in upstream Marlin as well --- src/libslic3r/GCode/WipeTower.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/libslic3r/GCode/WipeTower.cpp b/src/libslic3r/GCode/WipeTower.cpp index b464a39b8..73dc91c40 100644 --- a/src/libslic3r/GCode/WipeTower.cpp +++ b/src/libslic3r/GCode/WipeTower.cpp @@ -331,15 +331,18 @@ public: // Let the firmware back up the active speed override value. WipeTowerWriter& speed_override_backup() - { - m_gcode += "M220 B\n"; + { + // This is only supported by Prusa at this point (https://github.com/prusa3d/PrusaSlicer/issues/3114) + if (m_gcode_flavor == gcfMarlin) + m_gcode += "M220 B\n"; return *this; } // Let the firmware restore the active speed override value. WipeTowerWriter& speed_override_restore() { - m_gcode += "M220 R\n"; + if (m_gcode_flavor == gcfMarlin) + m_gcode += "M220 R\n"; return *this; } -- cgit v1.2.3 From d729315de389533103a1d6f298c34da3e86a6ff2 Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Fri, 1 Nov 2019 10:51:26 +0100 Subject: Fix g-code export to permissionless filesystems Fix #2521 Fix #3102 --- src/libslic3r/utils.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/libslic3r/utils.cpp b/src/libslic3r/utils.cpp index 8d2a6a866..678ad9ed2 100644 --- a/src/libslic3r/utils.cpp +++ b/src/libslic3r/utils.cpp @@ -424,14 +424,19 @@ int copy_file(const std::string &from, const std::string &to) static const auto perms = boost::filesystem::owner_read | boost::filesystem::owner_write | boost::filesystem::group_read | boost::filesystem::others_read; // aka 644 // Make sure the file has correct permission both before and after we copy over it. - try { - if (boost::filesystem::exists(target)) - boost::filesystem::permissions(target, perms); - boost::filesystem::copy_file(source, target, boost::filesystem::copy_option::overwrite_if_exists); - boost::filesystem::permissions(target, perms); - } catch (std::exception & /* ex */) { + // NOTE: error_code variants are used here to supress expception throwing. + // Error code of permission() calls is ignored on purpose - if they fail, + // the copy_file() function will fail appropriately and we don't want the permission() + // calls to cause needless failures on permissionless filesystems (ie. FATs on SD cards etc.) + // or when the target file doesn't exist. + boost::system::error_code ec; + boost::filesystem::permissions(target, perms, ec); + boost::filesystem::copy_file(source, target, boost::filesystem::copy_option::overwrite_if_exists, ec); + if (ec) { return -1; } + boost::filesystem::permissions(target, perms, ec); + return 0; } -- cgit v1.2.3 From 59c128d9fdcd602aecdf52337932c40e60bda13e Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Fri, 1 Nov 2019 15:13:05 +0100 Subject: Fix broken partial arrange --- src/libslic3r/Arrange.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/libslic3r/Arrange.cpp b/src/libslic3r/Arrange.cpp index aed6e41f7..3fa7e1841 100644 --- a/src/libslic3r/Arrange.cpp +++ b/src/libslic3r/Arrange.cpp @@ -375,7 +375,7 @@ public: for(unsigned idx = 0; idx < fixeditems.size(); ++idx) { Item& itm = fixeditems[idx]; - itm.markAsFixedInBin(0); + itm.markAsFixedInBin(itm.binId()); } m_pck.configure(m_pconf); -- cgit v1.2.3 From a72ac57fab54771ab583aa573086ef547ff53431 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Fri, 1 Nov 2019 19:59:09 +0100 Subject: adaptive elpehant foot compensation, fixing GH issues #1757 #2085 #2132 #2423 #2502 #2156 #2773 #2828 #2998 #3001 --- src/libslic3r/CMakeLists.txt | 2 + src/libslic3r/ClipperUtils.cpp | 16 ++ src/libslic3r/EdgeGrid.cpp | 6 +- src/libslic3r/EdgeGrid.hpp | 19 +- src/libslic3r/ElephantFootCompensation.cpp | 320 +++++++++++++++++++++++++++++ src/libslic3r/ElephantFootCompensation.hpp | 16 ++ src/libslic3r/GCode.cpp | 2 +- src/libslic3r/Layer.cpp | 8 +- src/libslic3r/Polygon.cpp | 5 + src/libslic3r/Polygon.hpp | 2 +- src/libslic3r/PolygonTrimmer.cpp | 4 +- src/libslic3r/PrintObject.cpp | 47 +---- src/libslic3r/SVG.cpp | 4 + src/libslic3r/SVG.hpp | 10 +- 14 files changed, 410 insertions(+), 51 deletions(-) create mode 100644 src/libslic3r/ElephantFootCompensation.cpp create mode 100644 src/libslic3r/ElephantFootCompensation.hpp (limited to 'src') diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index 8b162a1d5..0388b1ac0 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -22,6 +22,8 @@ add_library(libslic3r STATIC Config.hpp EdgeGrid.cpp EdgeGrid.hpp + ElephantFootCompensation.cpp + ElephantFootCompensation.hpp ExPolygon.cpp ExPolygon.hpp ExPolygonCollection.cpp diff --git a/src/libslic3r/ClipperUtils.cpp b/src/libslic3r/ClipperUtils.cpp index 55bb4b446..3db2f1f00 100644 --- a/src/libslic3r/ClipperUtils.cpp +++ b/src/libslic3r/ClipperUtils.cpp @@ -1060,6 +1060,22 @@ ClipperLib::Path mittered_offset_path_scaled(const Points &contour, const std::v } } +#if 0 + { + ClipperLib::Path polytmp(out); + unscaleClipperPolygon(polytmp); + Slic3r::Polygon offsetted = ClipperPath_to_Slic3rPolygon(polytmp); + BoundingBox bbox = get_extents(contour); + bbox.merge(get_extents(offsetted)); + static int iRun = 0; + SVG svg(debug_out_path("mittered_offset_path_scaled-%d.svg", iRun ++).c_str(), bbox); + svg.draw_outline(Polygon(contour), "blue", scale_(0.01)); + svg.draw_outline(offsetted, "red", scale_(0.01)); + svg.draw(contour, "blue", scale_(0.03)); + svg.draw((Points)offsetted, "blue", scale_(0.03)); + } +#endif + return out; } diff --git a/src/libslic3r/EdgeGrid.cpp b/src/libslic3r/EdgeGrid.cpp index 5e19c3b08..52ac4a0aa 100644 --- a/src/libslic3r/EdgeGrid.cpp +++ b/src/libslic3r/EdgeGrid.cpp @@ -282,7 +282,11 @@ void EdgeGrid::Grid::create_from_m_contours(coord_t resolution) Visitor(std::vector> &cell_data, std::vector &cells, size_t cols) : cell_data(cell_data), cells(cells), cols(cols), i(0), j(0) {} - void operator()(coord_t iy, coord_t ix) { cell_data[cells[iy*cols + ix].end++] = std::pair(i, j); } + inline bool operator()(coord_t iy, coord_t ix) { + cell_data[cells[iy*cols + ix].end++] = std::pair(i, j); + // Continue traversing the grid along the edge. + return true; + } std::vector> &cell_data; std::vector &cells; diff --git a/src/libslic3r/EdgeGrid.hpp b/src/libslic3r/EdgeGrid.hpp index 38a7d8542..92cee8362 100644 --- a/src/libslic3r/EdgeGrid.hpp +++ b/src/libslic3r/EdgeGrid.hpp @@ -25,6 +25,8 @@ public: void create(const ExPolygons &expolygons, coord_t resolution); void create(const ExPolygonCollection &expolygons, coord_t resolution); + const std::vector& contours() const { return m_contours; } + #if 0 // Test, whether the edges inside the grid intersect with the polygons provided. bool intersect(const MultiPoint &polyline, bool closed); @@ -77,7 +79,7 @@ public: std::vector> intersecting_edges() const; bool has_intersecting_edges() const; - template void visit_cells_intersecting_line(Slic3r::Point p1, Slic3r::Point p2, FUNCTION func) const + template void visit_cells_intersecting_line(Slic3r::Point p1, Slic3r::Point p2, VISITOR &visitor) const { // End points of the line segment. p1(0) -= m_bbox.min(0); @@ -94,8 +96,7 @@ public: assert(ixb >= 0 && size_t(ixb) < m_cols); assert(iyb >= 0 && size_t(iyb) < m_rows); // Account for the end points. - func(iy, ix); - if (ix == ixb && iy == iyb) + if (! visitor(iy, ix) || (ix == ixb && iy == iyb)) // Both ends fall into the same cell. return; // Raster the centeral part of the line. @@ -125,7 +126,8 @@ public: ey = int64_t(dx) * m_resolution; iy += 1; } - func(iy, ix); + if (! visitor(iy, ix)) + return; } while (ix != ixb || iy != iyb); } else { @@ -143,7 +145,8 @@ public: ey = int64_t(dx) * m_resolution; iy -= 1; } - func(iy, ix); + if (! visitor(iy, ix)) + return; } while (ix != ixb || iy != iyb); } } @@ -165,7 +168,8 @@ public: ey = int64_t(dx) * m_resolution; iy += 1; } - func(iy, ix); + if (! visitor(iy, ix)) + return; } while (ix != ixb || iy != iyb); } else { @@ -197,7 +201,8 @@ public: ey = int64_t(dx) * m_resolution; iy -= 1; } - func(iy, ix); + if (! visitor(iy, ix)) + return; } while (ix != ixb || iy != iyb); } } diff --git a/src/libslic3r/ElephantFootCompensation.cpp b/src/libslic3r/ElephantFootCompensation.cpp new file mode 100644 index 000000000..b23854f11 --- /dev/null +++ b/src/libslic3r/ElephantFootCompensation.cpp @@ -0,0 +1,320 @@ +#include "clipper/clipper_z.hpp" + +#include "libslic3r.h" +#include "EdgeGrid.hpp" +#include "ExPolygon.hpp" +#include "ElephantFootCompensation.hpp" +#include "Flow.hpp" +#include "Geometry.hpp" +#include "SVG.hpp" + +#include +#include + +// #define CONTOUR_DISTANCE_DEBUG_SVG + +namespace Slic3r { + +struct ResampledPoint { + ResampledPoint(size_t idx_src, bool interpolated, double curve_parameter) : idx_src(idx_src), interpolated(interpolated), curve_parameter(curve_parameter) {} + + size_t idx_src; + // Is this point interpolated or initial? + bool interpolated; + // Euclidean distance along the curve from the 0th point. + double curve_parameter; +}; + +std::vector contour_distance(const EdgeGrid::Grid &grid, const size_t idx_contour, const Slic3r::Points &contour, const std::vector &resampled_point_parameters, double search_radius) +{ + assert(! contour.empty()); + assert(contour.size() >= 2); + + std::vector out; + + if (contour.size() > 2) + { +#ifdef CONTOUR_DISTANCE_DEBUG_SVG + static int iRun = 0; + ++ iRun; + BoundingBox bbox = get_extents(contour); + bbox.merge(grid.bbox()); + ExPolygon expoly_grid; + expoly_grid.contour = Polygon(*grid.contours().front()); + for (size_t i = 1; i < grid.contours().size(); ++ i) + expoly_grid.holes.emplace_back(Polygon(*grid.contours()[i])); +#endif + struct Visitor { + Visitor(const EdgeGrid::Grid &grid, const size_t idx_contour, const std::vector &resampled_point_parameters, double dist_same_contour_reject) : + grid(grid), idx_contour(idx_contour), resampled_point_parameters(resampled_point_parameters), dist_same_contour_reject(dist_same_contour_reject) {} + + void init(const size_t aidx_point_start, const Point &apt_start, Vec2d dir, const double radius) { + this->idx_point_start = aidx_point_start; + this->pt = apt_start.cast() + SCALED_EPSILON * dir; + dir *= radius; + this->pt_start = this->pt.cast(); + // Trim the vector by the grid's bounding box. + const BoundingBox &bbox = this->grid.bbox(); + double t = 1.; + for (size_t axis = 0; axis < 2; ++ axis) { + double dx = std::abs(dir(axis)); + if (dx >= EPSILON) { + double tedge = (dir(axis) > 0) ? (double(bbox.max(axis)) - EPSILON - this->pt(axis)) : (this->pt(axis) - double(bbox.min(axis)) - EPSILON); + if (tedge < dx) + t = tedge / dx; + } + } + this->dir = dir; + if (t < 1.) + dir *= t; + this->pt_end = (this->pt + dir).cast(); + this->t_min = 1.; + } + + bool operator()(coord_t iy, coord_t ix) { + // Called with a row and colum of the grid cell, which is intersected by a line. + auto cell_data_range = this->grid.cell_data_range(iy, ix); + bool valid = true; + for (auto it_contour_and_segment = cell_data_range.first; it_contour_and_segment != cell_data_range.second; ++ it_contour_and_segment) { + // End points of the line segment and their vector. + auto segment = this->grid.segment(*it_contour_and_segment); + if (Geometry::segments_intersect(segment.first, segment.second, this->pt_start, this->pt_end)) { + // The two segments intersect. Calculate the intersection. + Vec2d pt2 = segment.first.cast(); + Vec2d dir2 = segment.second.cast() - pt2; + Vec2d vptpt2 = pt - pt2; + double denom = dir(0) * dir2(1) - dir2(0) * dir(1); + + if (std::abs(denom) >= EPSILON) { + double t = cross2(dir2, vptpt2) / denom; + assert(t > 0. && t <= 1.); + bool this_valid = true; + if (it_contour_and_segment->first == idx_contour) { + // The intersected segment originates from the same contour as the starting point. + // Reject the intersection if it is close to the starting point. + // Find the start and end points of this segment + double param_lo = resampled_point_parameters[idx_point_start].curve_parameter; + double param_hi; + double param_end = resampled_point_parameters.back().curve_parameter; + { + const Slic3r::Points &ipts = *grid.contours()[it_contour_and_segment->first]; + size_t ipt = it_contour_and_segment->second; + ResampledPoint key(ipt, false, 0.); + auto lower = [](const ResampledPoint& l, const ResampledPoint r) { return l.idx_src < r.idx_src || (l.idx_src == r.idx_src && int(l.interpolated) > int(r.interpolated)); }; + auto it = std::lower_bound(resampled_point_parameters.begin(), resampled_point_parameters.end(), key, lower); + assert(it != resampled_point_parameters.end() && it->idx_src == ipt && ! it->interpolated); + double t2 = cross2(dir, vptpt2) / denom; + assert(t2 >= 0. && t2 <= 1.); + if (++ ipt == ipts.size()) + param_hi = t2 * dir2.norm(); + else + param_hi = it->curve_parameter + t2 * dir2.norm(); + } + if (param_lo > param_hi) + std::swap(param_lo, param_hi); + assert(param_lo >= 0. && param_lo <= param_end); + assert(param_hi >= 0. && param_hi <= param_end); + this_valid = param_hi > param_lo + dist_same_contour_reject && param_hi - param_end < param_lo - dist_same_contour_reject; + } + if (t < this->t_min) { + this->t_min = t; + valid = this_valid; + } + } + } + if (! valid) + this->t_min = 1.; + } + // Continue traversing the grid along the edge. + return true; + } + + const EdgeGrid::Grid &grid; + const size_t idx_contour; + const std::vector &resampled_point_parameters; + const double dist_same_contour_reject; + + size_t idx_point_start; + Point pt_start; + Point pt_end; + Vec2d pt; + Vec2d dir; + // Minium parameter along the vector (pt_end - pt_start). + double t_min; + } visitor(grid, idx_contour, resampled_point_parameters, search_radius); + + const Point *pt_this = &contour.back(); + size_t idx_pt_this = contour.size() - 1; + const Point *pt_prev = pt_this - 1; + // perpenduclar vector + auto perp = [](const Vec2d& v) -> Vec2d { return Vec2d(v.y(), -v.x()); }; + Vec2d vprev = (*pt_this - *pt_prev).cast().normalized(); + out.reserve(contour.size() + 1); + for (const Point &pt_next : contour) { + Vec2d vnext = (pt_next - *pt_this).cast().normalized(); + Vec2d dir = - (perp(vprev) + perp(vnext)).normalized(); + Vec2d dir_perp = perp(dir); + double cross = cross2(vprev, vnext); + double dot = vprev.dot(vnext); + double a = (cross < 0 || dot > 0.5) ? (M_PI / 3.) : (0.48 * acos(std::min(1., - dot))); + // Throw rays, collect distances. + std::vector distances; + int num_rays = 15; + +#ifdef CONTOUR_DISTANCE_DEBUG_SVG + SVG svg(debug_out_path("contour_distance_raycasted-%d-%d.svg", iRun, &pt_next - contour.data()).c_str(), bbox); + svg.draw(expoly_grid); + svg.draw_outline(Polygon(contour), "blue", scale_(0.01)); + svg.draw(*pt_this, "red", scale_(0.1)); +#endif /* CONTOUR_DISTANCE_DEBUG_SVG */ + + for (int i = - num_rays + 1; i < num_rays; ++ i) { + double angle = a * i / (int)num_rays; + double c = cos(angle); + double s = sin(angle); + Vec2d v = c * dir + s * dir_perp; + visitor.init(idx_pt_this, *pt_this, v, search_radius); + grid.visit_cells_intersecting_line(visitor.pt_start, visitor.pt_end, visitor); + distances.emplace_back(visitor.t_min); +#ifdef CONTOUR_DISTANCE_DEBUG_SVG + svg.draw(Line(visitor.pt_start, visitor.pt_end), "yellow", scale_(0.01)); + if (visitor.t_min < 1.) { + Vec2d pt = visitor.pt + visitor.dir * visitor.t_min; + svg.draw(Point(pt), "red", scale_(0.1)); + } +#endif /* CONTOUR_DISTANCE_DEBUG_SVG */ + } +#ifdef CONTOUR_DISTANCE_DEBUG_SVG + svg.Close(); +#endif /* CONTOUR_DISTANCE_DEBUG_SVG */ + std::sort(distances.begin(), distances.end()); +#if 0 + double median = distances[distances.size() / 2]; + double standard_deviation = 0; + for (double d : distances) + standard_deviation += (d - median) * (d - median); + standard_deviation = sqrt(standard_deviation / (distances.size() - 1)); + double avg = 0; + size_t cnt = 0; + for (double d : distances) + if (d > median - standard_deviation - EPSILON && d < median + standard_deviation + EPSILON) { + avg += d; + ++ cnt; + } + avg /= double(cnt); + out.emplace_back(float(avg * search_radius)); +#else + out.emplace_back(float(distances.front() * search_radius)); +#endif +#ifdef CONTOUR_DISTANCE_DEBUG_SVG + printf("contour_distance_raycasted-%d-%d.svg - distance %lf\n", iRun, &pt_next - contour.data(), unscale(out.back())); +#endif /* CONTOUR_DISTANCE_DEBUG_SVG */ + pt_this = &pt_next; + idx_pt_this = &pt_next - contour.data(); + vprev = vnext; + } + // Rotate the vector by one item. + out.emplace_back(out.front()); + out.erase(out.begin()); + } + + return out; +} + +Points resample_polygon(const Points &contour, double dist, std::vector &resampled_point_parameters) +{ + Points out; + out.reserve(contour.size()); + resampled_point_parameters.reserve(contour.size()); + if (contour.size() > 2) { + Vec2d pt_prev = contour.back().cast(); + for (const Point &pt : contour) { + size_t idx_this = &pt - contour.data(); + const Vec2d pt_this = pt.cast(); + const Vec2d v = pt_this - pt_prev; + const double l = v.norm(); + const size_t n = size_t(ceil(l / dist)); + const double l_step = l / n; + for (size_t i = 1; i < n; ++ i) { + double interpolation_parameter = double(i) / n; + Vec2d new_pt = pt_prev + v * interpolation_parameter; + out.emplace_back(new_pt.cast()); + resampled_point_parameters.emplace_back(idx_this, true, l_step); + } + out.emplace_back(pt); + resampled_point_parameters.emplace_back(idx_this, false, l_step); + pt_prev = pt_this; + } + for (size_t i = 1; i < resampled_point_parameters.size(); ++i) + resampled_point_parameters[i].curve_parameter += resampled_point_parameters[i - 1].curve_parameter; + } + return out; +} + +static inline void smooth_compensation(std::vector &compensation, float strength, size_t num_iterations) +{ + std::vector out(compensation); + for (size_t iter = 0; iter < num_iterations; ++ iter) { + for (size_t i = 0; i < compensation.size(); ++ i) { + float prev = (i == 0) ? compensation.back() : compensation[i - 1]; + float next = (i + 1 == compensation.size()) ? compensation.front() : compensation[i + 1]; + float laplacian = compensation[i] * (1.f - strength) + 0.5f * strength * (prev + next); + // Compensations are negative. Only apply the laplacian if it leads to lower compensation. + out[i] = std::max(laplacian, compensation[i]); + } + out.swap(compensation); + } +} + +ExPolygon elephant_foot_compensation(const ExPolygon &input_expoly, const Flow &external_perimeter_flow, const double compensation) +{ + // The contour shall be wide enough to apply the external perimeter plus compensation on both sides. + double min_contour_width = double(external_perimeter_flow.scaled_width() + external_perimeter_flow.scaled_spacing()); + double scaled_compensation = scale_(compensation); + double min_contour_width_compensated = min_contour_width + 2. * scaled_compensation; + // Make the search radius a bit larger for the averaging in contour_distance over a fan of rays to work. + double search_radius = min_contour_width_compensated + min_contour_width * 0.5; + + EdgeGrid::Grid grid; + ExPolygon simplified = input_expoly.simplify(SCALED_EPSILON).front(); + BoundingBox bbox = get_extents(simplified.contour); + bbox.offset(SCALED_EPSILON); + grid.set_bbox(bbox); + grid.create(simplified, coord_t(0.7 * search_radius)); + std::vector> deltas; + deltas.reserve(simplified.holes.size() + 1); + ExPolygon resampled(simplified); + for (size_t idx_contour = 0; idx_contour <= simplified.holes.size(); ++ idx_contour) { + Polygon &poly = (idx_contour == 0) ? resampled.contour : resampled.holes[idx_contour - 1]; + std::vector resampled_point_parameters; + poly.points = resample_polygon(poly.points, scale_(0.5), resampled_point_parameters); + std::vector dists = contour_distance(grid, idx_contour, poly.points, resampled_point_parameters, search_radius); + for (float &d : dists) { +// printf("Point %d, Distance: %lf\n", int(&d - dists.data()), unscale(d)); + // Convert contour width to available compensation distance. + if (d < min_contour_width) + d = 0.f; + else if (d > min_contour_width_compensated) + d = - float(scaled_compensation); + else + d = - (d - float(min_contour_width)) / 2.f; + assert(d >= - float(scaled_compensation) && d <= 0.f); + } + smooth_compensation(dists, 0.4f, 10); + deltas.emplace_back(dists); + } + + ExPolygons out = variable_offset_inner_ex(resampled, deltas, 2.); + return out.front(); +} + +ExPolygons elephant_foot_compensation(const ExPolygons &input, const Flow &external_perimeter_flow, const double compensation) +{ + ExPolygons out; + out.reserve(input.size()); + for (const ExPolygon &expoly : input) + out.emplace_back(elephant_foot_compensation(expoly, external_perimeter_flow, compensation)); + return out; +} + +} // namespace Slic3r diff --git a/src/libslic3r/ElephantFootCompensation.hpp b/src/libslic3r/ElephantFootCompensation.hpp new file mode 100644 index 000000000..0119df1af --- /dev/null +++ b/src/libslic3r/ElephantFootCompensation.hpp @@ -0,0 +1,16 @@ +#ifndef slic3r_ElephantFootCompensation_hpp_ +#define slic3r_ElephantFootCompensation_hpp_ + +#include "libslic3r.h" +#include + +namespace Slic3r { + +class Flow; + +ExPolygon elephant_foot_compensation(const ExPolygon &input, const Flow &external_perimeter_flow, const double compensation); +ExPolygons elephant_foot_compensation(const ExPolygons &input, const Flow &external_perimeter_flow, const double compensation); + +} // Slic3r + +#endif /* slic3r_ElephantFootCompensation_hpp_ */ diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 26d9c90f8..26d2fc649 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -543,7 +543,7 @@ std::vector GCode::collect_layers_to_print(const PrintObjec //FIXME should we use the printing extruders instead? double gap_over_supports = object.config().support_material_contact_distance; // FIXME should we test object.config().support_material_synchronize_layers ? Currently the support layers are synchronized with object layers iff soluble supports. - assert(gap_over_supports != 0. || object.config().support_material_synchronize_layers); + assert(! object.config().support_material || gap_over_supports != 0. || object.config().support_material_synchronize_layers); if (gap_over_supports != 0.) { gap_over_supports = std::max(0., gap_over_supports); // Not a soluble support, diff --git a/src/libslic3r/Layer.cpp b/src/libslic3r/Layer.cpp index 74deabf3e..53a7f2fc4 100644 --- a/src/libslic3r/Layer.cpp +++ b/src/libslic3r/Layer.cpp @@ -88,8 +88,12 @@ ExPolygons Layer::merged(float offset_scaled) const offset_scaled2 = float(- EPSILON); } Polygons polygons; - for (LayerRegion *layerm : m_regions) - append(polygons, offset(to_expolygons(layerm->slices.surfaces), offset_scaled)); + for (LayerRegion *layerm : m_regions) { + const PrintRegionConfig &config = layerm->region()->config(); + // Our users learned to bend Slic3r to produce empty volumes to act as subtracters. Only add the region if it is non-empty. + if (config.bottom_solid_layers > 0 || config.top_solid_layers > 0 || config.fill_density > 0. || config.perimeters > 0) + append(polygons, offset(to_expolygons(layerm->slices.surfaces), offset_scaled)); + } ExPolygons out = union_ex(polygons); if (offset_scaled2 != 0.f) out = offset_ex(out, offset_scaled2); diff --git a/src/libslic3r/Polygon.cpp b/src/libslic3r/Polygon.cpp index bd5ec3de5..e1e299144 100644 --- a/src/libslic3r/Polygon.cpp +++ b/src/libslic3r/Polygon.cpp @@ -254,6 +254,11 @@ Point Polygon::point_projection(const Point &point) const return proj; } +BoundingBox get_extents(const Points &points) +{ + return BoundingBox(points); +} + BoundingBox get_extents(const Polygon &poly) { return poly.bounding_box(); diff --git a/src/libslic3r/Polygon.hpp b/src/libslic3r/Polygon.hpp index 4d53e97e1..8230b49f8 100644 --- a/src/libslic3r/Polygon.hpp +++ b/src/libslic3r/Polygon.hpp @@ -70,7 +70,7 @@ public: inline bool operator==(const Polygon &lhs, const Polygon &rhs) { return lhs.points == rhs.points; } inline bool operator!=(const Polygon &lhs, const Polygon &rhs) { return lhs.points != rhs.points; } - +extern BoundingBox get_extents(const Points &points); extern BoundingBox get_extents(const Polygon &poly); extern BoundingBox get_extents(const Polygons &polygons); extern BoundingBox get_extents_rotated(const Polygon &poly, double angle); diff --git a/src/libslic3r/PolygonTrimmer.cpp b/src/libslic3r/PolygonTrimmer.cpp index a2779b666..2c4e06fc5 100644 --- a/src/libslic3r/PolygonTrimmer.cpp +++ b/src/libslic3r/PolygonTrimmer.cpp @@ -16,7 +16,7 @@ TrimmedLoop trim_loop(const Polygon &loop, const EdgeGrid::Grid &grid) struct Visitor { Visitor(const EdgeGrid::Grid &grid, const Slic3r::Point *pt_prev, const Slic3r::Point *pt_this) : grid(grid), pt_prev(pt_prev), pt_this(pt_this) {} - void operator()(coord_t iy, coord_t ix) { + bool operator()(coord_t iy, coord_t ix) { // Called with a row and colum of the grid cell, which is intersected by a line. auto cell_data_range = grid.cell_data_range(iy, ix); for (auto it_contour_and_segment = cell_data_range.first; it_contour_and_segment != cell_data_range.second; ++ it_contour_and_segment) { @@ -26,6 +26,8 @@ TrimmedLoop trim_loop(const Polygon &loop, const EdgeGrid::Grid &grid) // The two segments intersect. Add them to the output. } } + // Continue traversing the grid along the edge. + return true; } const EdgeGrid::Grid &grid; diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index d87e63c27..b334b70fc 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -1,6 +1,7 @@ #include "Print.hpp" #include "BoundingBox.hpp" #include "ClipperUtils.hpp" +#include "ElephantFootCompensation.hpp" #include "Geometry.hpp" #include "I18N.hpp" #include "SupportMaterial.hpp" @@ -1769,6 +1770,7 @@ end: Layer *layer = m_layers[layer_id]; // Apply size compensation and perform clipping of multi-part objects. float delta = float(scale_(m_config.xy_size_compensation.value)); + //FIXME only apply the compensation if no raft is enabled. float elephant_foot_compensation = 0.f; if (layer_id == 0) elephant_foot_compensation = float(scale_(m_config.elefant_foot_compensation.value)); @@ -1789,19 +1791,8 @@ end: to_expolygons(std::move(layerm->slices.surfaces)) : offset_ex(to_expolygons(std::move(layerm->slices.surfaces)), delta); // Apply the elephant foot compensation. - if (elephant_foot_compensation > 0) { - float elephant_foot_spacing = float(layerm->flow(frExternalPerimeter).scaled_elephant_foot_spacing()); - float external_perimeter_nozzle = float(scale_(this->print()->config().nozzle_diameter.get_at(layerm->region()->config().perimeter_extruder.value - 1))); - // Apply the elephant foot compensation by steps of 1/10 nozzle diameter. - float steps = std::ceil(elephant_foot_compensation / (0.1f * external_perimeter_nozzle)); - size_t nsteps = size_t(steps); - float step = elephant_foot_compensation / steps; - for (size_t i = 0; i < nsteps; ++ i) { - Polygons tmp = offset(expolygons, - step); - append(tmp, diff(to_polygons(expolygons), offset(offset_ex(expolygons, -elephant_foot_spacing - step), elephant_foot_spacing + step))); - expolygons = union_ex(tmp); - } - } + if (elephant_foot_compensation > 0) + expolygons = union_ex(Slic3r::elephant_foot_compensation(expolygons, layerm->flow(frExternalPerimeter), unscale(elephant_foot_compensation))); layerm->slices.set(std::move(expolygons), stInternal); } } else { @@ -1825,33 +1816,17 @@ end: layerm->slices.set(std::move(slices), stInternal); } } - if (delta < 0.f) { + if (delta < 0.f || elephant_foot_compensation > 0.f) { // Apply the negative XY compensation. - Polygons trimming = offset(layer->merged(float(EPSILON)), delta - float(EPSILON)); + Polygons trimming; + if (elephant_foot_compensation > 0.f) { + trimming = to_polygons(Slic3r::elephant_foot_compensation(offset_ex(layer->merged(float(EPSILON)), std::min(delta, 0.f) - float(EPSILON)), + layer->m_regions.front()->flow(frExternalPerimeter), unscale(elephant_foot_compensation))); + } else + trimming = offset(layer->merged(float(EPSILON)), delta - float(EPSILON)); for (size_t region_id = 0; region_id < layer->m_regions.size(); ++ region_id) layer->m_regions[region_id]->trim_surfaces(trimming); } - if (elephant_foot_compensation > 0.f) { - // Apply the elephant foot compensation. - std::vector elephant_foot_spacing; - elephant_foot_spacing.reserve(layer->m_regions.size()); - float external_perimeter_nozzle = 0.f; - for (size_t region_id = 0; region_id < layer->m_regions.size(); ++ region_id) { - LayerRegion *layerm = layer->m_regions[region_id]; - elephant_foot_spacing.emplace_back(float(layerm->flow(frExternalPerimeter).scaled_elephant_foot_spacing())); - external_perimeter_nozzle += float(scale_(this->print()->config().nozzle_diameter.get_at(layerm->region()->config().perimeter_extruder.value - 1))); - } - external_perimeter_nozzle /= (float)layer->m_regions.size(); - // Apply the elephant foot compensation by steps of 1/10 nozzle diameter. - float steps = std::ceil(elephant_foot_compensation / (0.1f * external_perimeter_nozzle)); - size_t nsteps = size_t(steps); - float step = elephant_foot_compensation / steps; - for (size_t i = 0; i < nsteps; ++ i) { - Polygons trimming_polygons = offset(layer->merged(float(EPSILON)), - step - float(EPSILON)); - for (size_t region_id = 0; region_id < layer->m_regions.size(); ++ region_id) - layer->m_regions[region_id]->elephant_foot_compensation_step(elephant_foot_spacing[region_id] + step, trimming_polygons); - } - } } // Merge all regions' slices to get islands, chain them by a shortest path. layer->make_slices(); diff --git a/src/libslic3r/SVG.cpp b/src/libslic3r/SVG.cpp index 03f55802e..6e4b973ea 100644 --- a/src/libslic3r/SVG.cpp +++ b/src/libslic3r/SVG.cpp @@ -368,6 +368,10 @@ void SVG::export_expolygons(const char *path, const std::vector 0) + for (const ExPolygon &expoly : exp_with_attr.first) + svg.draw((Points)expoly, exp_with_attr.second.color_points, exp_with_attr.second.radius_points); svg.Close(); } diff --git a/src/libslic3r/SVG.hpp b/src/libslic3r/SVG.hpp index 3a5602196..c1b387554 100644 --- a/src/libslic3r/SVG.hpp +++ b/src/libslic3r/SVG.hpp @@ -105,19 +105,25 @@ public: const std::string &color_contour, const std::string &color_holes, const coord_t outline_width = scale_(0.05), - const float fill_opacity = 0.5f) : + const float fill_opacity = 0.5f, + const std::string &color_points = "black", + const coord_t radius_points = 0) : color_fill (color_fill), color_contour (color_contour), color_holes (color_holes), outline_width (outline_width), - fill_opacity (fill_opacity) + fill_opacity (fill_opacity), + color_points (color_points), + radius_points (radius_points) {} std::string color_fill; std::string color_contour; std::string color_holes; + std::string color_points; coord_t outline_width; float fill_opacity; + coord_t radius_points; }; static void export_expolygons(const char *path, const std::vector> &expolygons_with_attributes); -- cgit v1.2.3 From bb8d59391fdd21317a68e4b83c54fc3f3fe88c0a Mon Sep 17 00:00:00 2001 From: bubnikv Date: Fri, 1 Nov 2019 21:13:53 +0100 Subject: Fixed missing include --- src/libslic3r/ElephantFootCompensation.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/libslic3r/ElephantFootCompensation.cpp b/src/libslic3r/ElephantFootCompensation.cpp index b23854f11..5bdeaa954 100644 --- a/src/libslic3r/ElephantFootCompensation.cpp +++ b/src/libslic3r/ElephantFootCompensation.cpp @@ -1,6 +1,7 @@ #include "clipper/clipper_z.hpp" #include "libslic3r.h" +#include "ClipperUtils.hpp" #include "EdgeGrid.hpp" #include "ExPolygon.hpp" #include "ElephantFootCompensation.hpp" -- cgit v1.2.3