From 46ade45ced5511cbee401ebd9266fcd5e4008a2c Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Tue, 14 Apr 2020 13:18:08 +0200 Subject: [PATCH 01/16] The bed texture is not shown when looking from below and FDM/SLA support gizmo is active --- src/slic3r/GUI/3DBed.cpp | 17 ++++++++++------- src/slic3r/GUI/3DBed.hpp | 12 ++++++++---- src/slic3r/GUI/GLCanvas3D.cpp | 9 +++++++-- src/slic3r/GUI/GLCanvas3D.hpp | 2 +- 4 files changed, 26 insertions(+), 14 deletions(-) diff --git a/src/slic3r/GUI/3DBed.cpp b/src/slic3r/GUI/3DBed.cpp index 742941b84..2cc9de38c 100644 --- a/src/slic3r/GUI/3DBed.cpp +++ b/src/slic3r/GUI/3DBed.cpp @@ -259,7 +259,8 @@ Point Bed3D::point_projection(const Point& point) const return m_polygon.point_projection(point); } -void Bed3D::render(GLCanvas3D& canvas, bool bottom, float scale_factor, bool show_axes) const +void Bed3D::render(GLCanvas3D& canvas, bool bottom, float scale_factor, + bool show_axes, bool show_texture) const { m_scale_factor = scale_factor; @@ -270,9 +271,9 @@ void Bed3D::render(GLCanvas3D& canvas, bool bottom, float scale_factor, bool sho switch (m_type) { - case System: { render_system(canvas, bottom); break; } + case System: { render_system(canvas, bottom, show_texture); break; } default: - case Custom: { render_custom(canvas, bottom); break; } + case Custom: { render_custom(canvas, bottom, show_texture); break; } } glsafe(::glDisable(GL_DEPTH_TEST)); @@ -384,12 +385,13 @@ void Bed3D::render_axes() const m_axes.render(); } -void Bed3D::render_system(GLCanvas3D& canvas, bool bottom) const +void Bed3D::render_system(GLCanvas3D& canvas, bool bottom, bool show_texture) const { if (!bottom) render_model(); - render_texture(bottom, canvas); + if (show_texture) + render_texture(bottom, canvas); } void Bed3D::render_texture(bool bottom, GLCanvas3D& canvas) const @@ -564,7 +566,7 @@ void Bed3D::render_model() const } } -void Bed3D::render_custom(GLCanvas3D& canvas, bool bottom) const +void Bed3D::render_custom(GLCanvas3D& canvas, bool bottom, bool show_texture) const { if (m_texture_filename.empty() && m_model_filename.empty()) { @@ -575,7 +577,8 @@ void Bed3D::render_custom(GLCanvas3D& canvas, bool bottom) const if (!bottom) render_model(); - render_texture(bottom, canvas); + if (show_texture) + render_texture(bottom, canvas); } void Bed3D::render_default(bool bottom) const diff --git a/src/slic3r/GUI/3DBed.hpp b/src/slic3r/GUI/3DBed.hpp index 3a5f95978..abdfca1fe 100644 --- a/src/slic3r/GUI/3DBed.hpp +++ b/src/slic3r/GUI/3DBed.hpp @@ -103,11 +103,15 @@ public: // Return true if the bed shape changed, so the calee will update the UI. bool set_shape(const Pointfs& shape, const std::string& custom_texture, const std::string& custom_model); - const BoundingBoxf3& get_bounding_box(bool extended) const { return extended ? m_extended_bounding_box : m_bounding_box; } + const BoundingBoxf3& get_bounding_box(bool extended) const { + return extended ? m_extended_bounding_box : m_bounding_box; + } + bool contains(const Point& point) const; Point point_projection(const Point& point) const; - void render(GLCanvas3D& canvas, bool bottom, float scale_factor, bool show_axes) const; + void render(GLCanvas3D& canvas, bool bottom, float scale_factor, + bool show_axes, bool show_texture) const; private: void calc_bounding_boxes() const; @@ -115,10 +119,10 @@ private: void calc_gridlines(const ExPolygon& poly, const BoundingBox& bed_bbox); std::tuple detect_type(const Pointfs& shape) const; void render_axes() const; - void render_system(GLCanvas3D& canvas, bool bottom) const; + void render_system(GLCanvas3D& canvas, bool bottom, bool show_texture) const; void render_texture(bool bottom, GLCanvas3D& canvas) const; void render_model() const; - void render_custom(GLCanvas3D& canvas, bool bottom) const; + void render_custom(GLCanvas3D& canvas, bool bottom, bool show_texture) const; void render_default(bool bottom) const; void reset(); }; diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 9127fcaf4..48243857e 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -5339,14 +5339,19 @@ void GLCanvas3D::_render_background() const glsafe(::glPopMatrix()); } -void GLCanvas3D::_render_bed(float theta, bool show_axes) const +void GLCanvas3D::_render_bed(bool bottom, bool show_axes) const { float scale_factor = 1.0; #if ENABLE_RETINA_GL scale_factor = m_retina_helper->get_scale_factor(); #endif // ENABLE_RETINA_GL + + bool show_texture = ! bottom || + (m_gizmos.get_current_type() != GLGizmosManager::FdmSupports + && m_gizmos.get_current_type() != GLGizmosManager::SlaSupports); + #if ENABLE_NON_STATIC_CANVAS_MANAGER - wxGetApp().plater()->get_bed().render(const_cast(*this), theta, scale_factor, show_axes); + wxGetApp().plater()->get_bed().render(const_cast(*this), bottom, scale_factor, show_axes, show_texture); #else m_bed.render(const_cast(*this), theta, scale_factor, show_axes); #endif // ENABLE_NON_STATIC_CANVAS_MANAGER diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 07fa00b9d..c7d4f4a06 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -755,7 +755,7 @@ private: void _picking_pass() const; void _rectangular_selection_picking_pass() const; void _render_background() const; - void _render_bed(float theta, bool show_axes) const; + void _render_bed(bool bottom, bool show_axes) const; void _render_objects() const; void _render_selection() const; #if ENABLE_RENDER_SELECTION_CENTER From 546b0702f901cf24768ccf9df2022d1505957777 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Thu, 16 Apr 2020 14:42:42 +0200 Subject: [PATCH 02/16] Custom supports data are saved into ModelObject and propagate to the backend Invalidation of supports after they change is not implemented yet. --- src/libslic3r/Model.cpp | 37 ++++++++++++++ src/libslic3r/Model.hpp | 39 ++++++++++++++- src/libslic3r/Print.cpp | 3 +- src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp | 52 ++++++++++++++------ src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp | 11 ++--- 5 files changed, 118 insertions(+), 24 deletions(-) diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 59df8eb61..56c1f8b7e 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -1149,6 +1149,8 @@ ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z, bool keep_upper, b for (ModelVolume *volume : volumes) { const auto volume_matrix = volume->get_matrix(); + volume->m_supported_facets.clear(); + if (! volume->is_model_part()) { // Modifiers are not cut, but we still need to add the instance transformation // to the modifier volume transformation to preserve their shape properly. @@ -1848,6 +1850,41 @@ arrangement::ArrangePolygon ModelInstance::get_arrange_polygon() const return ret; } + +std::vector FacetsAnnotation::get_facets(FacetSupportType type) const +{ + std::vector out; + for (auto& [facet_idx, this_type] : m_data) + if (this_type == type) + out.push_back(facet_idx); + return out; +} + + + +void FacetsAnnotation::set_facet(int idx, FacetSupportType type) +{ + bool changed = true; + + if (type == FacetSupportType::NONE) + changed = m_data.erase(idx) != 0; + else + m_data[idx] = type; + + if (changed) + update_timestamp(); +} + + + +void FacetsAnnotation::clear() +{ + m_data.clear(); + update_timestamp(); +} + + + // Test whether the two models contain the same number of ModelObjects with the same set of IDs // ordered in the same order. In that case it is not necessary to kill the background processing. bool model_object_list_equal(const Model &model_old, const Model &model_new) diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 2ddad9e59..33fc8a622 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -19,6 +19,7 @@ #include #include #include +#include namespace cereal { class BinaryInputArchive; @@ -391,6 +392,35 @@ enum class ModelVolumeType : int { SUPPORT_BLOCKER, }; +enum class FacetSupportType : int8_t { + NONE = 0, + ENFORCER = 1, + BLOCKER = 2 +}; + +class FacetsAnnotation { +public: + using ClockType = std::chrono::steady_clock; + + + std::vector get_facets(FacetSupportType type) const; + void set_facet(int idx, FacetSupportType type); + void clear(); + + ClockType::time_point get_timestamp() const { return timestamp; } + bool is_newer_than(const FacetsAnnotation& other) const { + return timestamp > other.get_timestamp(); + } + +private: + std::map m_data; + + ClockType::time_point timestamp; + void update_timestamp() { + timestamp = ClockType::now(); + } +}; + // An object STL, or a modifier volume, over which a different set of parameters shall be applied. // ModelVolume instances are owned by a ModelObject. class ModelVolume final : public ObjectBase @@ -421,6 +451,9 @@ public: // overriding the global Slic3r settings and the ModelObject settings. ModelConfig config; + // List of mesh facets to be supported/unsupported. + FacetsAnnotation m_supported_facets; + // A parent object owning this modifier volume. ModelObject* get_object() const { return this->object; }; ModelVolumeType type() const { return m_type; } @@ -548,7 +581,9 @@ private: // Copying an existing volume, therefore this volume will get a copy of the ID assigned. ModelVolume(ModelObject *object, const ModelVolume &other) : ObjectBase(other), - name(other.name), source(other.source), m_mesh(other.m_mesh), m_convex_hull(other.m_convex_hull), config(other.config), m_type(other.m_type), object(object), m_transformation(other.m_transformation) + name(other.name), source(other.source), m_mesh(other.m_mesh), m_convex_hull(other.m_convex_hull), + config(other.config), m_type(other.m_type), object(object), m_transformation(other.m_transformation), + m_supported_facets(other.m_supported_facets) { assert(this->id().valid()); assert(this->config.id().valid()); assert(this->id() != this->config.id()); assert(this->id() == other.id() && this->config.id() == other.config.id()); @@ -565,6 +600,8 @@ private: if (mesh.stl.stats.number_of_facets > 1) calculate_convex_hull(); assert(this->config.id().valid()); assert(this->config.id() != other.config.id()); assert(this->id() != this->config.id()); + + m_supported_facets.clear(); } ModelVolume& operator=(ModelVolume &rhs) = delete; diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 8631db624..facc5f521 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -404,6 +404,7 @@ static inline void model_volume_list_copy_configs(ModelObject &model_object_dst, // Copy the ModelVolume data. mv_dst.name = mv_src.name; static_cast(mv_dst.config) = static_cast(mv_src.config); + mv_dst.m_supported_facets = mv_src.m_supported_facets; //FIXME what to do with the materials? // mv_dst.m_material_id = mv_src.m_material_id; ++ i_src; @@ -881,7 +882,7 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ } } } - // Synchronize (just copy) the remaining data of ModelVolumes (name, config). + // Synchronize (just copy) the remaining data of ModelVolumes (name, config, custom supports data). //FIXME What to do with m_material_id? model_volume_list_copy_configs(model_object /* dst */, model_object_new /* src */, ModelVolumeType::MODEL_PART); model_volume_list_copy_configs(model_object /* dst */, model_object_new /* src */, ModelVolumeType::PARAMETER_MODIFIER); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp index 7086f3c8d..085986c46 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp @@ -8,6 +8,7 @@ #include "slic3r/GUI/GUI_App.hpp" #include "slic3r/GUI/PresetBundle.hpp" #include "slic3r/GUI/Camera.hpp" +#include "libslic3r/Model.hpp" @@ -187,7 +188,16 @@ void GLGizmoFdmSupports::update_mesh() // This mesh does not account for the possible Z up SLA offset. const TriangleMesh* mesh = &mv->mesh(); - m_selected_facets[volume_id].assign(mesh->its.indices.size(), SelType::NONE); + m_selected_facets[volume_id].assign(mesh->its.indices.size(), FacetSupportType::NONE); + + // Load current state from ModelVolume. + for (FacetSupportType type : {FacetSupportType::ENFORCER, FacetSupportType::BLOCKER}) { + const std::vector& list = mv->m_supported_facets.get_facets(type); + for (int i : list) + m_selected_facets[volume_id][i] = type; + } + update_vertex_buffers(mv, volume_id, true, true); + m_neighbors[volume_id].resize(3 * mesh->its.indices.size()); // Prepare vector of vertex_index - facet_index pairs to quickly find adjacent facets @@ -243,16 +253,16 @@ bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous || action == SLAGizmoEventType::RightDown || (action == SLAGizmoEventType::Dragging && m_button_down != Button::None)) { - SelType new_state = SelType::NONE; + FacetSupportType new_state = FacetSupportType::NONE; if (! shift_down) { if (action == SLAGizmoEventType::Dragging) new_state = m_button_down == Button::Left - ? SelType::ENFORCER - : SelType::BLOCKER; + ? FacetSupportType::ENFORCER + : FacetSupportType::BLOCKER; else new_state = action == SLAGizmoEventType::LeftDown - ? SelType::ENFORCER - : SelType::BLOCKER; + ? FacetSupportType::ENFORCER + : FacetSupportType::BLOCKER; } const Camera& camera = wxGetApp().plater()->get_camera(); @@ -379,9 +389,9 @@ bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous // Now just select all facets that passed. for (size_t next_facet : facets_to_select) { - SelType& facet = m_selected_facets[mesh_id][next_facet]; + FacetSupportType& facet = m_selected_facets[mesh_id][next_facet]; - if (facet != new_state && facet != SelType::NONE) { + if (facet != new_state && facet != FacetSupportType::NONE) { // this triangle is currently in the other VBA. // Both VBAs need to be refreshed. update_both = true; @@ -391,8 +401,8 @@ bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous } update_vertex_buffers(mv, mesh_id, - new_state == SelType::ENFORCER || update_both, - new_state == SelType::BLOCKER || update_both + new_state == FacetSupportType::ENFORCER || update_both, + new_state == FacetSupportType::BLOCKER || update_both ); } @@ -416,6 +426,18 @@ bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous if ((action == SLAGizmoEventType::LeftUp || action == SLAGizmoEventType::RightUp) && m_button_down != Button::None) { m_button_down = Button::None; + + // Synchronize gizmo with ModelVolume data. + ModelObject* mo = m_c->selection_info()->model_object(); + int idx = -1; + for (ModelVolume* mv : mo->volumes) { + ++idx; + if (! mv->is_model_part()) + continue; + for (int i=0; im_supported_facets.set_facet(i, m_selected_facets[idx][i]); + } + return true; } @@ -430,16 +452,16 @@ void GLGizmoFdmSupports::update_vertex_buffers(const ModelVolume* mv, { const TriangleMesh* mesh = &mv->mesh(); - for (SelType type : {SelType::ENFORCER, SelType::BLOCKER}) { - if ((type == SelType::ENFORCER && ! update_enforcers) - || (type == SelType::BLOCKER && ! update_blockers)) + for (FacetSupportType type : {FacetSupportType::ENFORCER, FacetSupportType::BLOCKER}) { + if ((type == FacetSupportType::ENFORCER && ! update_enforcers) + || (type == FacetSupportType::BLOCKER && ! update_blockers)) continue; - GLIndexedVertexArray& iva = m_ivas[mesh_id][type==SelType::ENFORCER ? 0 : 1]; + GLIndexedVertexArray& iva = m_ivas[mesh_id][type==FacetSupportType::ENFORCER ? 0 : 1]; iva.release_geometry(); size_t triangle_cnt=0; for (size_t facet_idx=0; facet_idx> m_selected_facets; + std::vector> m_selected_facets; // Store two vertex buffer arrays (for enforcers/blockers) // for each model-part volume. From c570fc40de709d097afa1c763b3b5efbdc794ba7 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Thu, 16 Apr 2020 16:59:06 +0200 Subject: [PATCH 03/16] First partially working implementation of custom supports at the backend The solution is temporary and should be improved and moved elsewhere - see comments in the code. --- src/libslic3r/SupportMaterial.cpp | 71 +++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/src/libslic3r/SupportMaterial.cpp b/src/libslic3r/SupportMaterial.cpp index 1d98bb0e6..dccc8616b 100644 --- a/src/libslic3r/SupportMaterial.cpp +++ b/src/libslic3r/SupportMaterial.cpp @@ -971,6 +971,77 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_ std::vector enforcers = object.slice_support_enforcers(); std::vector blockers = object.slice_support_blockers(); + + + + + + /////////////////////////////////////////////////////////////////////////// + /// TEMPORARY INLINE DRAFT PROJECTING CUSTOM SUPPORTS ON SLICES /// + /// /////////////////////////////////////////////////////////////////////// + const auto& data = object.model_object()->volumes.front()->m_supported_facets; + const auto& custom_enf = data.get_facets(FacetSupportType::ENFORCER); + const TriangleMesh& mesh = object.model_object()->volumes.front()->mesh(); + const Transform3f& tr1 = object.model_object()->volumes.front()->get_matrix().cast(); + const Transform3f& tr2 = object.trafo().cast(); + + // Make a list of all layers. + const LayerPtrs& layers = object.layers(); + + // Make sure that enforcers vector can be used. + if (! custom_enf.empty()) + enforcers.resize(layers.size()); + + // Iterate over all triangles. + for (int facet_idx : custom_enf) { + + ExPolygon triangle; // To store horizontal projection of the triangle. + + // Min and max z-coord of the triangle. + float max_z = std::numeric_limits::min(); + float min_z = std::numeric_limits::max(); + + // This block transforms the triangle into worlds coords and + // calculates the projection and z-bounds. + { + std::array facet; + Points projection(3); + for (int i=0; i<3; ++i) { + facet[i] = tr2 * tr1 * mesh.its.vertices[mesh.its.indices[facet_idx](i)]; + max_z = std::max(max_z, facet[i].z()); + min_z = std::min(min_z, facet[i].z()); + projection[i] = Point(scale_(facet[i].x()), scale_(facet[i].y())); + projection[i] = projection[i] - object.center_offset(); + } + triangle = ExPolygon(projection); + } + + // We now have the projection of the triangle. + // Find lowest slice not below the triangle. + auto it = std::lower_bound(layers.begin(), layers.end(), min_z, + [](const Layer* l1, float z) { + return l1->slice_z < z; + }); + + // Project the triangles on all slices intersecting the triangle. + // FIXME: This ignores horizontal triangles and does not project + // anything to the slice above max_z. + // FIXME: Each part of the projection should be assigned to one slice only. + // FIXME: The speed of the algorithm might be improved. + while (it != layers.end() && (*it)->slice_z < max_z) { + enforcers[it-layers.begin()].emplace_back(triangle); + ++it; + } + } + /////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// + + + + + + // Output layers, sorted by top Z. MyLayersPtr contact_out; From 7b104bcdd1dee6ed81b269a0781b0922d918d18d Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Fri, 17 Apr 2020 13:16:50 +0200 Subject: [PATCH 04/16] Save z heights of the triangle vertices --- src/libslic3r/SupportMaterial.cpp | 42 ++++++++++++++----------------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/src/libslic3r/SupportMaterial.cpp b/src/libslic3r/SupportMaterial.cpp index dccc8616b..c22bc15f0 100644 --- a/src/libslic3r/SupportMaterial.cpp +++ b/src/libslic3r/SupportMaterial.cpp @@ -994,31 +994,24 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_ // Iterate over all triangles. for (int facet_idx : custom_enf) { + std::array facet; - ExPolygon triangle; // To store horizontal projection of the triangle. - - // Min and max z-coord of the triangle. - float max_z = std::numeric_limits::min(); - float min_z = std::numeric_limits::max(); - - // This block transforms the triangle into worlds coords and - // calculates the projection and z-bounds. - { - std::array facet; - Points projection(3); - for (int i=0; i<3; ++i) { - facet[i] = tr2 * tr1 * mesh.its.vertices[mesh.its.indices[facet_idx](i)]; - max_z = std::max(max_z, facet[i].z()); - min_z = std::min(min_z, facet[i].z()); - projection[i] = Point(scale_(facet[i].x()), scale_(facet[i].y())); - projection[i] = projection[i] - object.center_offset(); - } - triangle = ExPolygon(projection); + // Transform the triangle into worlds coords. + for (int i=0; i<3; ++i) { + facet[i] = tr2 * tr1 * mesh.its.vertices[mesh.its.indices[facet_idx](i)]; + facet[i] -= Vec3f(unscale(object.center_offset().x()), + unscale(object.center_offset().y()), + 0.f); } - // We now have the projection of the triangle. + // Sort the three vertices according the z-coordinate. + std::sort(facet.begin(), facet.end(), + [](const Vec3f& pt1, const Vec3f&pt2) { + return pt1.z() < pt2.z(); + }); + // Find lowest slice not below the triangle. - auto it = std::lower_bound(layers.begin(), layers.end(), min_z, + auto it = std::lower_bound(layers.begin(), layers.end(), facet[0].z(), [](const Layer* l1, float z) { return l1->slice_z < z; }); @@ -1028,8 +1021,11 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_ // anything to the slice above max_z. // FIXME: Each part of the projection should be assigned to one slice only. // FIXME: The speed of the algorithm might be improved. - while (it != layers.end() && (*it)->slice_z < max_z) { - enforcers[it-layers.begin()].emplace_back(triangle); + while (it != layers.end() && (*it)->slice_z < facet[2].z()) { + Polygon plg; + for (const Vec3f& vert : facet) + plg.append(Point::new_scale(vert.x(), vert.y())); + enforcers[it-layers.begin()].emplace_back(ExPolygon(std::move(plg))); ++it; } } From 20068842ec30b919cbcd4027e6807bbfc59ee49c Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Fri, 17 Apr 2020 17:37:23 +0200 Subject: [PATCH 05/16] Project each part of the triangle on one slice only (WIP) --- src/libslic3r/SupportMaterial.cpp | 93 +++++++++++++++++++++++++++++-- 1 file changed, 88 insertions(+), 5 deletions(-) diff --git a/src/libslic3r/SupportMaterial.cpp b/src/libslic3r/SupportMaterial.cpp index c22bc15f0..e23b641bd 100644 --- a/src/libslic3r/SupportMaterial.cpp +++ b/src/libslic3r/SupportMaterial.cpp @@ -26,6 +26,8 @@ #include "SVG.hpp" #endif +#include "SVG.hpp" + // #undef NDEBUG #include @@ -1021,19 +1023,100 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_ // anything to the slice above max_z. // FIXME: Each part of the projection should be assigned to one slice only. // FIXME: The speed of the algorithm might be improved. - while (it != layers.end() && (*it)->slice_z < facet[2].z()) { + + // Calculate how to move points on triangle sides per unit z increment. + Vec2f ta(facet[1].x()-facet[0].x(), facet[1].y()-facet[0].y()); + Vec2f tb(facet[2].x()-facet[0].x(), facet[2].y()-facet[0].y()); + ta /= (facet[1].z() - facet[0].z()); + tb /= (facet[2].z() - facet[0].z()); + + + std::vector proj; + proj.emplace_back(facet[0].x(), facet[0].y()); + + Vec2f a(proj.back()); + Vec2f b(proj.back()); + float last_z = facet[0].z(); + bool passed_first = false; + bool stop = false; + + //////////////// debugging + Polygon trg; + for (const Vec3f& vert : facet) + trg.append(Point::new_scale(vert.x(), vert.y())); + ::Slic3r::SVG::export_expolygons("triangle.svg", trg.bounding_box(), {ExPolygon(trg)}); + /////////////////////////// + +Polygons plgs; + + while (it != layers.end()) { + const float z = (*it)->slice_z; + + if (z > facet[1].z() && ! passed_first) { + a = Vec2f(facet[1].x(), facet[1].y()); + proj.push_back(a); + + ta = Vec2f(facet[2].x()-facet[1].x(), facet[2].y()-facet[1].y()); + ta /= (facet[2].z() - facet[1].z()); + + passed_first = true; + } + + a += ta * (z-last_z); + + + if (z > facet[2].z() || it+1 == layers.end()) { + b = Vec2f(facet[2].x(), facet[2].y()); + stop = true; + } + else { + proj.push_back(a); + b += tb * (z-last_z); + } + proj.push_back(b); + Polygon plg; - for (const Vec3f& vert : facet) - plg.append(Point::new_scale(vert.x(), vert.y())); - enforcers[it-layers.begin()].emplace_back(ExPolygon(std::move(plg))); + for (const Vec2f& vert : proj) + plg.append(Point::new_scale(vert.x(), vert.y())); + + // plg = offset(plg, 100).front(); + enforcers[it-layers.begin()].emplace_back(plg); + + plgs.emplace_back(plg); + + std::ostringstream ss; + ExPolygons explgs; + explgs.emplace_back(plg); + ss << std::setprecision(5) << std::setw(5) << (*it)->print_z; + ::Slic3r::SVG::export_expolygons(ss.str()+".svg", trg.bounding_box(), explgs); + ::Slic3r::SVG::export_expolygons(ss.str()+"_layer.svg", trg.bounding_box(), (*it)->lslices); + + if (stop) + break; + + proj.clear(); + proj.push_back(b); + proj.push_back(a); + ++it; + last_z = z; } + + ExPolygons explgs; + for (const auto& plg : plgs) + explgs.emplace_back(plg); + ::Slic3r::SVG::export_expolygons("plgs.svg", trg.bounding_box(), explgs); + break; } + /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// - +/* + * for (const Vec3f& vert : facet) + plg.append(Point::new_scale(vert.x(), vert.y())); + */ From 79ef456d7c12a91925ca3343c20f0d5d99bbcc5e Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Mon, 20 Apr 2020 18:31:04 +0200 Subject: [PATCH 06/16] Fixed the algorithm so it works for horizontal triangles Partial code cleanup --- src/libslic3r/Point.hpp | 1 + src/libslic3r/SupportMaterial.cpp | 102 +++++++++--------------------- 2 files changed, 32 insertions(+), 71 deletions(-) diff --git a/src/libslic3r/Point.hpp b/src/libslic3r/Point.hpp index e095f1c75..cf07fbcf1 100644 --- a/src/libslic3r/Point.hpp +++ b/src/libslic3r/Point.hpp @@ -114,6 +114,7 @@ public: Point& operator+=(const Point& rhs) { (*this)(0) += rhs(0); (*this)(1) += rhs(1); return *this; } Point& operator-=(const Point& rhs) { (*this)(0) -= rhs(0); (*this)(1) -= rhs(1); return *this; } Point& operator*=(const double &rhs) { (*this)(0) = coord_t((*this)(0) * rhs); (*this)(1) = coord_t((*this)(1) * rhs); return *this; } + Point operator*(const double &rhs) { return Point((*this)(0) * rhs, (*this)(1) * rhs); } void rotate(double angle); void rotate(double angle, const Point ¢er); diff --git a/src/libslic3r/SupportMaterial.cpp b/src/libslic3r/SupportMaterial.cpp index e23b641bd..65835fe9c 100644 --- a/src/libslic3r/SupportMaterial.cpp +++ b/src/libslic3r/SupportMaterial.cpp @@ -26,8 +26,6 @@ #include "SVG.hpp" #endif -#include "SVG.hpp" - // #undef NDEBUG #include @@ -997,99 +995,74 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_ // Iterate over all triangles. for (int facet_idx : custom_enf) { std::array facet; + std::array z_heights; // Transform the triangle into worlds coords. - for (int i=0; i<3; ++i) { + for (int i=0; i<3; ++i) facet[i] = tr2 * tr1 * mesh.its.vertices[mesh.its.indices[facet_idx](i)]; - facet[i] -= Vec3f(unscale(object.center_offset().x()), - unscale(object.center_offset().y()), - 0.f); - } - // Sort the three vertices according the z-coordinate. + // Sort the three vertices according to z-coordinate. std::sort(facet.begin(), facet.end(), [](const Vec3f& pt1, const Vec3f&pt2) { return pt1.z() < pt2.z(); }); + Polygon triangle; + for (int i=0; i<3; ++i) { + z_heights[i] = facet[i].z(); + triangle.append(Point::new_scale(facet[i].x(), facet[i].y())); + triangle.translate(object.center_offset()); + } + // Find lowest slice not below the triangle. - auto it = std::lower_bound(layers.begin(), layers.end(), facet[0].z(), + auto it = std::lower_bound(layers.begin(), layers.end(), z_heights[0], [](const Layer* l1, float z) { return l1->slice_z < z; }); - // Project the triangles on all slices intersecting the triangle. - // FIXME: This ignores horizontal triangles and does not project - // anything to the slice above max_z. - // FIXME: Each part of the projection should be assigned to one slice only. - // FIXME: The speed of the algorithm might be improved. // Calculate how to move points on triangle sides per unit z increment. - Vec2f ta(facet[1].x()-facet[0].x(), facet[1].y()-facet[0].y()); - Vec2f tb(facet[2].x()-facet[0].x(), facet[2].y()-facet[0].y()); - ta /= (facet[1].z() - facet[0].z()); - tb /= (facet[2].z() - facet[0].z()); + Point ta(triangle.points[1] - triangle.points[0]); + Point tb(triangle.points[2] - triangle.points[0]); + ta *= 1./(z_heights[1] - z_heights[0]); + tb *= 1./(z_heights[2] - z_heights[0]); - std::vector proj; - proj.emplace_back(facet[0].x(), facet[0].y()); + Points proj; + proj.emplace_back(triangle.points[0]); - Vec2f a(proj.back()); - Vec2f b(proj.back()); + Point a(proj.back()); + Point b(proj.back()); float last_z = facet[0].z(); bool passed_first = false; bool stop = false; - //////////////// debugging - Polygon trg; - for (const Vec3f& vert : facet) - trg.append(Point::new_scale(vert.x(), vert.y())); - ::Slic3r::SVG::export_expolygons("triangle.svg", trg.bounding_box(), {ExPolygon(trg)}); - /////////////////////////// - -Polygons plgs; - + // Project a sub-triangle on all slices intersecting the triangle. while (it != layers.end()) { const float z = (*it)->slice_z; - if (z > facet[1].z() && ! passed_first) { - a = Vec2f(facet[1].x(), facet[1].y()); + if (z > z_heights[1] && ! passed_first) { + a = triangle.points[1]; + ta = triangle.points[2]-triangle.points[1]; + ta *= 1./(z_heights[2] - z_heights[1]); proj.push_back(a); - - ta = Vec2f(facet[2].x()-facet[1].x(), facet[2].y()-facet[1].y()); - ta /= (facet[2].z() - facet[1].z()); - passed_first = true; } - a += ta * (z-last_z); - - if (z > facet[2].z() || it+1 == layers.end()) { - b = Vec2f(facet[2].x(), facet[2].y()); + if (z > z_heights[2] || it+1 == layers.end()) { + b = triangle.points[2]; + proj.push_back(b); stop = true; } else { - proj.push_back(a); b += tb * (z-last_z); + proj.push_back(a+ta); + proj.push_back(b+tb); } - proj.push_back(b); - Polygon plg; - for (const Vec2f& vert : proj) - plg.append(Point::new_scale(vert.x(), vert.y())); - - // plg = offset(plg, 100).front(); - enforcers[it-layers.begin()].emplace_back(plg); - - plgs.emplace_back(plg); - - std::ostringstream ss; - ExPolygons explgs; - explgs.emplace_back(plg); - ss << std::setprecision(5) << std::setw(5) << (*it)->print_z; - ::Slic3r::SVG::export_expolygons(ss.str()+".svg", trg.bounding_box(), explgs); - ::Slic3r::SVG::export_expolygons(ss.str()+"_layer.svg", trg.bounding_box(), (*it)->lslices); + if (it != layers.begin()) + enforcers[it-layers.begin()-1].emplace_back(proj); if (stop) break; @@ -1101,25 +1074,12 @@ Polygons plgs; ++it; last_z = z; } - - ExPolygons explgs; - for (const auto& plg : plgs) - explgs.emplace_back(plg); - ::Slic3r::SVG::export_expolygons("plgs.svg", trg.bounding_box(), explgs); - break; } /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// -/* - * for (const Vec3f& vert : facet) - plg.append(Point::new_scale(vert.x(), vert.y())); - */ - - - // Output layers, sorted by top Z. MyLayersPtr contact_out; From 7fc4a71715c834e7016caceba67dafa67f8ef141 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Tue, 21 Apr 2020 13:50:47 +0200 Subject: [PATCH 07/16] Moved the projection function into PrintObject.cpp --- src/libslic3r/Print.hpp | 5 ++ src/libslic3r/PrintObject.cpp | 103 +++++++++++++++++++++++++++ src/libslic3r/SupportMaterial.cpp | 112 +----------------------------- 3 files changed, 111 insertions(+), 109 deletions(-) diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index 7180bae17..af32478d6 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -192,6 +192,11 @@ public: std::vector slice_support_blockers() const { return this->slice_support_volumes(ModelVolumeType::SUPPORT_BLOCKER); } std::vector slice_support_enforcers() const { return this->slice_support_volumes(ModelVolumeType::SUPPORT_ENFORCER); } + // Helpers to project custom supports on slices + void project_and_append_custom_supports(FacetSupportType type, std::vector& expolys) const; + void project_and_append_custom_enforcers(std::vector& enforcers) const { project_and_append_custom_supports(FacetSupportType::ENFORCER, enforcers); } + void project_and_append_custom_blockers(std::vector& blockers) const { project_and_append_custom_supports(FacetSupportType::BLOCKER, blockers); } + private: // to be called from Print only. friend class Print; diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 5573f4ac3..bff9198c0 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -2645,4 +2645,107 @@ void PrintObject::_generate_support_material() support_material.generate(*this); } + +void PrintObject::project_and_append_custom_supports( + FacetSupportType type, std::vector& expolys) const +{ + for (const ModelVolume* mv : this->model_object()->volumes) { + const auto& custom_facets = mv->m_supported_facets.get_facets(type); + const TriangleMesh& mesh = mv->mesh(); + const Transform3f& tr1 = mv->get_matrix().cast(); + const Transform3f& tr2 = this->trafo().cast(); + + // List of all layers. + const LayerPtrs& layers = this->layers(); + + // Make sure that enforcers vector can be used. + if (! custom_facets.empty()) + expolys.resize(layers.size()); + + // Iterate over all triangles. + for (int facet_idx : custom_facets) { + std::array facet; + std::array z_heights; + + // Transform the triangle into worlds coords. + for (int i=0; i<3; ++i) + facet[i] = tr2 * tr1 * mesh.its.vertices[mesh.its.indices[facet_idx](i)]; + + // Sort the three vertices according to z-coordinate. + std::sort(facet.begin(), facet.end(), + [](const Vec3f& pt1, const Vec3f&pt2) { + return pt1.z() < pt2.z(); + }); + + Polygon triangle; + for (int i=0; i<3; ++i) { + z_heights[i] = facet[i].z(); + triangle.append(Point::new_scale(facet[i].x(), facet[i].y())); + triangle.translate(this->center_offset()); + } + + // Find lowest slice not below the triangle. + auto it = std::lower_bound(layers.begin(), layers.end(), z_heights[0], + [](const Layer* l1, float z) { + return l1->slice_z < z; + }); + + + // Calculate how to move points on triangle sides per unit z increment. + Point ta(triangle.points[1] - triangle.points[0]); + Point tb(triangle.points[2] - triangle.points[0]); + + ta *= 1./(z_heights[1] - z_heights[0]); + tb *= 1./(z_heights[2] - z_heights[0]); + + Points proj; + proj.emplace_back(triangle.points[0]); + + Point a(proj.back()); + Point b(proj.back()); + float last_z = facet[0].z(); + bool passed_first = false; + bool stop = false; + + // Project a sub-triangle on all slices intersecting the triangle. + while (it != layers.end()) { + const float z = (*it)->slice_z; + + if (z > z_heights[1] && ! passed_first) { + a = triangle.points[1]; + ta = triangle.points[2]-triangle.points[1]; + ta *= 1./(z_heights[2] - z_heights[1]); + proj.push_back(a); + passed_first = true; + } + a += ta * (z-last_z); + + if (z > z_heights[2] || it+1 == layers.end()) { + b = triangle.points[2]; + proj.push_back(b); + stop = true; + } + else { + b += tb * (z-last_z); + proj.push_back(a+ta); + proj.push_back(b+tb); + } + + if (it != layers.begin()) + expolys[it-layers.begin()-1].emplace_back(proj); + + if (stop) + break; + + proj.clear(); + proj.push_back(b); + proj.push_back(a); + + ++it; + last_z = z; + } + } + } +} + } // namespace Slic3r diff --git a/src/libslic3r/SupportMaterial.cpp b/src/libslic3r/SupportMaterial.cpp index 65835fe9c..647c00ec2 100644 --- a/src/libslic3r/SupportMaterial.cpp +++ b/src/libslic3r/SupportMaterial.cpp @@ -971,115 +971,9 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_ std::vector enforcers = object.slice_support_enforcers(); std::vector blockers = object.slice_support_blockers(); - - - - - - /////////////////////////////////////////////////////////////////////////// - /// TEMPORARY INLINE DRAFT PROJECTING CUSTOM SUPPORTS ON SLICES /// - /// /////////////////////////////////////////////////////////////////////// - const auto& data = object.model_object()->volumes.front()->m_supported_facets; - const auto& custom_enf = data.get_facets(FacetSupportType::ENFORCER); - const TriangleMesh& mesh = object.model_object()->volumes.front()->mesh(); - const Transform3f& tr1 = object.model_object()->volumes.front()->get_matrix().cast(); - const Transform3f& tr2 = object.trafo().cast(); - - // Make a list of all layers. - const LayerPtrs& layers = object.layers(); - - // Make sure that enforcers vector can be used. - if (! custom_enf.empty()) - enforcers.resize(layers.size()); - - // Iterate over all triangles. - for (int facet_idx : custom_enf) { - std::array facet; - std::array z_heights; - - // Transform the triangle into worlds coords. - for (int i=0; i<3; ++i) - facet[i] = tr2 * tr1 * mesh.its.vertices[mesh.its.indices[facet_idx](i)]; - - // Sort the three vertices according to z-coordinate. - std::sort(facet.begin(), facet.end(), - [](const Vec3f& pt1, const Vec3f&pt2) { - return pt1.z() < pt2.z(); - }); - - Polygon triangle; - for (int i=0; i<3; ++i) { - z_heights[i] = facet[i].z(); - triangle.append(Point::new_scale(facet[i].x(), facet[i].y())); - triangle.translate(object.center_offset()); - } - - // Find lowest slice not below the triangle. - auto it = std::lower_bound(layers.begin(), layers.end(), z_heights[0], - [](const Layer* l1, float z) { - return l1->slice_z < z; - }); - - - // Calculate how to move points on triangle sides per unit z increment. - Point ta(triangle.points[1] - triangle.points[0]); - Point tb(triangle.points[2] - triangle.points[0]); - - ta *= 1./(z_heights[1] - z_heights[0]); - tb *= 1./(z_heights[2] - z_heights[0]); - - Points proj; - proj.emplace_back(triangle.points[0]); - - Point a(proj.back()); - Point b(proj.back()); - float last_z = facet[0].z(); - bool passed_first = false; - bool stop = false; - - // Project a sub-triangle on all slices intersecting the triangle. - while (it != layers.end()) { - const float z = (*it)->slice_z; - - if (z > z_heights[1] && ! passed_first) { - a = triangle.points[1]; - ta = triangle.points[2]-triangle.points[1]; - ta *= 1./(z_heights[2] - z_heights[1]); - proj.push_back(a); - passed_first = true; - } - a += ta * (z-last_z); - - if (z > z_heights[2] || it+1 == layers.end()) { - b = triangle.points[2]; - proj.push_back(b); - stop = true; - } - else { - b += tb * (z-last_z); - proj.push_back(a+ta); - proj.push_back(b+tb); - } - - if (it != layers.begin()) - enforcers[it-layers.begin()-1].emplace_back(proj); - - if (stop) - break; - - proj.clear(); - proj.push_back(b); - proj.push_back(a); - - ++it; - last_z = z; - } - } - - /////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////// - + // Append custom supports. + object.project_and_append_custom_enforcers(enforcers); + object.project_and_append_custom_blockers(blockers); // Output layers, sorted by top Z. MyLayersPtr contact_out; From 8d95345edef099a27639d6f2854723d64549de41 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 22 Apr 2020 09:24:52 +0200 Subject: [PATCH 08/16] Fixed a logic error in the algorithm The error created extremely large projections of triangles that were close to horizontal --- src/libslic3r/PrintObject.cpp | 80 +++++++++++++++++++---------------- 1 file changed, 44 insertions(+), 36 deletions(-) diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index bff9198c0..1af273f86 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -2655,17 +2655,13 @@ void PrintObject::project_and_append_custom_supports( const Transform3f& tr1 = mv->get_matrix().cast(); const Transform3f& tr2 = this->trafo().cast(); - // List of all layers. - const LayerPtrs& layers = this->layers(); - - // Make sure that enforcers vector can be used. + // Make sure that the output vector can be used. if (! custom_facets.empty()) - expolys.resize(layers.size()); + expolys.resize(layers().size()); // Iterate over all triangles. for (int facet_idx : custom_facets) { std::array facet; - std::array z_heights; // Transform the triangle into worlds coords. for (int i=0; i<3; ++i) @@ -2677,72 +2673,84 @@ void PrintObject::project_and_append_custom_supports( return pt1.z() < pt2.z(); }); - Polygon triangle; + std::array trianglef; for (int i=0; i<3; ++i) { - z_heights[i] = facet[i].z(); - triangle.append(Point::new_scale(facet[i].x(), facet[i].y())); - triangle.translate(this->center_offset()); + trianglef[i] = Vec2f(facet[i].x(), facet[i].y()); + trianglef[i] += Vec2f(unscale(this->center_offset().x()), + unscale(this->center_offset().y())); } // Find lowest slice not below the triangle. - auto it = std::lower_bound(layers.begin(), layers.end(), z_heights[0], + auto it = std::lower_bound(layers().begin(), layers().end(), facet[0].z()+EPSILON, [](const Layer* l1, float z) { return l1->slice_z < z; }); - // Calculate how to move points on triangle sides per unit z increment. - Point ta(triangle.points[1] - triangle.points[0]); - Point tb(triangle.points[2] - triangle.points[0]); + Vec2f ta(trianglef[1] - trianglef[0]); + Vec2f tb(trianglef[2] - trianglef[0]); + ta *= 1./(facet[1].z() - facet[0].z()); + tb *= 1./(facet[2].z() - facet[0].z()); - ta *= 1./(z_heights[1] - z_heights[0]); - tb *= 1./(z_heights[2] - z_heights[0]); + // Projection on current slice. + std::vector proj; + proj.emplace_back(trianglef[0]); - Points proj; - proj.emplace_back(triangle.points[0]); - - Point a(proj.back()); - Point b(proj.back()); - float last_z = facet[0].z(); + // Projections of triangle sides intersections with slices. + // a moves along one side, b tracks the other. + Vec2f a(proj.back()); + Vec2f b(proj.back()); bool passed_first = false; bool stop = false; // Project a sub-triangle on all slices intersecting the triangle. - while (it != layers.end()) { + while (it != layers().end()) { const float z = (*it)->slice_z; - if (z > z_heights[1] && ! passed_first) { - a = triangle.points[1]; - ta = triangle.points[2]-triangle.points[1]; - ta *= 1./(z_heights[2] - z_heights[1]); - proj.push_back(a); + // If the middle vertex was already passed, append the vertex + // and make it track the remaining side. + if (z > facet[1].z() && ! passed_first) { + proj.push_back(trianglef[1]); + a = trianglef[1]; + ta = trianglef[2]-trianglef[1]; + ta *= 1./(facet[2].z() - facet[1].z()); passed_first = true; } - a += ta * (z-last_z); - if (z > z_heights[2] || it+1 == layers.end()) { - b = triangle.points[2]; + // Move a along the side it currently tracks to get + // projected intersection with current slice. + a = passed_first ? (trianglef[1]+ta*(z-facet[1].z())) + : (trianglef[0]+ta*(z-facet[0].z())); + + // This slice is above the triangle already. + if (z > facet[2].z() || it+1 == layers().end()) { + b = trianglef[2]; proj.push_back(b); stop = true; } else { - b += tb * (z-last_z); - proj.push_back(a+ta); + b = trianglef[0]+tb*(z-facet[0].z()); + proj.push_back(a); proj.push_back(b+tb); } - if (it != layers.begin()) - expolys[it-layers.begin()-1].emplace_back(proj); + if (it != layers().begin()) { + Points pts; + for (const Vec2f& pt : proj) + pts.emplace_back(scale_(pt.x()), scale_(pt.y())); + expolys[it-layers().begin()-1].emplace_back(pts); + } if (stop) break; + // Use a and b as first two points of the polygon + // for the next layer. proj.clear(); proj.push_back(b); proj.push_back(a); ++it; - last_z = z; } } } From d74b5cb1da10da3ae7e01b8ff5465c4df25f529e Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 22 Apr 2020 11:16:28 +0200 Subject: [PATCH 09/16] Custom supports data change forces invalidation of supports step --- src/libslic3r/Model.cpp | 10 ++++++++++ src/libslic3r/Model.hpp | 17 ++++++++++------- src/libslic3r/Print.cpp | 8 +++++--- 3 files changed, 25 insertions(+), 10 deletions(-) diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 56c1f8b7e..f11bd5be0 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -1948,6 +1948,16 @@ bool model_volume_list_changed(const ModelObject &model_object_old, const ModelO return false; } +bool model_custom_supports_data_changed(const ModelObject& mo, const ModelObject& mo_new) { + assert(! model_volume_list_changed(mo, mo_new, ModelVolumeType::MODEL_PART)); + assert(mo.volumes.size() == mo_new.volumes.size()); + for (size_t i=0; im_supported_facets.is_same_as(mo.volumes[i]->m_supported_facets)) + return true; + } + return false; +}; + extern bool model_has_multi_part_objects(const Model &model) { for (const ModelObject *model_object : model.objects) diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 33fc8a622..81f177a9c 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -215,8 +215,8 @@ public: when user expects that. */ Vec3d origin_translation; - Model* get_model() { return m_model; }; - const Model* get_model() const { return m_model; }; + Model* get_model() { return m_model; } + const Model* get_model() const { return m_model; } ModelVolume* add_volume(const TriangleMesh &mesh); ModelVolume* add_volume(TriangleMesh &&mesh); @@ -402,14 +402,13 @@ class FacetsAnnotation { public: using ClockType = std::chrono::steady_clock; - std::vector get_facets(FacetSupportType type) const; void set_facet(int idx, FacetSupportType type); void clear(); ClockType::time_point get_timestamp() const { return timestamp; } - bool is_newer_than(const FacetsAnnotation& other) const { - return timestamp > other.get_timestamp(); + bool is_same_as(const FacetsAnnotation& other) const { + return timestamp == other.get_timestamp(); } private: @@ -455,7 +454,7 @@ public: FacetsAnnotation m_supported_facets; // A parent object owning this modifier volume. - ModelObject* get_object() const { return this->object; }; + ModelObject* get_object() const { return this->object; } ModelVolumeType type() const { return m_type; } void set_type(const ModelVolumeType t) { m_type = t; } bool is_model_part() const { return m_type == ModelVolumeType::MODEL_PART; } @@ -859,7 +858,7 @@ public: std::string propose_export_file_name_and_path(const std::string &new_extension) const; private: - explicit Model(int) : ObjectBase(-1) { assert(this->id().invalid()); }; + explicit Model(int) : ObjectBase(-1) { assert(this->id().invalid()); } void assign_new_unique_ids_recursive(); void update_links_bottom_up_recursive(); @@ -886,6 +885,10 @@ extern bool model_object_list_extended(const Model &model_old, const Model &mode // than the old ModelObject. extern bool model_volume_list_changed(const ModelObject &model_object_old, const ModelObject &model_object_new, const ModelVolumeType type); +// Test whether the now ModelObject has newer custom supports data than the old one. +// The function assumes that volumes list is synchronized. +extern bool model_custom_supports_data_changed(const ModelObject& mo, const ModelObject& mo_new); + // If the model has multi-part objects, then it is currently not supported by the SLA mode. // Either the model cannot be loaded, or a SLA printer has to be activated. extern bool model_has_multi_part_objects(const Model &model); diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index facc5f521..2af9909de 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -855,7 +855,7 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ } // Copy content of the ModelObject including its ID, do not change the parent. model_object.assign_copy(model_object_new); - } else if (support_blockers_differ || support_enforcers_differ) { + } else if (support_blockers_differ || support_enforcers_differ || model_custom_supports_data_changed(model_object, model_object_new)) { // First stop background processing before shuffling or deleting the ModelVolumes in the ModelObject's list. this->call_cancel_callback(); update_apply_status(false); @@ -863,8 +863,10 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ auto range = print_object_status.equal_range(PrintObjectStatus(model_object.id())); for (auto it = range.first; it != range.second; ++ it) update_apply_status(it->print_object->invalidate_step(posSupportMaterial)); - // Copy just the support volumes. - model_volume_list_update_supports(model_object, model_object_new); + if (support_enforcers_differ || support_blockers_differ) { + // Copy just the support volumes. + model_volume_list_update_supports(model_object, model_object_new); + } } if (! model_parts_differ && ! modifiers_differ) { // Synchronize Object's config. From 1e12863ceb4809f08d97932fa1f93e5a583787cf Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 22 Apr 2020 11:34:11 +0200 Subject: [PATCH 10/16] FDM custom supports gizmo now has a 'Remove all' button --- src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp index d7883331d..8094d10ad 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp @@ -46,6 +46,7 @@ bool GLGizmoFdmSupports::on_init() m_desc["block"] = _L("Block supports"); m_desc["remove_caption"] = _L("Shift + Left mouse button") + ": "; m_desc["remove"] = _L("Remove selection"); + m_desc["remove_all"] = _L("Remove all"); return true; } @@ -493,6 +494,7 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l // First calculate width of all the texts that are could possibly be shown. We will decide set the dialog width based on that: const float clipping_slider_left = std::max(m_imgui->calc_text_size(m_desc.at("clipping_of_view")).x, m_imgui->calc_text_size(m_desc.at("reset_direction")).x) + m_imgui->scaled(1.5f); const float cursor_slider_left = m_imgui->calc_text_size(m_desc.at("cursor_size")).x + m_imgui->scaled(1.f); + const float button_width = m_imgui->calc_text_size(m_desc.at("remove_all")).x + m_imgui->scaled(1.f); const float minimal_slider_width = m_imgui->scaled(4.f); float caption_max = 0.f; @@ -506,6 +508,7 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l float window_width = minimal_slider_width + std::max(cursor_slider_left, clipping_slider_left); window_width = std::max(window_width, total_text_max); + window_width = std::max(window_width, button_width); auto draw_text_with_caption = [this, &caption_max](const wxString& caption, const wxString& text) { static const ImVec4 ORANGE(1.0f, 0.49f, 0.22f, 1.0f); @@ -521,6 +524,20 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l m_imgui->text(""); + if (m_imgui->button(m_desc.at("remove_all"))) { + ModelObject* mo = m_c->selection_info()->model_object(); + int idx = -1; + for (ModelVolume* mv : mo->volumes) { + ++idx; + if (mv->is_model_part()) { + m_selected_facets[idx].assign(m_selected_facets[idx].size(), FacetSupportType::NONE); + mv->m_supported_facets.clear(); + update_vertex_buffers(mv, idx, true, true); + m_parent.set_as_dirty(); + } + } + } + const float max_tooltip_width = ImGui::GetFontSize() * 20.0f; m_imgui->text(m_desc.at("cursor_size")); From a40d60ce089c52c5e0789259b099faa9a72b9344 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 22 Apr 2020 14:01:29 +0200 Subject: [PATCH 11/16] Custom support generation now ignores triangles with upward-pointing normal --- src/libslic3r/PrintObject.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 1af273f86..360c690f8 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -2667,6 +2667,10 @@ void PrintObject::project_and_append_custom_supports( for (int i=0; i<3; ++i) facet[i] = tr2 * tr1 * mesh.its.vertices[mesh.its.indices[facet_idx](i)]; + // Ignore triangles with upward-pointing normal. + if ((facet[1]-facet[0]).cross(facet[2]-facet[0]).z() > 0.) + continue; + // Sort the three vertices according to z-coordinate. std::sort(facet.begin(), facet.end(), [](const Vec3f& pt1, const Vec3f&pt2) { From 61e5eab35dc2cf5578d71bd18171fbd8d99c7578 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 22 Apr 2020 16:08:36 +0200 Subject: [PATCH 12/16] Custom supports projection now runs in parallel --- src/libslic3r/PrintObject.cpp | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 360c690f8..a376b6f4a 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -2650,22 +2650,32 @@ void PrintObject::project_and_append_custom_supports( FacetSupportType type, std::vector& expolys) const { for (const ModelVolume* mv : this->model_object()->volumes) { - const auto& custom_facets = mv->m_supported_facets.get_facets(type); + const std::vector& custom_facets = mv->m_supported_facets.get_facets(type); const TriangleMesh& mesh = mv->mesh(); const Transform3f& tr1 = mv->get_matrix().cast(); const Transform3f& tr2 = this->trafo().cast(); + // Structure to collect projected polygons. One element for each triangle. + // Saves list of (layer_id, polygon) pair. + std::vector>> layer_polygon_pairs_per_triangle(custom_facets.size()); + // Make sure that the output vector can be used. - if (! custom_facets.empty()) + if (custom_facets.empty()) + continue; + else expolys.resize(layers().size()); // Iterate over all triangles. - for (int facet_idx : custom_facets) { + tbb::parallel_for( + tbb::blocked_range(0, custom_facets.size() - 1), + [&](const tbb::blocked_range& range) { + for (size_t idx = range.begin(); idx < range.end(); ++ idx) { + std::array facet; // Transform the triangle into worlds coords. for (int i=0; i<3; ++i) - facet[i] = tr2 * tr1 * mesh.its.vertices[mesh.its.indices[facet_idx](i)]; + facet[i] = tr2 * tr1 * mesh.its.vertices[mesh.its.indices[custom_facets[idx]](i)]; // Ignore triangles with upward-pointing normal. if ((facet[1]-facet[0]).cross(facet[2]-facet[0]).z() > 0.) @@ -2739,10 +2749,10 @@ void PrintObject::project_and_append_custom_supports( } if (it != layers().begin()) { - Points pts; + ExPolygon explg; for (const Vec2f& pt : proj) - pts.emplace_back(scale_(pt.x()), scale_(pt.y())); - expolys[it-layers().begin()-1].emplace_back(pts); + explg.contour.points.emplace_back(scale_(pt.x()), scale_(pt.y())); + layer_polygon_pairs_per_triangle[idx].emplace_back(int(it-layers().begin()-1), std::move(explg)); } if (stop) @@ -2757,7 +2767,16 @@ void PrintObject::project_and_append_custom_supports( ++it; } } - } + }); // end of parallel_for + + // Now append the collected polygons to respective layers. + for (auto& trg : layer_polygon_pairs_per_triangle) { + for (auto& [layer_id, expolygon] : trg) { + expolys[layer_id].emplace_back(std::move(expolygon)); + } + } + + } // loop over ModelVolumes } } // namespace Slic3r From 5a80f0442f024ab171ed6cab65aa84f9ca257e38 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Fri, 24 Apr 2020 01:01:47 +0200 Subject: [PATCH 13/16] Optimization of the custom support projection algorithm - transformation matrix is precalculated for each volume - number of heap allocations was reduced --- src/libslic3r/PrintObject.cpp | 123 +++++++++++++++++++++------------- 1 file changed, 77 insertions(+), 46 deletions(-) diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index a376b6f4a..fdd99226d 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -2650,20 +2650,39 @@ void PrintObject::project_and_append_custom_supports( FacetSupportType type, std::vector& expolys) const { for (const ModelVolume* mv : this->model_object()->volumes) { - const std::vector& custom_facets = mv->m_supported_facets.get_facets(type); + const std::vector custom_facets = mv->m_supported_facets.get_facets(type); + if (custom_facets.empty()) + continue; + const TriangleMesh& mesh = mv->mesh(); const Transform3f& tr1 = mv->get_matrix().cast(); const Transform3f& tr2 = this->trafo().cast(); + const Transform3f tr = tr2 * tr1; + + + // The projection will be at most a pentagon. Let's minimize heap + // reallocations by saving in in the following struct. + // Points are used so that scaling can be done in parallel + // and they can be moved from to create an ExPolygon later. + struct LightPolygon { + LightPolygon() { pts.reserve(5); } + Points pts; + + void add(const Vec2f& pt) { + pts.emplace_back(scale_(pt.x()), scale_(pt.y())); + assert(pts.size <= 5); + } + }; // Structure to collect projected polygons. One element for each triangle. - // Saves list of (layer_id, polygon) pair. - std::vector>> layer_polygon_pairs_per_triangle(custom_facets.size()); + // Saves vector of polygons and layer_id of the first one. + struct TriangleProjections { + size_t first_layer_id; + std::vector polygons; + }; - // Make sure that the output vector can be used. - if (custom_facets.empty()) - continue; - else - expolys.resize(layers().size()); + // Vector to collect resulting projections from each triangle. + std::vector projections_of_triangles(custom_facets.size()); // Iterate over all triangles. tbb::parallel_for( @@ -2675,7 +2694,7 @@ void PrintObject::project_and_append_custom_supports( // Transform the triangle into worlds coords. for (int i=0; i<3; ++i) - facet[i] = tr2 * tr1 * mesh.its.vertices[mesh.its.indices[custom_facets[idx]](i)]; + facet[i] = tr * mesh.its.vertices[mesh.its.indices[custom_facets[idx]](i)]; // Ignore triangles with upward-pointing normal. if ((facet[1]-facet[0]).cross(facet[2]-facet[0]).z() > 0.) @@ -2700,79 +2719,91 @@ void PrintObject::project_and_append_custom_supports( return l1->slice_z < z; }); + // Count how many projections will be generated for this triangle + // and allocate respective amount in projections_of_triangles. + projections_of_triangles[idx].first_layer_id = it-layers().begin(); + size_t last_layer_id = projections_of_triangles[idx].first_layer_id; + // The cast in the condition below is important. The comparison must + // be an exact opposite of the one lower in the code where + // the polygons are appended. And that one is on floats. + while (last_layer_id + 1 < layers().size() + && float(layers()[last_layer_id]->slice_z) <= facet[2].z()) + ++last_layer_id; + projections_of_triangles[idx].polygons.resize( + last_layer_id - projections_of_triangles[idx].first_layer_id + 1); + // Calculate how to move points on triangle sides per unit z increment. Vec2f ta(trianglef[1] - trianglef[0]); Vec2f tb(trianglef[2] - trianglef[0]); ta *= 1./(facet[1].z() - facet[0].z()); tb *= 1./(facet[2].z() - facet[0].z()); - // Projection on current slice. - std::vector proj; - proj.emplace_back(trianglef[0]); + // Projection on current slice will be build directly in place. + LightPolygon* proj = &projections_of_triangles[idx].polygons[0]; + proj->add(trianglef[0]); - // Projections of triangle sides intersections with slices. - // a moves along one side, b tracks the other. - Vec2f a(proj.back()); - Vec2f b(proj.back()); bool passed_first = false; bool stop = false; - // Project a sub-triangle on all slices intersecting the triangle. + // Project a sub-polygon on all slices intersecting the triangle. while (it != layers().end()) { const float z = (*it)->slice_z; + // Projections of triangle sides intersections with slices. + // a moves along one side, b tracks the other. + Vec2f a; + Vec2f b; + // If the middle vertex was already passed, append the vertex - // and make it track the remaining side. + // and use ta for tracking the remaining side. if (z > facet[1].z() && ! passed_first) { - proj.push_back(trianglef[1]); - a = trianglef[1]; + proj->add(trianglef[1]); ta = trianglef[2]-trianglef[1]; ta *= 1./(facet[2].z() - facet[1].z()); passed_first = true; } - // Move a along the side it currently tracks to get - // projected intersection with current slice. - a = passed_first ? (trianglef[1]+ta*(z-facet[1].z())) - : (trianglef[0]+ta*(z-facet[0].z())); - // This slice is above the triangle already. if (z > facet[2].z() || it+1 == layers().end()) { - b = trianglef[2]; - proj.push_back(b); + proj->add(trianglef[2]); stop = true; } else { + // Move a, b along the side it currently tracks to get + // projected intersection with current slice. + a = passed_first ? (trianglef[1]+ta*(z-facet[1].z())) + : (trianglef[0]+ta*(z-facet[0].z())); b = trianglef[0]+tb*(z-facet[0].z()); - proj.push_back(a); - proj.push_back(b+tb); + proj->add(a); + proj->add(b); } - if (it != layers().begin()) { - ExPolygon explg; - for (const Vec2f& pt : proj) - explg.contour.points.emplace_back(scale_(pt.x()), scale_(pt.y())); - layer_polygon_pairs_per_triangle[idx].emplace_back(int(it-layers().begin()-1), std::move(explg)); - } - - if (stop) + if (stop) break; - // Use a and b as first two points of the polygon - // for the next layer. - proj.clear(); - proj.push_back(b); - proj.push_back(a); - + // Advance to the next layer. ++it; + ++proj; + assert(proj <= &projections_of_triangles[idx].polygons.back() ); + + // a, b are first two points of the polygon for the next layer. + proj->add(b); + proj->add(a); } } }); // end of parallel_for + // Make sure that the output vector can be used. + expolys.resize(layers().size()); + // Now append the collected polygons to respective layers. - for (auto& trg : layer_polygon_pairs_per_triangle) { - for (auto& [layer_id, expolygon] : trg) { - expolys[layer_id].emplace_back(std::move(expolygon)); + for (auto& trg : projections_of_triangles) { + int layer_id = trg.first_layer_id; + if (layer_id == 0) + continue; + for (const LightPolygon& poly : trg.polygons) { + expolys[layer_id-1].emplace_back(std::move(poly.pts)); + ++layer_id; } } From bf2a10803e8c90a278d4e6d5b9fd75383aa23679 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Mon, 27 Apr 2020 12:15:45 +0200 Subject: [PATCH 14/16] Fixing debug build broken after recent merge --- src/libslic3r/PrintObject.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index fdd99226d..1370b4d0f 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -2670,7 +2670,7 @@ void PrintObject::project_and_append_custom_supports( void add(const Vec2f& pt) { pts.emplace_back(scale_(pt.x()), scale_(pt.y())); - assert(pts.size <= 5); + assert(pts.size() <= 5); } }; From 9fdc54bfffbcb72241a0cbaa5960ed7d15f36c0b Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Mon, 27 Apr 2020 13:02:16 +0200 Subject: [PATCH 15/16] Fix app crash on startup under Linux/GTK3/Wayland config --- src/PrusaSlicer.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/PrusaSlicer.cpp b/src/PrusaSlicer.cpp index 751df6fbf..9efecb50c 100644 --- a/src/PrusaSlicer.cpp +++ b/src/PrusaSlicer.cpp @@ -57,6 +57,14 @@ using namespace Slic3r; int CLI::run(int argc, char **argv) { + +#ifdef __WXGTK__ + // On Linux, wxGTK has no support for Wayland, and the app crashes on + // startup if gtk3 is used. This env var has to be set explicitly to + // instruct the window manager to fall back to X server mode. + ::setenv("GDK_BACKEND", "x11", /* replace */ true); +#endif + // Switch boost::filesystem to utf8. try { boost::nowide::nowide_filesystem(); From 2bd524849ad8aeeb8fb96f29c9ef9d28dfeaa727 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Mon, 27 Apr 2020 17:43:34 +0200 Subject: [PATCH 16/16] Custom support blockers are now working --- src/libslic3r/PrintObject.cpp | 7 +++---- src/libslic3r/SupportMaterial.cpp | 23 +++++++++++++++-------- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 1370b4d0f..34b17c7bf 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -2686,7 +2686,7 @@ void PrintObject::project_and_append_custom_supports( // Iterate over all triangles. tbb::parallel_for( - tbb::blocked_range(0, custom_facets.size() - 1), + tbb::blocked_range(0, custom_facets.size()), [&](const tbb::blocked_range& range) { for (size_t idx = range.begin(); idx < range.end(); ++ idx) { @@ -2799,10 +2799,9 @@ void PrintObject::project_and_append_custom_supports( // Now append the collected polygons to respective layers. for (auto& trg : projections_of_triangles) { int layer_id = trg.first_layer_id; - if (layer_id == 0) - continue; + for (const LightPolygon& poly : trg.polygons) { - expolys[layer_id-1].emplace_back(std::move(poly.pts)); + expolys[layer_id].emplace_back(std::move(poly.pts)); ++layer_id; } } diff --git a/src/libslic3r/SupportMaterial.cpp b/src/libslic3r/SupportMaterial.cpp index 647c00ec2..6cde050cf 100644 --- a/src/libslic3r/SupportMaterial.cpp +++ b/src/libslic3r/SupportMaterial.cpp @@ -1101,10 +1101,10 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_ if (! enforcers.empty()) { // Apply the "support enforcers". //FIXME add the "enforcers" to the sparse support regions only. - const ExPolygons &enforcer = enforcers[layer_id - 1]; + const ExPolygons &enforcer = enforcers[layer_id]; if (! enforcer.empty()) { // Enforce supports (as if with 90 degrees of slope) for the regions covered by the enforcer meshes. - Polygons new_contacts = diff(intersection(layerm_polygons, to_polygons(enforcer)), + Polygons new_contacts = diff(intersection(layerm_polygons, to_polygons(std::move(enforcer))), offset(lower_layer_polygons, 0.05f * fw, SUPPORT_SURFACES_OFFSET_PARAMETERS)); if (! new_contacts.empty()) { if (diff_polygons.empty()) @@ -1115,19 +1115,26 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_ } } } - // Apply the "support blockers". - if (! diff_polygons.empty() && ! blockers.empty() && ! blockers[layer_id].empty()) { - // Enforce supports (as if with 90 degrees of slope) for the regions covered by the enforcer meshes. - diff_polygons = diff(diff_polygons, to_polygons(blockers[layer_id])); - } + if (diff_polygons.empty()) continue; + // Apply the "support blockers". + if (! blockers.empty() && ! blockers[layer_id].empty()) { + // Expand the blocker a bit. Custom blockers produce strips + // spanning just the projection between the two slices. + // Subtracting them as they are may leave unwanted narrow + // residues of diff_polygons that would then be supported. + diff_polygons = diff(diff_polygons, + offset(union_(to_polygons(std::move(blockers[layer_id]))), + 1000.*SCALED_EPSILON)); + } + #ifdef SLIC3R_DEBUG { ::Slic3r::SVG svg(debug_out_path("support-top-contacts-raw-run%d-layer%d-region%d.svg", iRun, layer_id, - std::find_if(layer.regions.begin(), layer.regions.end(), [layerm](const LayerRegion* other){return other == layerm;}) - layer.regions.begin()), + std::find_if(layer.regions.begin(), layer.regions.end(), [layerm](const LayerRegion* other){return other == layerm;}) - layer.regions.begin()), get_extents(diff_polygons)); Slic3r::ExPolygons expolys = union_ex(diff_polygons, false); svg.draw(expolys);