From 5a84b46ec9a037adf677489d2051b3baef9fe4e1 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Thu, 16 Sep 2021 13:38:02 +0200 Subject: [PATCH 001/102] Fix of detection of the out of bed state for sinking objects --- src/libslic3r/Technologies.hpp | 2 ++ src/libslic3r/TriangleMesh.cpp | 26 ++++++++++++++++++++++++++ src/libslic3r/TriangleMesh.hpp | 4 ++++ src/slic3r/GUI/3DScene.cpp | 21 +++++++++++++++++++++ src/slic3r/GUI/3DScene.hpp | 18 ++++++++++++++++++ 5 files changed, 71 insertions(+) diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index 8da21d56a..df7414eda 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -62,6 +62,8 @@ #define ENABLE_FIX_PREVIEW_OPTIONS_Z (1 && ENABLE_SEAMS_USING_MODELS && ENABLE_2_4_0_ALPHA2) // Enable replacing a missing file during reload from disk command #define ENABLE_RELOAD_FROM_DISK_REPLACE_FILE (1 && ENABLE_2_4_0_ALPHA2) +// Enable the fix for the detection of the out of bed state for sinking objects +#define ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION (1 && ENABLE_2_4_0_ALPHA2) #endif // _prusaslicer_technologies_h_ diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp index d289fca14..822548412 100644 --- a/src/libslic3r/TriangleMesh.cpp +++ b/src/libslic3r/TriangleMesh.cpp @@ -574,6 +574,32 @@ BoundingBoxf3 TriangleMesh::transformed_bounding_box(const Transform3d &trafo) c return bbox; } +#if ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION +BoundingBoxf3 TriangleMesh::transformed_bounding_box(const Transform3d& trafo, double world_min_z) const +{ + assert(!its.vertices.empty()); + + BoundingBoxf3 bbox; + // add vertices above the cut + for (const stl_vertex& v : its.vertices) { + const Vec3d world_v = trafo * v.cast(); + if (world_v.z() > world_min_z) + bbox.merge(world_v); + } + + // add new vertices along the cut + MeshSlicingParams slicing_params; + slicing_params.trafo = trafo; + Polygons polygons = union_(slice_mesh(its, world_min_z, slicing_params)); + for (const Polygon& polygon : polygons) { + for (const Point& p : polygon.points) { + bbox.merge(unscale(p.x(), p.y(), world_min_z)); + } + } + return bbox; +} +#endif // ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION + TriangleMesh TriangleMesh::convex_hull_3d() const { // The qhull call: diff --git a/src/libslic3r/TriangleMesh.hpp b/src/libslic3r/TriangleMesh.hpp index 60ab975c4..a603dd064 100644 --- a/src/libslic3r/TriangleMesh.hpp +++ b/src/libslic3r/TriangleMesh.hpp @@ -57,6 +57,10 @@ public: BoundingBoxf3 bounding_box() const; // Returns the bbox of this TriangleMesh transformed by the given transformation BoundingBoxf3 transformed_bounding_box(const Transform3d &trafo) const; +#if ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION + // Variant returning the bbox of the part of this TriangleMesh above the given world_min_z + BoundingBoxf3 transformed_bounding_box(const Transform3d& trafo, double world_min_z) const; +#endif // ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION // Return the size of the mesh in coordinates. Vec3d size() const { return stl.stats.size.cast(); } /// Return the center of the related bounding box. diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index f693143c4..19864b36a 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -524,6 +524,23 @@ BoundingBoxf3 GLVolume::transformed_convex_hull_bounding_box(const Transform3d & bounding_box().transformed(trafo); } +#if ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION +BoundingBoxf3 GLVolume::transformed_non_sinking_bounding_box(const Transform3d& trafo) const +{ + return GUI::wxGetApp().plater()->model().objects[object_idx()]->volumes[volume_idx()]->mesh().transformed_bounding_box(trafo, 0.0); +} + +const BoundingBoxf3& GLVolume::transformed_non_sinking_bounding_box() const +{ + if (!m_transformed_non_sinking_bounding_box.has_value()) { + std::optional* trans_box = const_cast*>(&m_transformed_non_sinking_bounding_box); + const Transform3d& trafo = world_matrix(); + *trans_box = transformed_non_sinking_bounding_box(trafo); + } + return *m_transformed_non_sinking_bounding_box; +} +#endif // ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION + void GLVolume::set_range(double min_z, double max_z) { this->qverts_range.first = 0; @@ -936,7 +953,11 @@ bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, M if (volume->is_modifier || (!volume->shader_outside_printer_detection_enabled && (volume->is_wipe_tower || volume->composite_id.volume_id < 0))) continue; +#if ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION + const BoundingBoxf3& bb = volume->transformed_non_sinking_bounding_box(); +#else const BoundingBoxf3& bb = volume->transformed_convex_hull_bounding_box(); +#endif // ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION bool contained = print_volume.contains(bb); volume->is_outside = !contained; diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index 78b9a96d9..4db1611e7 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -279,6 +279,10 @@ private: std::shared_ptr m_convex_hull; // Bounding box of this volume, in unscaled coordinates. std::optional m_transformed_convex_hull_bounding_box; +#if ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION + // Bounding box of the non sinking part of this volume, in unscaled coordinates. + std::optional m_transformed_non_sinking_bounding_box; +#endif // ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION class SinkingContours { @@ -469,6 +473,12 @@ public: BoundingBoxf3 transformed_convex_hull_bounding_box(const Transform3d &trafo) const; // caching variant const BoundingBoxf3& transformed_convex_hull_bounding_box() const; +#if ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION + // non-caching variant + BoundingBoxf3 transformed_non_sinking_bounding_box(const Transform3d& trafo) const; + // caching variant + const BoundingBoxf3& transformed_non_sinking_bounding_box() const; +#endif // ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION // convex hull const TriangleMesh* convex_hull() const { return m_convex_hull.get(); } @@ -481,7 +491,15 @@ public: void finalize_geometry(bool opengl_initialized) { this->indexed_vertex_array.finalize_geometry(opengl_initialized); } void release_geometry() { this->indexed_vertex_array.release_geometry(); } +#if ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION + void set_bounding_boxes_as_dirty() { + m_transformed_bounding_box.reset(); + m_transformed_convex_hull_bounding_box.reset(); + m_transformed_non_sinking_bounding_box.reset(); + } +#else void set_bounding_boxes_as_dirty() { m_transformed_bounding_box.reset(); m_transformed_convex_hull_bounding_box.reset(); } +#endif // ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION bool is_sla_support() const; bool is_sla_pad() const; From 2f95c7721f9a1093bf87be296eacfc3800439981 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 17 Sep 2021 08:42:01 +0200 Subject: [PATCH 002/102] Follow-up of 5a84b46ec9a037adf677489d2051b3baef9fe4e1 - Faster implementation of method TriangleMesh::transformed_bounding_box(const Transform3d& trafo, double world_min_z) --- src/libslic3r/TriangleMesh.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp index 822548412..c8bc2f763 100644 --- a/src/libslic3r/TriangleMesh.cpp +++ b/src/libslic3r/TriangleMesh.cpp @@ -588,14 +588,12 @@ BoundingBoxf3 TriangleMesh::transformed_bounding_box(const Transform3d& trafo, d } // add new vertices along the cut - MeshSlicingParams slicing_params; - slicing_params.trafo = trafo; - Polygons polygons = union_(slice_mesh(its, world_min_z, slicing_params)); - for (const Polygon& polygon : polygons) { - for (const Point& p : polygon.points) { - bbox.merge(unscale(p.x(), p.y(), world_min_z)); - } + Points all_pts; + its_collect_mesh_projection_points_above(its, trafo.cast(), static_cast(world_min_z), all_pts); + for (const Point& p : all_pts) { + bbox.merge(unscale(p.x(), p.y(), world_min_z)); } + return bbox; } #endif // ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION From 6d70ada637fc5a95afe8a7c3a3cfb68d42cb7711 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 17 Sep 2021 09:45:50 +0200 Subject: [PATCH 003/102] Follow-up of 2f95c7721f9a1093bf87be296eacfc3800439981 - Even faster implementation of method TriangleMesh::transformed_bounding_box(const Transform3d& trafo, double world_min_z) --- src/libslic3r/TriangleMesh.cpp | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp index c8bc2f763..cfd3436b2 100644 --- a/src/libslic3r/TriangleMesh.cpp +++ b/src/libslic3r/TriangleMesh.cpp @@ -577,23 +577,24 @@ BoundingBoxf3 TriangleMesh::transformed_bounding_box(const Transform3d &trafo) c #if ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION BoundingBoxf3 TriangleMesh::transformed_bounding_box(const Transform3d& trafo, double world_min_z) const { - assert(!its.vertices.empty()); - BoundingBoxf3 bbox; - // add vertices above the cut - for (const stl_vertex& v : its.vertices) { - const Vec3d world_v = trafo * v.cast(); - if (world_v.z() > world_min_z) - bbox.merge(world_v); + const Transform3f ftrafo = trafo.cast(); + for (const stl_triangle_vertex_indices& tri : its.indices) { + const Vec3f pts[3] = { ftrafo * its.vertices[tri(0)], ftrafo * its.vertices[tri(1)], ftrafo * its.vertices[tri(2)] }; + int iprev = 2; + for (int iedge = 0; iedge < 3; ++iedge) { + const Vec3f& p1 = pts[iprev]; + const Vec3f& p2 = pts[iedge]; + if ((p1.z() < world_min_z && p2.z() > world_min_z) || (p2.z() < world_min_z && p1.z() > world_min_z)) { + // Edge crosses the z plane. Calculate intersection point with the plane. + const float t = (world_min_z - p1.z()) / (p2.z() - p1.z()); + bbox.merge(Vec3f(p1.x() + (p2.x() - p1.x()) * t, p1.y() + (p2.y() - p1.y()) * t, world_min_z).cast()); + } + if (p2.z() >= world_min_z) + bbox.merge(p2.cast()); + iprev = iedge; + } } - - // add new vertices along the cut - Points all_pts; - its_collect_mesh_projection_points_above(its, trafo.cast(), static_cast(world_min_z), all_pts); - for (const Point& p : all_pts) { - bbox.merge(unscale(p.x(), p.y(), world_min_z)); - } - return bbox; } #endif // ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION From 92bf9a664d94474892ac27f33fa011599cedeeb0 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 17 Sep 2021 14:47:19 +0200 Subject: [PATCH 004/102] Fix of detection of the out of bed state for sinking objects in backend --- src/libslic3r/Model.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 2844f644c..4efa0264a 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -1545,7 +1545,11 @@ unsigned int ModelObject::check_instances_print_volume_state(const BoundingBoxf3 unsigned int inside_outside = 0; for (const ModelVolume *vol : this->volumes) if (vol->is_model_part()) { +#if ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION + BoundingBoxf3 bb = vol->mesh().transformed_bounding_box(model_instance->get_matrix() * vol->get_matrix(), 0.0); +#else BoundingBoxf3 bb = vol->get_convex_hull().transformed_bounding_box(model_instance->get_matrix() * vol->get_matrix()); +#endif // ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION if (print_volume.contains(bb)) inside_outside |= INSIDE; else if (print_volume.intersects(bb)) From 1af0c5c73b779ac00ef3d54a7f9af4709781491b Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 20 Sep 2021 13:40:34 +0200 Subject: [PATCH 005/102] Tech ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS - Call GLVolumeCollection::check_outside_state() only when needed --- src/libslic3r/Technologies.hpp | 2 ++ src/slic3r/GUI/3DScene.cpp | 13 ++++++------- src/slic3r/GUI/GLCanvas3D.cpp | 9 ++++++++- src/slic3r/GUI/GLCanvas3D.hpp | 6 ++++++ src/slic3r/GUI/Selection.cpp | 25 +++++++++++++++++-------- 5 files changed, 39 insertions(+), 16 deletions(-) diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index 20fc0a38f..1ca589fe8 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -62,6 +62,8 @@ #define ENABLE_RELOAD_FROM_DISK_REPLACE_FILE (1 && ENABLE_2_4_0_ALPHA2) // Enable the fix for the detection of the out of bed state for sinking objects #define ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION (1 && ENABLE_2_4_0_ALPHA2) +// Enable detection of out of bed using the bed perimeter and other improvements +#define ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS (1 && ENABLE_2_4_0_ALPHA2) #endif // _prusaslicer_technologies_h_ diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 19864b36a..3aba88a56 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -936,14 +936,13 @@ bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, M const BoundingBox bed_box_2D = get_extents(Polygon::new_scale(opt->values)); BoundingBoxf3 print_volume({ unscale(bed_box_2D.min.x()), unscale(bed_box_2D.min.y()), 0.0 }, - { unscale(bed_box_2D.max.x()), unscale(bed_box_2D.max.y()), - config->opt_float("max_print_height") }); + { unscale(bed_box_2D.max.x()), unscale(bed_box_2D.max.y()), config->opt_float("max_print_height") }); // Allow the objects to protrude below the print bed - print_volume.min(2) = -1e10; - print_volume.min(0) -= BedEpsilon; - print_volume.min(1) -= BedEpsilon; - print_volume.max(0) += BedEpsilon; - print_volume.max(1) += BedEpsilon; + print_volume.min.z() = -1e10; + print_volume.min.x() -= BedEpsilon; + print_volume.min.y() -= BedEpsilon; + print_volume.max.x() += BedEpsilon; + print_volume.max.y() += BedEpsilon; ModelInstanceEPrintVolumeState state = ModelInstancePVS_Inside; diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 83b907f01..68b0fd5f4 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -5074,8 +5074,15 @@ void GLCanvas3D::_render_objects(GLVolumeCollection::ERenderType type) if (m_config != nullptr) { const BoundingBoxf3& bed_bb = wxGetApp().plater()->get_bed().get_bounding_box(false); - m_volumes.set_print_box((float)bed_bb.min(0) - BedEpsilon, (float)bed_bb.min(1) - BedEpsilon, 0.0f, (float)bed_bb.max(0) + BedEpsilon, (float)bed_bb.max(1) + BedEpsilon, (float)m_config->opt_float("max_print_height")); + m_volumes.set_print_box((float)bed_bb.min.x() - BedEpsilon, (float)bed_bb.min.y() - BedEpsilon, 0.0f, (float)bed_bb.max.x() + BedEpsilon, (float)bed_bb.max.y() + BedEpsilon, (float)m_config->opt_float("max_print_height")); +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + if (m_requires_check_outside_state) { + m_volumes.check_outside_state(m_config, nullptr); + m_requires_check_outside_state = false; + } +#else m_volumes.check_outside_state(m_config, nullptr); +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS } } diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index e03c4a71d..bbdcb9de6 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -475,6 +475,9 @@ private: const DynamicPrintConfig* m_config; Model* m_model; BackgroundSlicingProcess *m_process; +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + bool m_requires_check_outside_state{ false }; +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS std::array m_old_size{ 0, 0 }; @@ -611,6 +614,9 @@ public: void post_event(wxEvent &&event); void set_as_dirty(); +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + void requires_check_outside_state() { m_requires_check_outside_state = true; } +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS unsigned int get_volumes_count() const; const GLVolumeCollection& get_volumes() const { return m_volumes; } diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index 4a9c7cd56..6946bab0e 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -715,6 +715,9 @@ void Selection::translate(const Vec3d& displacement, bool local) ensure_not_below_bed(); set_bounding_boxes_dirty(); +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + wxGetApp().plater()->canvas3D()->requires_check_outside_state(); +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS } // Rotate an object around one of the axes. Only one rotation component is expected to be changing. @@ -827,7 +830,10 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_ volume.set_volume_offset(volume.get_volume_offset() + center_local - center_local_new); } - this->set_bounding_boxes_dirty(); + set_bounding_boxes_dirty(); +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + wxGetApp().plater()->canvas3D()->requires_check_outside_state(); +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS } void Selection::flattening_rotate(const Vec3d& normal) @@ -926,6 +932,9 @@ void Selection::scale(const Vec3d& scale, TransformationType transformation_type ensure_on_bed(); set_bounding_boxes_dirty(); +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + wxGetApp().plater()->canvas3D()->requires_check_outside_state(); +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS } void Selection::scale_to_fit_print_volume(const DynamicPrintConfig& config) @@ -2125,10 +2134,10 @@ void Selection::ensure_not_below_bed() GLVolume* volume = (*m_volumes)[i]; if (!volume->is_wipe_tower && !volume->is_modifier) { const double max_z = volume->transformed_convex_hull_bounding_box().max.z(); - std::pair instance = std::make_pair(volume->object_idx(), volume->instance_idx()); + const std::pair instance = std::make_pair(volume->object_idx(), volume->instance_idx()); InstancesToZMap::iterator it = instances_max_z.find(instance); if (it == instances_max_z.end()) - it = instances_max_z.insert(InstancesToZMap::value_type(instance, -DBL_MAX)).first; + it = instances_max_z.insert({ instance, -DBL_MAX }).first; it->second = std::max(it->second, max_z); } @@ -2137,17 +2146,17 @@ void Selection::ensure_not_below_bed() if (is_any_volume()) { for (unsigned int i : m_list) { GLVolume& volume = *(*m_volumes)[i]; - std::pair instance = std::make_pair(volume.object_idx(), volume.instance_idx()); - InstancesToZMap::iterator it = instances_max_z.find(instance); - double z_shift = SINKING_MIN_Z_THRESHOLD - it->second; + const std::pair instance = std::make_pair(volume.object_idx(), volume.instance_idx()); + InstancesToZMap::const_iterator it = instances_max_z.find(instance); + const double z_shift = SINKING_MIN_Z_THRESHOLD - it->second; if (it != instances_max_z.end() && z_shift > 0.0) volume.set_volume_offset(Z, volume.get_volume_offset(Z) + z_shift); } } else { for (GLVolume* volume : *m_volumes) { - std::pair instance = std::make_pair(volume->object_idx(), volume->instance_idx()); - InstancesToZMap::iterator it = instances_max_z.find(instance); + const std::pair instance = std::make_pair(volume->object_idx(), volume->instance_idx()); + InstancesToZMap::const_iterator it = instances_max_z.find(instance); if (it != instances_max_z.end() && it->second < SINKING_MIN_Z_THRESHOLD) volume->set_instance_offset(Z, volume->get_instance_offset(Z) + SINKING_MIN_Z_THRESHOLD - it->second); } From cf380fb4564fec4bd731e34819102f66fda23e75 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 21 Sep 2021 13:51:57 +0200 Subject: [PATCH 006/102] Tech ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS - Out of bed detection for circular printbeds --- resources/shaders/gouraud_mod.fs | 130 +++++++++++ resources/shaders/gouraud_mod.vs | 78 +++++++ src/libslic3r/Geometry.cpp | 9 + src/libslic3r/Geometry.hpp | 3 + src/libslic3r/Line.cpp | 7 + src/libslic3r/Line.hpp | 4 + src/slic3r/GUI/3DBed.cpp | 100 ++++++++- src/slic3r/GUI/3DBed.hpp | 37 +++- src/slic3r/GUI/3DScene.cpp | 54 +++++ src/slic3r/GUI/3DScene.hpp | 24 ++ src/slic3r/GUI/BedShapeDialog.cpp | 208 ++++++++++++------ src/slic3r/GUI/BedShapeDialog.hpp | 17 ++ src/slic3r/GUI/GLCanvas3D.cpp | 64 ++++++ src/slic3r/GUI/GLShadersManager.cpp | 16 +- .../GUI/Gizmos/GLGizmoMmuSegmentation.cpp | 4 + src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp | 16 ++ 16 files changed, 692 insertions(+), 79 deletions(-) create mode 100644 resources/shaders/gouraud_mod.fs create mode 100644 resources/shaders/gouraud_mod.vs diff --git a/resources/shaders/gouraud_mod.fs b/resources/shaders/gouraud_mod.fs new file mode 100644 index 000000000..959c9cb27 --- /dev/null +++ b/resources/shaders/gouraud_mod.fs @@ -0,0 +1,130 @@ +#version 110 + +#define INTENSITY_CORRECTION 0.6 + +// normalized values for (-0.6/1.31, 0.6/1.31, 1./1.31) +const vec3 LIGHT_TOP_DIR = vec3(-0.4574957, 0.4574957, 0.7624929); +#define LIGHT_TOP_DIFFUSE (0.8 * INTENSITY_CORRECTION) +#define LIGHT_TOP_SPECULAR (0.125 * INTENSITY_CORRECTION) +#define LIGHT_TOP_SHININESS 20.0 + +// normalized values for (1./1.43, 0.2/1.43, 1./1.43) +const vec3 LIGHT_FRONT_DIR = vec3(0.6985074, 0.1397015, 0.6985074); +#define LIGHT_FRONT_DIFFUSE (0.3 * INTENSITY_CORRECTION) + +#define INTENSITY_AMBIENT 0.3 + +const vec3 ZERO = vec3(0.0, 0.0, 0.0); +const vec3 GREEN = vec3(0.0, 0.7, 0.0); +const vec3 YELLOW = vec3(0.5, 0.7, 0.0); +const vec3 RED = vec3(0.7, 0.0, 0.0); +const vec3 WHITE = vec3(1.0, 1.0, 1.0); +const float EPSILON = 0.0001; +const float BANDS_WIDTH = 10.0; + +struct PrintVolumeDetection +{ + // 0 = rectangle, 1 = circle, 2 = custom, 3 = invalid + int type; + // type = 0 (rectangle): + // x = min.x, y = min.y, z = max.x, w = max.y + // type = 1 (circle): + // x = center.x, y = center.y, z = radius + vec4 xy_data; + // x = min z, y = max z + vec2 z_data; +}; + +struct SlopeDetection +{ + bool actived; + float normal_z; + mat3 volume_world_normal_matrix; +}; + +uniform vec4 uniform_color; +uniform SlopeDetection slope; + +#ifdef ENABLE_ENVIRONMENT_MAP + uniform sampler2D environment_tex; + uniform bool use_environment_tex; +#endif // ENABLE_ENVIRONMENT_MAP + +varying vec3 clipping_planes_dots; + +// x = diffuse, y = specular; +varying vec2 intensity; + +uniform PrintVolumeDetection print_volume; + +varying vec4 model_pos; +varying vec4 world_pos; +varying float world_normal_z; +varying vec3 eye_normal; + +uniform bool compute_triangle_normals_in_fs; + +void main() +{ + if (any(lessThan(clipping_planes_dots, ZERO))) + discard; + vec3 color = uniform_color.rgb; + float alpha = uniform_color.a; + + vec2 intensity_fs = intensity; + vec3 eye_normal_fs = eye_normal; + float world_normal_z_fs = world_normal_z; + if (compute_triangle_normals_in_fs) { + vec3 triangle_normal = normalize(cross(dFdx(model_pos.xyz), dFdy(model_pos.xyz))); +#ifdef FLIP_TRIANGLE_NORMALS + triangle_normal = -triangle_normal; +#endif + + // First transform the normal into camera space and normalize the result. + eye_normal_fs = normalize(gl_NormalMatrix * triangle_normal); + + // Compute the cos of the angle between the normal and lights direction. The light is directional so the direction is constant for every vertex. + // Since these two are normalized the cosine is the dot product. We also need to clamp the result to the [0,1] range. + float NdotL = max(dot(eye_normal_fs, LIGHT_TOP_DIR), 0.0); + + intensity_fs = vec2(0.0, 0.0); + intensity_fs.x = INTENSITY_AMBIENT + NdotL * LIGHT_TOP_DIFFUSE; + vec3 position = (gl_ModelViewMatrix * model_pos).xyz; + intensity_fs.y = LIGHT_TOP_SPECULAR * pow(max(dot(-normalize(position), reflect(-LIGHT_TOP_DIR, eye_normal_fs)), 0.0), LIGHT_TOP_SHININESS); + + // Perform the same lighting calculation for the 2nd light source (no specular applied). + NdotL = max(dot(eye_normal_fs, LIGHT_FRONT_DIR), 0.0); + intensity_fs.x += NdotL * LIGHT_FRONT_DIFFUSE; + + // z component of normal vector in world coordinate used for slope shading + world_normal_z_fs = slope.actived ? (normalize(slope.volume_world_normal_matrix * triangle_normal)).z : 0.0; + } + + if (slope.actived && world_normal_z_fs < slope.normal_z - EPSILON) { + color = vec3(0.7, 0.7, 1.0); + alpha = 1.0; + } + + // if the fragment is outside the print volume -> use darker color + vec3 pv_check_min = ZERO; + vec3 pv_check_max = ZERO; + if (print_volume.type == 0) { + // rectangle + pv_check_min = world_pos.xyz - vec3(print_volume.xy_data.x, print_volume.xy_data.y, print_volume.z_data.x); + pv_check_max = world_pos.xyz - vec3(print_volume.xy_data.z, print_volume.xy_data.w, print_volume.z_data.y); + } + else if (print_volume.type == 1) { + // circle + float delta_radius = print_volume.xy_data.z - distance(world_pos.xy, print_volume.xy_data.xy); + pv_check_min = vec3(delta_radius, 0.0, world_pos.z - print_volume.z_data.x); + pv_check_max = vec3(0.0, 0.0, world_pos.z - print_volume.z_data.y); + } + color = (any(lessThan(pv_check_min, ZERO)) || any(greaterThan(pv_check_max, ZERO))) ? mix(color, ZERO, 0.3333) : color; + +#ifdef ENABLE_ENVIRONMENT_MAP + if (use_environment_tex) + gl_FragColor = vec4(0.45 * texture2D(environment_tex, normalize(eye_normal_fs).xy * 0.5 + 0.5).xyz + 0.8 * color * intensity_fs.x, alpha); + else +#endif + gl_FragColor = vec4(vec3(intensity_fs.y) + color * intensity_fs.x, alpha); +} diff --git a/resources/shaders/gouraud_mod.vs b/resources/shaders/gouraud_mod.vs new file mode 100644 index 000000000..bc83c38fb --- /dev/null +++ b/resources/shaders/gouraud_mod.vs @@ -0,0 +1,78 @@ +#version 110 + +#define INTENSITY_CORRECTION 0.6 + +// normalized values for (-0.6/1.31, 0.6/1.31, 1./1.31) +const vec3 LIGHT_TOP_DIR = vec3(-0.4574957, 0.4574957, 0.7624929); +#define LIGHT_TOP_DIFFUSE (0.8 * INTENSITY_CORRECTION) +#define LIGHT_TOP_SPECULAR (0.125 * INTENSITY_CORRECTION) +#define LIGHT_TOP_SHININESS 20.0 + +// normalized values for (1./1.43, 0.2/1.43, 1./1.43) +const vec3 LIGHT_FRONT_DIR = vec3(0.6985074, 0.1397015, 0.6985074); +#define LIGHT_FRONT_DIFFUSE (0.3 * INTENSITY_CORRECTION) +//#define LIGHT_FRONT_SPECULAR (0.0 * INTENSITY_CORRECTION) +//#define LIGHT_FRONT_SHININESS 5.0 + +#define INTENSITY_AMBIENT 0.3 + +const vec3 ZERO = vec3(0.0, 0.0, 0.0); + +struct SlopeDetection +{ + bool actived; + float normal_z; + mat3 volume_world_normal_matrix; +}; + +uniform mat4 volume_world_matrix; +uniform SlopeDetection slope; + +// Clipping plane, x = min z, y = max z. Used by the FFF and SLA previews to clip with a top / bottom plane. +uniform vec2 z_range; +// Clipping plane - general orientation. Used by the SLA gizmo. +uniform vec4 clipping_plane; + +// x = diffuse, y = specular; +varying vec2 intensity; + +varying vec3 clipping_planes_dots; + +varying vec4 model_pos; +varying vec4 world_pos; +varying float world_normal_z; +varying vec3 eye_normal; + +uniform bool compute_triangle_normals_in_fs; + +void main() +{ + if (!compute_triangle_normals_in_fs) { + // First transform the normal into camera space and normalize the result. + eye_normal = normalize(gl_NormalMatrix * gl_Normal); + + // Compute the cos of the angle between the normal and lights direction. The light is directional so the direction is constant for every vertex. + // Since these two are normalized the cosine is the dot product. We also need to clamp the result to the [0,1] range. + float NdotL = max(dot(eye_normal, LIGHT_TOP_DIR), 0.0); + + intensity.x = INTENSITY_AMBIENT + NdotL * LIGHT_TOP_DIFFUSE; + vec3 position = (gl_ModelViewMatrix * gl_Vertex).xyz; + intensity.y = LIGHT_TOP_SPECULAR * pow(max(dot(-normalize(position), reflect(-LIGHT_TOP_DIR, eye_normal)), 0.0), LIGHT_TOP_SHININESS); + + // Perform the same lighting calculation for the 2nd light source (no specular applied). + NdotL = max(dot(eye_normal, LIGHT_FRONT_DIR), 0.0); + intensity.x += NdotL * LIGHT_FRONT_DIFFUSE; + } + + model_pos = gl_Vertex; + // Point in homogenous coordinates. + world_pos = volume_world_matrix * gl_Vertex; + + // z component of normal vector in world coordinate used for slope shading + if (!compute_triangle_normals_in_fs) + world_normal_z = slope.actived ? (normalize(slope.volume_world_normal_matrix * gl_Normal)).z : 0.0; + + gl_Position = ftransform(); + // Fill in the scalars for fragment shader clipping. Fragments with any of these components lower than zero are discarded. + clipping_planes_dots = vec3(dot(world_pos, clipping_plane), world_pos.z - z_range.x, z_range.y - world_pos.z); +} diff --git a/src/libslic3r/Geometry.cpp b/src/libslic3r/Geometry.cpp index 321443204..c4d48efd4 100644 --- a/src/libslic3r/Geometry.cpp +++ b/src/libslic3r/Geometry.cpp @@ -305,6 +305,15 @@ bool directions_parallel(double angle1, double angle2, double max_diff) return diff < max_diff || fabs(diff - PI) < max_diff; } +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS +bool directions_perpendicular(double angle1, double angle2, double max_diff) +{ + double diff = fabs(angle1 - angle2); + max_diff += EPSILON; + return fabs(diff - 0.5 * PI) < max_diff || fabs(diff - 1.5 * PI) < max_diff; +} +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + template bool contains(const std::vector &vector, const Point &point) { diff --git a/src/libslic3r/Geometry.hpp b/src/libslic3r/Geometry.hpp index c6af515c8..2ac19b502 100644 --- a/src/libslic3r/Geometry.hpp +++ b/src/libslic3r/Geometry.hpp @@ -336,6 +336,9 @@ Polygon convex_hull(Points points); Polygon convex_hull(const Polygons &polygons); bool directions_parallel(double angle1, double angle2, double max_diff = 0); +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS +bool directions_perpendicular(double angle1, double angle2, double max_diff = 0); +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS template bool contains(const std::vector &vector, const Point &point); template T rad2deg(T angle) { return T(180.0) * angle / T(PI); } double rad2deg_dir(double angle); diff --git a/src/libslic3r/Line.cpp b/src/libslic3r/Line.cpp index 8a2a2875b..1a96b8b1f 100644 --- a/src/libslic3r/Line.cpp +++ b/src/libslic3r/Line.cpp @@ -63,6 +63,13 @@ bool Line::parallel_to(double angle) const return Slic3r::Geometry::directions_parallel(this->direction(), angle); } +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS +bool Line::perpendicular_to(double angle) const +{ + return Slic3r::Geometry::directions_perpendicular(this->direction(), angle); +} +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + bool Line::intersection(const Line &l2, Point *intersection) const { const Line &l1 = *this; diff --git a/src/libslic3r/Line.hpp b/src/libslic3r/Line.hpp index b62775bfe..b662daa2b 100644 --- a/src/libslic3r/Line.hpp +++ b/src/libslic3r/Line.hpp @@ -85,6 +85,10 @@ public: double perp_distance_to(const Point &point) const; bool parallel_to(double angle) const; bool parallel_to(const Line &line) const { return this->parallel_to(line.direction()); } +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + bool perpendicular_to(double angle) const; + bool perpendicular_to(const Line& line) const { return this->perpendicular_to(line.direction()); } +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS double atan2_() const { return atan2(this->b(1) - this->a(1), this->b(0) - this->a(0)); } double orientation() const; double direction() const; diff --git a/src/slic3r/GUI/3DBed.cpp b/src/slic3r/GUI/3DBed.cpp index 5b7218c87..6e04664e2 100644 --- a/src/slic3r/GUI/3DBed.cpp +++ b/src/slic3r/GUI/3DBed.cpp @@ -7,11 +7,10 @@ #include "libslic3r/BoundingBox.hpp" #include "libslic3r/Geometry.hpp" #include "libslic3r/Tesselate.hpp" +#include "libslic3r/PresetBundle.hpp" #include "GUI_App.hpp" -#include "libslic3r/PresetBundle.hpp" #include "GLCanvas3D.hpp" -#include "3DScene.hpp" #include @@ -154,7 +153,11 @@ bool Bed3D::set_shape(const Pointfs& shape, const std::string& custom_texture, c std::string model; std::string texture; if (force_as_custom) +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + type = EType::Custom; +#else type = Custom; +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS else { auto [new_type, system_model, system_texture] = detect_type(shape); type = new_type; @@ -174,7 +177,12 @@ bool Bed3D::set_shape(const Pointfs& shape, const std::string& custom_texture, c model_filename.clear(); } +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + EShapeType shape_type = detect_shape_type(shape); + if (m_shape == shape && m_type == type && m_shape_type == shape_type && m_texture_filename == texture_filename && m_model_filename == model_filename) +#else if (m_shape == shape && m_type == type && m_texture_filename == texture_filename && m_model_filename == model_filename) +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS // No change, no need to update the UI. return false; @@ -182,6 +190,9 @@ bool Bed3D::set_shape(const Pointfs& shape, const std::string& custom_texture, c m_texture_filename = texture_filename; m_model_filename = model_filename; m_type = type; +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + m_shape_type = shape_type; +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS calc_bounding_boxes(); @@ -229,6 +240,77 @@ void Bed3D::render_for_picking(GLCanvas3D& canvas, bool bottom, float scale_fact render_internal(canvas, bottom, scale_factor, false, false, true); } +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS +bool Bed3D::is_rectangle(const Pointfs& shape, Vec2d* min, Vec2d* max) +{ + const Lines lines = Polygon::new_scale(shape).lines(); + bool ret = lines.size() == 4 && lines[0].parallel_to(lines[2]) && lines[1].parallel_to(lines[3]) && lines[0].perpendicular_to(lines[1]); + if (ret) { + if (min != nullptr) { + *min = shape.front(); + for (const Vec2d& pt : shape) { + min->x() = std::min(min->x(), pt.x()); + min->y() = std::min(min->y(), pt.y()); + } + } + if (max != nullptr) { + *max = shape.front(); + for (const Vec2d& pt : shape) { + max->x() = std::max(max->x(), pt.x()); + max->y() = std::max(max->y(), pt.y()); + } + } + } + return ret; +} + +bool Bed3D::is_circle(const Pointfs& shape, Vec2d* center, double* radius) +{ + if (shape.size() < 3) + return false; + + // Analyze the array of points. + // Do they reside on a circle ? + const Vec2d box_center = BoundingBoxf(shape).center(); + std::vector vertex_distances; + double avg_dist = 0.0; + for (const Vec2d& pt : shape) { + double distance = (pt - box_center).norm(); + vertex_distances.push_back(distance); + avg_dist += distance; + } + + avg_dist /= vertex_distances.size(); + + bool defined_value = true; + for (double el : vertex_distances) { + if (fabs(el - avg_dist) > 10.0 * SCALED_EPSILON) + defined_value = false; + break; + } + + if (center != nullptr) + *center = box_center; + + if (radius != nullptr) + *radius = avg_dist; + + return defined_value; +} + +Bed3D::EShapeType Bed3D::detect_shape_type(const Pointfs& shape) +{ + if (shape.size() < 3) + return EShapeType::Invalid; + else if (is_rectangle(shape)) + return EShapeType::Rectangle; + else if (is_circle(shape)) + return EShapeType::Circle; + else + return EShapeType::Custom; +} +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + void Bed3D::render_internal(GLCanvas3D& canvas, bool bottom, float scale_factor, bool show_axes, bool show_texture, bool picking) { @@ -244,9 +326,15 @@ void Bed3D::render_internal(GLCanvas3D& canvas, bool bottom, float scale_factor, switch (m_type) { +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + case EType::System: { render_system(canvas, bottom, show_texture); break; } + default: + case EType::Custom: { render_custom(canvas, bottom, show_texture, picking); break; } +#else case System: { render_system(canvas, bottom, show_texture); break; } default: case Custom: { render_custom(canvas, bottom, show_texture, picking); break; } +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS } glsafe(::glDisable(GL_DEPTH_TEST)); @@ -320,7 +408,11 @@ std::tuple Bed3D::detect_type(const Poin std::string model_filename = PresetUtils::system_printer_bed_model(*curr); std::string texture_filename = PresetUtils::system_printer_bed_texture(*curr); if (!model_filename.empty() && !texture_filename.empty()) +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + return { EType::System, model_filename, texture_filename }; +#else return { System, model_filename, texture_filename }; +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS } } @@ -328,7 +420,11 @@ std::tuple Bed3D::detect_type(const Poin } } +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + return { EType::Custom, "", "" }; +#else return { Custom, "", "" }; +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS } void Bed3D::render_axes() const diff --git a/src/slic3r/GUI/3DBed.hpp b/src/slic3r/GUI/3DBed.hpp index a2a643519..baa0ef5b7 100644 --- a/src/slic3r/GUI/3DBed.hpp +++ b/src/slic3r/GUI/3DBed.hpp @@ -62,15 +62,36 @@ class Bed3D }; public: +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + enum class EType : unsigned char + { + System, + Custom + }; + + enum class EShapeType : unsigned char + { + Rectangle, + Circle, + Custom, + Invalid + }; +#else enum EType : unsigned char { System, Custom, Num_Types }; +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS private: +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + EType m_type{ EType::Custom }; + EShapeType m_shape_type{ EShapeType::Invalid }; +#else EType m_type{ Custom }; +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS Pointfs m_shape; std::string m_texture_filename; std::string m_model_filename; @@ -94,16 +115,18 @@ public: ~Bed3D() { reset(); } EType get_type() const { return m_type; } - +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + EShapeType get_shape_type() const { return m_shape_type; } + bool is_custom() const { return m_type == EType::Custom; } +#else bool is_custom() const { return m_type == Custom; } +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS const Pointfs& get_shape() const { return m_shape; } // 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, bool force_as_custom = false); - 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; @@ -113,6 +136,12 @@ public: void render_for_picking(GLCanvas3D& canvas, bool bottom, float scale_factor); +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + static bool is_rectangle(const Pointfs& shape, Vec2d* min = nullptr, Vec2d* max = nullptr); + static bool is_circle(const Pointfs& shape, Vec2d* center = nullptr, double* radius = nullptr); + static EShapeType detect_shape_type(const Pointfs& shape); +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + private: void calc_bounding_boxes() const; void calc_triangles(const ExPolygon& poly); diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 3aba88a56..59535910d 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -873,10 +873,17 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type, bool disab shader->set_uniform("uniform_color", volume.first->render_color); shader->set_uniform("z_range", m_z_range, 2); shader->set_uniform("clipping_plane", m_clipping_plane, 4); +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + shader->set_uniform("print_volume.type", static_cast(m_print_volume.type)); + shader->set_uniform("print_volume.xy_data", m_print_volume.data); + shader->set_uniform("print_volume.z_data", m_print_volume.zs); + shader->set_uniform("volume_world_matrix", volume.first->world_matrix()); +#else shader->set_uniform("print_box.min", m_print_box_min, 3); shader->set_uniform("print_box.max", m_print_box_max, 3); shader->set_uniform("print_box.actived", volume.first->shader_outside_printer_detection_enabled); shader->set_uniform("print_box.volume_world_matrix", volume.first->world_matrix()); +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS shader->set_uniform("slope.actived", m_slope.active && !volume.first->is_modifier && !volume.first->is_wipe_tower); shader->set_uniform("slope.volume_world_normal_matrix", static_cast(volume.first->world_matrix().matrix().block(0, 0, 3, 3).inverse().transpose().cast())); shader->set_uniform("slope.normal_z", m_slope.normal_z); @@ -925,6 +932,31 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type, bool disab glsafe(::glDisable(GL_BLEND)); } +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS +static bool same(const Polygon& lhs, const Polygon& rhs) +{ + if (lhs.points.size() != rhs.points.size()) + return false; + + size_t rhs_id = 0; + while (rhs_id < rhs.points.size()) { + if (rhs.points[rhs_id].isApprox(lhs.points.front())) + break; + ++rhs_id; + } + + if (rhs_id == rhs.points.size()) + return false; + + for (size_t i = 0; i < lhs.points.size(); ++i) { + if (!lhs.points[i].isApprox(rhs.points[(i + rhs_id) % lhs.points.size()])) + return false; + } + + return true; +} +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, ModelInstanceEPrintVolumeState* out_state) const { if (config == nullptr) @@ -934,6 +966,10 @@ bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, M if (opt == nullptr) return false; +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + const Polygon bed_poly = offset(Polygon::new_scale(opt->values), static_cast(scale_(BedEpsilon))).front(); + const float bed_height = config->opt_float("max_print_height"); +#else const BoundingBox bed_box_2D = get_extents(Polygon::new_scale(opt->values)); BoundingBoxf3 print_volume({ unscale(bed_box_2D.min.x()), unscale(bed_box_2D.min.y()), 0.0 }, { unscale(bed_box_2D.max.x()), unscale(bed_box_2D.max.y()), config->opt_float("max_print_height") }); @@ -943,6 +979,7 @@ bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, M print_volume.min.y() -= BedEpsilon; print_volume.max.x() += BedEpsilon; print_volume.max.y() += BedEpsilon; +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS ModelInstanceEPrintVolumeState state = ModelInstancePVS_Inside; @@ -957,7 +994,19 @@ bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, M #else const BoundingBoxf3& bb = volume->transformed_convex_hull_bounding_box(); #endif // ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + const indexed_triangle_set& its = GUI::wxGetApp().plater()->model().objects[volume->object_idx()]->volumes[volume->volume_idx()]->mesh().its; + const Polygon volume_hull_2d = its_convex_hull_2d_above(its, volume->world_matrix().cast(), 0.0f); + Polygons intersection_polys = intersection(bed_poly, volume_hull_2d); + bool contained_xy = !intersection_polys.empty() && same(intersection_polys.front(), volume_hull_2d); + bool contained_z = -1e10 < bb.min.z() && bb.max.z() < bed_height; + bool contained = contained_xy && contained_z; + bool intersects_xy = !contained_xy && !intersection_polys.empty(); + bool intersects_z = !contained_z && bb.min.z() < bed_height && -1e10 < bb.max.z(); + bool intersects = intersects_xy || intersects_z; +#else bool contained = print_volume.contains(bb); +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS volume->is_outside = !contained; if (!volume->printable) @@ -968,8 +1017,13 @@ bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, M if (state == ModelInstancePVS_Inside && volume->is_outside) state = ModelInstancePVS_Fully_Outside; +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + if (state == ModelInstancePVS_Fully_Outside && volume->is_outside && intersects) + state = ModelInstancePVS_Partly_Outside; +#else if (state == ModelInstancePVS_Fully_Outside && volume->is_outside && print_volume.intersects(bb)) state = ModelInstancePVS_Partly_Outside; +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS } if (out_state != nullptr) diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index 4db1611e7..9bfd6edeb 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -532,10 +532,30 @@ public: All }; +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + struct PrintVolume + { + // see: Bed3D::EShapeType + int type{ 0 }; + // data contains: + // Rectangle: + // [0] = min.x, [1] = min.y, [2] = max.x, [3] = max.y + // Circle: + // [0] = center.x, [1] = center.y, [3] = radius + std::array data; + // [0] = min z, [1] = max z + std::array zs; + }; +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + private: +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + PrintVolume m_print_volume; +#else // min and max vertex of the print box volume float m_print_box_min[3]; float m_print_box_max[3]; +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS // z range for clipping in shaders float m_z_range[2]; @@ -607,10 +627,14 @@ public: bool empty() const { return volumes.empty(); } void set_range(double low, double high) { for (GLVolume *vol : this->volumes) vol->set_range(low, high); } +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + void set_print_volume(const PrintVolume& print_volume) { m_print_volume = print_volume; } +#else void set_print_box(float min_x, float min_y, float min_z, float max_x, float max_y, float max_z) { m_print_box_min[0] = min_x; m_print_box_min[1] = min_y; m_print_box_min[2] = min_z; m_print_box_max[0] = max_x; m_print_box_max[1] = max_y; m_print_box_max[2] = max_z; } +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS void set_z_range(float min_z, float max_z) { m_z_range[0] = min_z; m_z_range[1] = max_z; } void set_clipping_plane(const double* coeffs) { m_clipping_plane[0] = coeffs[0]; m_clipping_plane[1] = coeffs[1]; m_clipping_plane[2] = coeffs[2]; m_clipping_plane[3] = coeffs[3]; } diff --git a/src/slic3r/GUI/BedShapeDialog.cpp b/src/slic3r/GUI/BedShapeDialog.cpp index 40d9ee3b2..0b8e31e13 100644 --- a/src/slic3r/GUI/BedShapeDialog.cpp +++ b/src/slic3r/GUI/BedShapeDialog.cpp @@ -22,9 +22,25 @@ namespace GUI { BedShape::BedShape(const ConfigOptionPoints& points) { - auto polygon = Polygon::new_scale(points.values); +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + if (points.size() < 3) { + m_type = Bed3D::EShapeType::Invalid; + return; + } +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS // is this a rectangle ? +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + Vec2d min; + Vec2d max; + if (Bed3D::is_rectangle(points.values, &min, &max)) { + m_type = Bed3D::EShapeType::Rectangle; + m_rectSize = max - min; + m_rectOrigin = -min; + return; + } +#else + Polygon polygon = Polygon::new_scale(points.values); if (points.size() == 4) { auto lines = polygon.lines(); if (lines[0].parallel_to(lines[2]) && lines[1].parallel_to(lines[3])) { @@ -48,8 +64,21 @@ BedShape::BedShape(const ConfigOptionPoints& points) return; } } +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS // is this a circle ? +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + Vec2d center; + double radius; + if (Bed3D::is_circle(points.values, ¢er, &radius)) { + m_type = Bed3D::EShapeType::Circle; + m_diameter = 2.0 * radius; + return; + } + + // This is a custom bed shape, use the polygon provided. + m_type = Bed3D::EShapeType::Custom; +#else { // Analyze the array of points.Do they reside on a circle ? auto center = polygon.bounding_box().center(); @@ -79,11 +108,12 @@ BedShape::BedShape(const ConfigOptionPoints& points) } } - if (points.size() < 3) + if (points.size() < 3) return; // This is a custom bed shape, use the polygon provided. m_type = Type::Custom; +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS } static std::string get_option_label(BedShape::Parameter param) @@ -134,31 +164,56 @@ void BedShape::append_option_line(ConfigOptionsGroupShp optgroup, Parameter para } } +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS +wxString BedShape::get_name(Bed3D::EShapeType type) +{ + switch (type) { + case Bed3D::EShapeType::Rectangle: { return _L("Rectangular"); } + case Bed3D::EShapeType::Circle: { return _L("Circular"); } + case Bed3D::EShapeType::Custom: { return _L("Custom"); } + case Bed3D::EShapeType::Invalid: + default: return _L("Invalid"); + } +} +#else wxString BedShape::get_name(Type type) { switch (type) { - case Type::Rectangular : return _L("Rectangular"); - case Type::Circular : return _L("Circular"); - case Type::Custom : return _L("Custom"); - case Type::Invalid : - default : return _L("Invalid"); + case Type::Rectangular: return _L("Rectangular"); + case Type::Circular: return _L("Circular"); + case Type::Custom: return _L("Custom"); + case Type::Invalid: + default: return _L("Invalid"); } } +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS size_t BedShape::get_type() { +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + return static_cast(m_type == Bed3D::EShapeType::Invalid ? Bed3D::EShapeType::Rectangle : m_type); +#else return static_cast(m_type == Type::Invalid ? Type::Rectangular : m_type); +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS } wxString BedShape::get_full_name_with_params() { wxString out = _L("Shape") + ": " + get_name(m_type); +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + if (m_type == Bed3D::EShapeType::Rectangle) { +#else if (m_type == Type::Rectangular) { +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS out += "\n" + _(get_option_label(Parameter::RectSize)) + ": [" + ConfigOptionPoint(m_rectSize).serialize() + "]"; out += "\n" + _(get_option_label(Parameter::RectOrigin))+ ": [" + ConfigOptionPoint(m_rectOrigin).serialize() + "]"; } +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + else if (m_type == Bed3D::EShapeType::Circle) +#else else if (m_type == Type::Circular) +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS out += "\n" + _L(get_option_label(Parameter::Diameter)) + ": [" + double_to_string(m_diameter) + "]"; return out; @@ -166,11 +221,19 @@ wxString BedShape::get_full_name_with_params() void BedShape::apply_optgroup_values(ConfigOptionsGroupShp optgroup) { +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + if (m_type == Bed3D::EShapeType::Rectangle || m_type == Bed3D::EShapeType::Invalid) { +#else if (m_type == Type::Rectangular || m_type == Type::Invalid) { +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS optgroup->set_value("rect_size" , new ConfigOptionPoints{ m_rectSize }); optgroup->set_value("rect_origin" , new ConfigOptionPoints{ m_rectOrigin }); } +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + else if (m_type == Bed3D::EShapeType::Circle) +#else else if (m_type == Type::Circular) +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS optgroup->set_value("diameter", double_to_string(m_diameter)); } @@ -222,7 +285,7 @@ void BedShapePanel::build_panel(const ConfigOptionPoints& default_pt, const Conf m_custom_texture = custom_texture.value.empty() ? NONE : custom_texture.value; m_custom_model = custom_model.value.empty() ? NONE : custom_model.value; - auto sbsizer = new wxStaticBoxSizer(wxVERTICAL, this, _(L("Shape"))); + auto sbsizer = new wxStaticBoxSizer(wxVERTICAL, this, _L("Shape")); sbsizer->GetStaticBox()->SetFont(wxGetApp().bold_font()); wxGetApp().UpdateDarkUI(sbsizer->GetStaticBox()); @@ -232,16 +295,28 @@ void BedShapePanel::build_panel(const ConfigOptionPoints& default_pt, const Conf sbsizer->Add(m_shape_options_book); +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + auto optgroup = init_shape_options_page(BedShape::get_name(Bed3D::EShapeType::Rectangle)); +#else auto optgroup = init_shape_options_page(BedShape::get_name(BedShape::Type::Rectangular)); +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS BedShape::append_option_line(optgroup, BedShape::Parameter::RectSize); BedShape::append_option_line(optgroup, BedShape::Parameter::RectOrigin); activate_options_page(optgroup); +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + optgroup = init_shape_options_page(BedShape::get_name(Bed3D::EShapeType::Circle)); +#else optgroup = init_shape_options_page(BedShape::get_name(BedShape::Type::Circular)); +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS BedShape::append_option_line(optgroup, BedShape::Parameter::Diameter); activate_options_page(optgroup); +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + optgroup = init_shape_options_page(BedShape::get_name(Bed3D::EShapeType::Custom)); +#else optgroup = init_shape_options_page(BedShape::get_name(BedShape::Type::Custom)); +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS Line line{ "", "" }; line.full_width = 1; @@ -265,10 +340,7 @@ void BedShapePanel::build_panel(const ConfigOptionPoints& default_pt, const Conf wxPanel* texture_panel = init_texture_panel(); wxPanel* model_panel = init_model_panel(); - Bind(wxEVT_CHOICEBOOK_PAGE_CHANGED, ([this](wxCommandEvent& e) - { - update_shape(); - })); + Bind(wxEVT_CHOICEBOOK_PAGE_CHANGED, ([this](wxCommandEvent& e) { update_shape(); })); // right pane with preview canvas m_canvas = new Bed_2D(this); @@ -295,7 +367,7 @@ void BedShapePanel::build_panel(const ConfigOptionPoints& default_pt, const Conf ConfigOptionsGroupShp BedShapePanel::init_shape_options_page(const wxString& title) { wxPanel* panel = new wxPanel(m_shape_options_book); - ConfigOptionsGroupShp optgroup = std::make_shared(panel, _(L("Settings"))); + ConfigOptionsGroupShp optgroup = std::make_shared(panel, _L("Settings")); optgroup->label_width = 10; optgroup->m_on_change = [this](t_config_option_key opt_key, boost::any value) { @@ -319,7 +391,7 @@ wxPanel* BedShapePanel::init_texture_panel() { wxPanel* panel = new wxPanel(this); wxGetApp().UpdateDarkUI(panel, true); - ConfigOptionsGroupShp optgroup = std::make_shared(panel, _(L("Texture"))); + ConfigOptionsGroupShp optgroup = std::make_shared(panel, _L("Texture")); optgroup->label_width = 10; optgroup->m_on_change = [this](t_config_option_key opt_key, boost::any value) { @@ -329,7 +401,7 @@ wxPanel* BedShapePanel::init_texture_panel() Line line{ "", "" }; line.full_width = 1; line.widget = [this](wxWindow* parent) { - wxButton* load_btn = new wxButton(parent, wxID_ANY, _(L("Load..."))); + wxButton* load_btn = new wxButton(parent, wxID_ANY, _L("Load...")); wxSizer* load_sizer = new wxBoxSizer(wxHORIZONTAL); load_sizer->Add(load_btn, 1, wxEXPAND); @@ -338,7 +410,7 @@ wxPanel* BedShapePanel::init_texture_panel() wxSizer* filename_sizer = new wxBoxSizer(wxHORIZONTAL); filename_sizer->Add(filename_lbl, 1, wxEXPAND); - wxButton* remove_btn = new wxButton(parent, wxID_ANY, _(L("Remove"))); + wxButton* remove_btn = new wxButton(parent, wxID_ANY, _L("Remove")); wxSizer* remove_sizer = new wxBoxSizer(wxHORIZONTAL); remove_sizer->Add(remove_btn, 1, wxEXPAND); @@ -347,31 +419,23 @@ wxPanel* BedShapePanel::init_texture_panel() sizer->Add(load_sizer, 1, wxEXPAND); sizer->Add(remove_sizer, 1, wxEXPAND | wxTOP, 2); - load_btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent& e) - { - load_texture(); - })); - - remove_btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent& e) - { + load_btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent& e) { load_texture(); })); + remove_btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent& e) { m_custom_texture = NONE; update_shape(); })); - filename_lbl->Bind(wxEVT_UPDATE_UI, ([this](wxUpdateUIEvent& e) - { + filename_lbl->Bind(wxEVT_UPDATE_UI, ([this](wxUpdateUIEvent& e) { e.SetText(_(boost::filesystem::path(m_custom_texture).filename().string())); wxStaticText* lbl = dynamic_cast(e.GetEventObject()); - if (lbl != nullptr) - { + if (lbl != nullptr) { bool exists = (m_custom_texture == NONE) || boost::filesystem::exists(m_custom_texture); lbl->SetForegroundColour(exists ? /*wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)*/wxGetApp().get_label_clr_default() : wxColor(*wxRED)); wxString tooltip_text = ""; - if (m_custom_texture != NONE) - { + if (m_custom_texture != NONE) { if (!exists) - tooltip_text += _(L("Not found:")) + " "; + tooltip_text += _L("Not found:") + " "; tooltip_text += _(m_custom_texture); } @@ -382,10 +446,7 @@ wxPanel* BedShapePanel::init_texture_panel() } })); - remove_btn->Bind(wxEVT_UPDATE_UI, ([this](wxUpdateUIEvent& e) - { - e.Enable(m_custom_texture != NONE); - })); + remove_btn->Bind(wxEVT_UPDATE_UI, ([this](wxUpdateUIEvent& e) { e.Enable(m_custom_texture != NONE); })); return sizer; }; @@ -401,7 +462,7 @@ wxPanel* BedShapePanel::init_model_panel() { wxPanel* panel = new wxPanel(this); wxGetApp().UpdateDarkUI(panel, true); - ConfigOptionsGroupShp optgroup = std::make_shared(panel, _(L("Model"))); + ConfigOptionsGroupShp optgroup = std::make_shared(panel, _L("Model")); optgroup->label_width = 10; optgroup->m_on_change = [this](t_config_option_key opt_key, boost::any value) { @@ -411,7 +472,7 @@ wxPanel* BedShapePanel::init_model_panel() Line line{ "", "" }; line.full_width = 1; line.widget = [this](wxWindow* parent) { - wxButton* load_btn = new wxButton(parent, wxID_ANY, _(L("Load..."))); + wxButton* load_btn = new wxButton(parent, wxID_ANY, _L("Load...")); wxSizer* load_sizer = new wxBoxSizer(wxHORIZONTAL); load_sizer->Add(load_btn, 1, wxEXPAND); @@ -419,7 +480,7 @@ wxPanel* BedShapePanel::init_model_panel() wxSizer* filename_sizer = new wxBoxSizer(wxHORIZONTAL); filename_sizer->Add(filename_lbl, 1, wxEXPAND); - wxButton* remove_btn = new wxButton(parent, wxID_ANY, _(L("Remove"))); + wxButton* remove_btn = new wxButton(parent, wxID_ANY, _L("Remove")); wxSizer* remove_sizer = new wxBoxSizer(wxHORIZONTAL); remove_sizer->Add(remove_btn, 1, wxEXPAND); @@ -428,31 +489,24 @@ wxPanel* BedShapePanel::init_model_panel() sizer->Add(load_sizer, 1, wxEXPAND); sizer->Add(remove_sizer, 1, wxEXPAND | wxTOP, 2); - load_btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent& e) - { - load_model(); - })); + load_btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent& e) { load_model(); })); - remove_btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent& e) - { + remove_btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent& e) { m_custom_model = NONE; update_shape(); })); - filename_lbl->Bind(wxEVT_UPDATE_UI, ([this](wxUpdateUIEvent& e) - { + filename_lbl->Bind(wxEVT_UPDATE_UI, ([this](wxUpdateUIEvent& e) { e.SetText(_(boost::filesystem::path(m_custom_model).filename().string())); wxStaticText* lbl = dynamic_cast(e.GetEventObject()); - if (lbl != nullptr) - { + if (lbl != nullptr) { bool exists = (m_custom_model == NONE) || boost::filesystem::exists(m_custom_model); lbl->SetForegroundColour(exists ? /*wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)*/wxGetApp().get_label_clr_default() : wxColor(*wxRED)); wxString tooltip_text = ""; - if (m_custom_model != NONE) - { + if (m_custom_model != NONE) { if (!exists) - tooltip_text += _(L("Not found:")) + " "; + tooltip_text += _L("Not found:") + " "; tooltip_text += _(m_custom_model); } @@ -463,10 +517,7 @@ wxPanel* BedShapePanel::init_model_panel() } })); - remove_btn->Bind(wxEVT_UPDATE_UI, ([this](wxUpdateUIEvent& e) - { - e.Enable(m_custom_model != NONE); - })); + remove_btn->Bind(wxEVT_UPDATE_UI, ([this](wxUpdateUIEvent& e) { e.Enable(m_custom_model != NONE); })); return sizer; }; @@ -511,10 +562,18 @@ void BedShapePanel::update_shape() auto page_idx = m_shape_options_book->GetSelection(); auto opt_group = m_optgroups[page_idx]; +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + Bed3D::EShapeType page_type = static_cast(page_idx); +#else BedShape::Type page_type = static_cast(page_idx); +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS - if (page_type == BedShape::Type::Rectangular) { - Vec2d rect_size(Vec2d::Zero()); +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + if (page_type == Bed3D::EShapeType::Rectangle) { +#else + if (page_type == BedShape::Type::Rectangular) { +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + Vec2d rect_size(Vec2d::Zero()); Vec2d rect_origin(Vec2d::Zero()); try { rect_size = boost::any_cast(opt_group->get_value("rect_size")); } @@ -544,8 +603,12 @@ void BedShapePanel::update_shape() Vec2d(x1, y1), Vec2d(x0, y1) }; } +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + else if (page_type == Bed3D::EShapeType::Circle) { +#else else if (page_type == BedShape::Type::Circular) { - double diameter; +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + double diameter; try { diameter = boost::any_cast(opt_group->get_value("diameter")); } catch (const std::exception & /* e */) { return; } @@ -560,7 +623,11 @@ void BedShapePanel::update_shape() } m_shape = points; } +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + else if (page_type == Bed3D::EShapeType::Custom) +#else else if (page_type == BedShape::Type::Custom) +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS m_shape = m_loaded_shape; update_preview(); @@ -569,14 +636,13 @@ void BedShapePanel::update_shape() // Loads an stl file, projects it to the XY plane and calculates a polygon. void BedShapePanel::load_stl() { - wxFileDialog dialog(this, _(L("Choose an STL file to import bed shape from:")), "", "", file_wildcards(FT_STL), wxFD_OPEN | wxFD_FILE_MUST_EXIST); + wxFileDialog dialog(this, _L("Choose an STL file to import bed shape from:"), "", "", file_wildcards(FT_STL), wxFD_OPEN | wxFD_FILE_MUST_EXIST); if (dialog.ShowModal() != wxID_OK) return; std::string file_name = dialog.GetPath().ToUTF8().data(); - if (!boost::algorithm::iends_with(file_name, ".stl")) - { - show_error(this, _(L("Invalid file format."))); + if (!boost::algorithm::iends_with(file_name, ".stl")) { + show_error(this, _L("Invalid file format.")); return; } @@ -587,7 +653,7 @@ void BedShapePanel::load_stl() model = Model::read_from_file(file_name); } catch (std::exception &) { - show_error(this, _(L("Error! Invalid model"))); + show_error(this, _L("Error! Invalid model")); return; } @@ -595,11 +661,11 @@ void BedShapePanel::load_stl() auto expolygons = mesh.horizontal_projection(); if (expolygons.size() == 0) { - show_error(this, _(L("The selected file contains no geometry."))); + show_error(this, _L("The selected file contains no geometry.")); return; } if (expolygons.size() > 1) { - show_error(this, _(L("The selected file contains several disjoint areas. This is not supported."))); + show_error(this, _L("The selected file contains several disjoint areas. This is not supported.")); return; } @@ -614,7 +680,7 @@ void BedShapePanel::load_stl() void BedShapePanel::load_texture() { - wxFileDialog dialog(this, _(L("Choose a file to import bed texture from (PNG/SVG):")), "", "", + wxFileDialog dialog(this, _L("Choose a file to import bed texture from (PNG/SVG):"), "", "", file_wildcards(FT_TEX), wxFD_OPEN | wxFD_FILE_MUST_EXIST); if (dialog.ShowModal() != wxID_OK) @@ -623,9 +689,8 @@ void BedShapePanel::load_texture() m_custom_texture = NONE; std::string file_name = dialog.GetPath().ToUTF8().data(); - if (!boost::algorithm::iends_with(file_name, ".png") && !boost::algorithm::iends_with(file_name, ".svg")) - { - show_error(this, _(L("Invalid file format."))); + if (!boost::algorithm::iends_with(file_name, ".png") && !boost::algorithm::iends_with(file_name, ".svg")) { + show_error(this, _L("Invalid file format.")); return; } @@ -637,7 +702,7 @@ void BedShapePanel::load_texture() void BedShapePanel::load_model() { - wxFileDialog dialog(this, _(L("Choose an STL file to import bed model from:")), "", "", + wxFileDialog dialog(this, _L("Choose an STL file to import bed model from:"), "", "", file_wildcards(FT_STL), wxFD_OPEN | wxFD_FILE_MUST_EXIST); if (dialog.ShowModal() != wxID_OK) @@ -646,9 +711,8 @@ void BedShapePanel::load_model() m_custom_model = NONE; std::string file_name = dialog.GetPath().ToUTF8().data(); - if (!boost::algorithm::iends_with(file_name, ".stl")) - { - show_error(this, _(L("Invalid file format."))); + if (!boost::algorithm::iends_with(file_name, ".stl")) { + show_error(this, _L("Invalid file format.")); return; } diff --git a/src/slic3r/GUI/BedShapeDialog.hpp b/src/slic3r/GUI/BedShapeDialog.hpp index 370129f2e..af84ffb95 100644 --- a/src/slic3r/GUI/BedShapeDialog.hpp +++ b/src/slic3r/GUI/BedShapeDialog.hpp @@ -5,6 +5,9 @@ #include "GUI_Utils.hpp" #include "2DBed.hpp" +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS +#include "3DBed.hpp" +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS #include "I18N.hpp" #include @@ -19,12 +22,14 @@ using ConfigOptionsGroupShp = std::shared_ptr; struct BedShape { +#if !ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS enum class Type { Rectangular = 0, Circular, Custom, Invalid }; +#endif // !ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS enum class Parameter { RectSize, @@ -34,10 +39,18 @@ struct BedShape BedShape(const ConfigOptionPoints& points); +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + bool is_custom() { return m_type == Bed3D::EShapeType::Custom; } +#else bool is_custom() { return m_type == Type::Custom; } +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS static void append_option_line(ConfigOptionsGroupShp optgroup, Parameter param); +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + static wxString get_name(Bed3D::EShapeType type); +#else static wxString get_name(Type type); +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS // convert Type to size_t size_t get_type(); @@ -46,7 +59,11 @@ struct BedShape void apply_optgroup_values(ConfigOptionsGroupShp optgroup); private: +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + Bed3D::EShapeType m_type{ Bed3D::EShapeType::Invalid }; +#else Type m_type {Type::Invalid}; +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS Vec2d m_rectSize {200, 200}; Vec2d m_rectOrigin {0, 0}; double m_diameter {0}; diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 68b0fd5f4..4f9b2d0b3 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -2115,8 +2115,38 @@ void GLCanvas3D::load_sla_preview() // Release OpenGL data before generating new data. reset_volumes(); _load_sla_shells(); +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + Bed3D::EShapeType type = wxGetApp().plater()->get_bed().get_shape_type(); + switch (type) + { + case Bed3D::EShapeType::Circle: { + Vec2d center; + double radius; + if (Bed3D::is_circle(wxGetApp().plater()->get_bed().get_shape(), ¢er, &radius)) { + m_volumes.set_print_volume({ static_cast(type), + { float(center.x()), float(center.y()), float(radius) + BedEpsilon, 0.0f }, + { 0.0f, float(m_config->opt_float("max_print_height")) } }); + } + break; + } + case Bed3D::EShapeType::Rectangle: { + const BoundingBoxf3& bed_bb = wxGetApp().plater()->get_bed().get_bounding_box(false); + m_volumes.set_print_volume({ static_cast(type), + { float(bed_bb.min.x()) - BedEpsilon, float(bed_bb.min.y()) - BedEpsilon, float(bed_bb.max.x()) + BedEpsilon, float(bed_bb.max.y()) + BedEpsilon }, + { 0.0f, float(m_config->opt_float("max_print_height")) } }); + break; + } + default: + case Bed3D::EShapeType::Custom: { + m_volumes.set_print_volume({ static_cast(type), + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.0f, 0.0f } }); + } + } +#else const BoundingBoxf3& bed_bb = wxGetApp().plater()->get_bed().get_bounding_box(false); m_volumes.set_print_box(float(bed_bb.min.x()) - BedEpsilon, float(bed_bb.min.y()) - BedEpsilon, 0.0f, float(bed_bb.max.x()) + BedEpsilon, float(bed_bb.max.y()) + BedEpsilon, (float)m_config->opt_float("max_print_height")); +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS _update_sla_shells_outside_state(); _set_warning_notification_if_needed(EWarning::SlaSupportsOutside); } @@ -5073,8 +5103,38 @@ void GLCanvas3D::_render_objects(GLVolumeCollection::ERenderType type) m_layers_editing.select_object(*m_model, this->is_layers_editing_enabled() ? m_selection.get_object_idx() : -1); if (m_config != nullptr) { +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + Bed3D::EShapeType type = wxGetApp().plater()->get_bed().get_shape_type(); + switch (type) + { + case Bed3D::EShapeType::Circle: { + Vec2d center; + double radius; + if (Bed3D::is_circle(wxGetApp().plater()->get_bed().get_shape(), ¢er, &radius)) { + m_volumes.set_print_volume({ static_cast(type), + { float(center.x()), float(center.y()), float(radius) + BedEpsilon, 0.0f }, + { 0.0f, float(m_config->opt_float("max_print_height")) } }); + } + break; + } + case Bed3D::EShapeType::Rectangle: { + const BoundingBoxf3& bed_bb = wxGetApp().plater()->get_bed().get_bounding_box(false); + m_volumes.set_print_volume({ static_cast(type), + { float(bed_bb.min.x()) - BedEpsilon, float(bed_bb.min.y()) - BedEpsilon, float(bed_bb.max.x()) + BedEpsilon, float(bed_bb.max.y()) + BedEpsilon }, + { 0.0f, float(m_config->opt_float("max_print_height")) } }); + break; + } + default: + case Bed3D::EShapeType::Custom: { + m_volumes.set_print_volume({ static_cast(type), + { 0.0f, 0.0f, 0.0f, 0.0f }, + { 0.0f, 0.0f } }); + } + } +#else const BoundingBoxf3& bed_bb = wxGetApp().plater()->get_bed().get_bounding_box(false); m_volumes.set_print_box((float)bed_bb.min.x() - BedEpsilon, (float)bed_bb.min.y() - BedEpsilon, 0.0f, (float)bed_bb.max.x() + BedEpsilon, (float)bed_bb.max.y() + BedEpsilon, (float)m_config->opt_float("max_print_height")); +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS #if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS if (m_requires_check_outside_state) { m_volumes.check_outside_state(m_config, nullptr); @@ -5094,7 +5154,11 @@ void GLCanvas3D::_render_objects(GLVolumeCollection::ERenderType type) m_volumes.set_clipping_plane(m_camera_clipping_plane.get_data()); m_volumes.set_show_sinking_contours(! m_gizmos.is_hiding_instances()); +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + GLShaderProgram* shader = wxGetApp().get_shader("gouraud_mod"); +#else GLShaderProgram* shader = wxGetApp().get_shader("gouraud"); +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS if (shader != nullptr) { shader->start_using(); diff --git a/src/slic3r/GUI/GLShadersManager.cpp b/src/slic3r/GUI/GLShadersManager.cpp index 5dd478b57..bf3ee7eee 100644 --- a/src/slic3r/GUI/GLShadersManager.cpp +++ b/src/slic3r/GUI/GLShadersManager.cpp @@ -64,17 +64,31 @@ std::pair GLShadersManager::init() // For Apple's on Arm CPU computed triangle normals inside fragment shader using dFdx and dFdy has the opposite direction. // Because of this, objects had darker colors inside the multi-material gizmo. // Based on https://stackoverflow.com/a/66206648, the similar behavior was also spotted on some other devices with Arm CPU. +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + if (platform_flavor() == PlatformFlavor::OSXOnArm) + valid &= append_shader("gouraud_mod", { "gouraud_mod.vs", "gouraud_mod.fs" }, { "FLIP_TRIANGLE_NORMALS"sv +#if ENABLE_ENVIRONMENT_MAP + , "ENABLE_ENVIRONMENT_MAP"sv +#endif + }); + else + valid &= append_shader("gouraud_mod", { "gouraud_mod.vs", "gouraud_mod.fs" } +#if ENABLE_ENVIRONMENT_MAP + , { "ENABLE_ENVIRONMENT_MAP"sv } +#endif +#else if (platform_flavor() == PlatformFlavor::OSXOnArm) valid &= append_shader("gouraud", { "gouraud.vs", "gouraud.fs" }, { "FLIP_TRIANGLE_NORMALS"sv #if ENABLE_ENVIRONMENT_MAP , "ENABLE_ENVIRONMENT_MAP"sv #endif - }); + }); else valid &= append_shader("gouraud", { "gouraud.vs", "gouraud.fs" } #if ENABLE_ENVIRONMENT_MAP , { "ENABLE_ENVIRONMENT_MAP"sv } #endif +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS ); // used to render variable layers heights in 3d editor valid &= append_shader("variable_layer_height", { "variable_layer_height.vs", "variable_layer_height.fs" }); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp index 30f7ff7cf..b460d93b0 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp @@ -607,7 +607,11 @@ void TriangleSelectorMmGui::render(ImGuiWrapper *imgui) auto *shader = wxGetApp().get_current_shader(); if (!shader) return; +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + assert(shader->get_name() == "gouraud_mod"); +#else assert(shader->get_name() == "gouraud"); +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS ScopeGuard guard([shader]() { if (shader) shader->set_uniform("compute_triangle_normals_in_fs", false);}); shader->set_uniform("compute_triangle_normals_in_fs", true); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp index aac4d6ff7..19b5549ae 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp @@ -97,12 +97,20 @@ void GLGizmoPainterBase::render_triangles(const Selection& selection, const bool clp_dataf[3] = float(clp->get_data()[3]); } +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + auto* shader = wxGetApp().get_shader("gouraud_mod"); +#else auto *shader = wxGetApp().get_shader("gouraud"); +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS if (! shader) return; shader->start_using(); shader->set_uniform("slope.actived", false); +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + shader->set_uniform("print_volume.type", 0); +#else shader->set_uniform("print_box.actived", false); +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS shader->set_uniform("clipping_plane", clp_dataf, 4); ScopeGuard guard([shader]() { if (shader) shader->stop_using(); }); @@ -128,7 +136,11 @@ void GLGizmoPainterBase::render_triangles(const Selection& selection, const bool // to the shader input variable print_box.volume_world_matrix before // rendering the painted triangles. When this matrix is not set, the // wrong transformation matrix is used for "Clipping of view". +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + shader->set_uniform("volume_world_matrix", trafo_matrix); +#else shader->set_uniform("print_box.volume_world_matrix", trafo_matrix); +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS m_triangle_selectors[mesh_id]->render(m_imgui); @@ -591,7 +603,11 @@ void TriangleSelectorGUI::render(ImGuiWrapper* imgui) auto* shader = wxGetApp().get_current_shader(); if (! shader) return; +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + assert(shader->get_name() == "gouraud_mod"); +#else assert(shader->get_name() == "gouraud"); +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS for (auto iva : {std::make_pair(&m_iva_enforcers, enforcers_color), std::make_pair(&m_iva_blockers, blockers_color)}) { From d854fd0b29673e06f0273f243a4976fc92828ba3 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 21 Sep 2021 15:48:17 +0200 Subject: [PATCH 007/102] Tech ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS - Fixed GLVolumeCollection::check_outside_state() for SLA printers --- src/libslic3r/Technologies.hpp | 2 +- src/slic3r/GUI/3DScene.cpp | 49 +++++++++++++++++++++------------- 2 files changed, 32 insertions(+), 19 deletions(-) diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index 61c1b7029..eb2f6cfc1 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -63,7 +63,7 @@ // Enable the fix for the detection of the out of bed state for sinking objects #define ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION (1 && ENABLE_2_4_0_ALPHA2) // Enable detection of out of bed using the bed perimeter and other improvements -#define ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS (1 && ENABLE_2_4_0_ALPHA2) +#define ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS (1 && ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION) #endif // _prusaslicer_technologies_h_ diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index d12986e06..a69f95a15 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -966,7 +966,8 @@ bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, M #if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS const Polygon bed_poly = offset(Polygon::new_scale(opt->values), static_cast(scale_(BedEpsilon))).front(); const float bed_height = config->opt_float("max_print_height"); -#else +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + const BoundingBox bed_box_2D = get_extents(Polygon::new_scale(opt->values)); BoundingBoxf3 print_volume({ unscale(bed_box_2D.min.x()), unscale(bed_box_2D.min.y()), 0.0 }, { unscale(bed_box_2D.max.x()), unscale(bed_box_2D.max.y()), config->opt_float("max_print_height") }); @@ -976,7 +977,6 @@ bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, M print_volume.min.y() -= BedEpsilon; print_volume.max.x() += BedEpsilon; print_volume.max.y() += BedEpsilon; -#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS ModelInstanceEPrintVolumeState state = ModelInstancePVS_Inside; @@ -987,23 +987,36 @@ bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, M continue; #if ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION - const BoundingBoxf3& bb = volume->transformed_non_sinking_bounding_box(); + bool contained = false; + bool intersects = false; + if (GUI::wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA) { + const BoundingBoxf3& bb = volume->transformed_convex_hull_bounding_box(); + contained = print_volume.contains(bb); + intersects = print_volume.intersects(bb); + } + else { + const BoundingBoxf3& bb = volume->transformed_non_sinking_bounding_box(); +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + const indexed_triangle_set& its = GUI::wxGetApp().plater()->model().objects[volume->object_idx()]->volumes[volume->volume_idx()]->mesh().its; + const Polygon volume_hull_2d = its_convex_hull_2d_above(its, volume->world_matrix().cast(), 0.0f); + Polygons intersection_polys = intersection(bed_poly, volume_hull_2d); + bool contained_xy = !intersection_polys.empty() && same(intersection_polys.front(), volume_hull_2d); + bool contained_z = -1e10 < bb.min.z() && bb.max.z() < bed_height; + contained = contained_xy && contained_z; + bool intersects_xy = !contained_xy && !intersection_polys.empty(); + bool intersects_z = !contained_z && bb.min.z() < bed_height && -1e10 < bb.max.z(); + intersects = intersects_xy || intersects_z; +#else + contained = print_volume.contains(bb); + intersects = print_volume.intersects(bb); +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS #else const BoundingBoxf3& bb = volume->transformed_convex_hull_bounding_box(); -#endif // ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION -#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS - const indexed_triangle_set& its = GUI::wxGetApp().plater()->model().objects[volume->object_idx()]->volumes[volume->volume_idx()]->mesh().its; - const Polygon volume_hull_2d = its_convex_hull_2d_above(its, volume->world_matrix().cast(), 0.0f); - Polygons intersection_polys = intersection(bed_poly, volume_hull_2d); - bool contained_xy = !intersection_polys.empty() && same(intersection_polys.front(), volume_hull_2d); - bool contained_z = -1e10 < bb.min.z() && bb.max.z() < bed_height; - bool contained = contained_xy && contained_z; - bool intersects_xy = !contained_xy && !intersection_polys.empty(); - bool intersects_z = !contained_z && bb.min.z() < bed_height && -1e10 < bb.max.z(); - bool intersects = intersects_xy || intersects_z; -#else bool contained = print_volume.contains(bb); -#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS +#endif // ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION +#if ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION + } +#endif // ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION volume->is_outside = !contained; if (!volume->printable) @@ -1014,13 +1027,13 @@ bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, M if (state == ModelInstancePVS_Inside && volume->is_outside) state = ModelInstancePVS_Fully_Outside; -#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS +#if ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION if (state == ModelInstancePVS_Fully_Outside && volume->is_outside && intersects) state = ModelInstancePVS_Partly_Outside; #else if (state == ModelInstancePVS_Fully_Outside && volume->is_outside && print_volume.intersects(bb)) state = ModelInstancePVS_Partly_Outside; -#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS +#endif // ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION } if (out_state != nullptr) From e24bd2d2d4e17944c1e25b06bd72ca867d24868b Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Thu, 30 Sep 2021 10:23:38 +0200 Subject: [PATCH 008/102] Tech ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION - Removed duplicated code --- src/slic3r/GUI/3DScene.cpp | 4 +--- src/slic3r/GUI/GLCanvas3D.cpp | 37 +++++++---------------------------- 2 files changed, 8 insertions(+), 33 deletions(-) diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index a69f95a15..e414a89ce 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -1010,13 +1010,11 @@ bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, M contained = print_volume.contains(bb); intersects = print_volume.intersects(bb); #endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + } #else const BoundingBoxf3& bb = volume->transformed_convex_hull_bounding_box(); bool contained = print_volume.contains(bb); #endif // ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION -#if ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION - } -#endif // ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION volume->is_outside = !contained; if (!volume->printable) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 4f9b2d0b3..32c472318 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -2115,38 +2115,10 @@ void GLCanvas3D::load_sla_preview() // Release OpenGL data before generating new data. reset_volumes(); _load_sla_shells(); -#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS - Bed3D::EShapeType type = wxGetApp().plater()->get_bed().get_shape_type(); - switch (type) - { - case Bed3D::EShapeType::Circle: { - Vec2d center; - double radius; - if (Bed3D::is_circle(wxGetApp().plater()->get_bed().get_shape(), ¢er, &radius)) { - m_volumes.set_print_volume({ static_cast(type), - { float(center.x()), float(center.y()), float(radius) + BedEpsilon, 0.0f }, - { 0.0f, float(m_config->opt_float("max_print_height")) } }); - } - break; - } - case Bed3D::EShapeType::Rectangle: { - const BoundingBoxf3& bed_bb = wxGetApp().plater()->get_bed().get_bounding_box(false); - m_volumes.set_print_volume({ static_cast(type), - { float(bed_bb.min.x()) - BedEpsilon, float(bed_bb.min.y()) - BedEpsilon, float(bed_bb.max.x()) + BedEpsilon, float(bed_bb.max.y()) + BedEpsilon }, - { 0.0f, float(m_config->opt_float("max_print_height")) } }); - break; - } - default: - case Bed3D::EShapeType::Custom: { - m_volumes.set_print_volume({ static_cast(type), - { 0.0f, 0.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f } }); - } - } -#else +#if !ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS const BoundingBoxf3& bed_bb = wxGetApp().plater()->get_bed().get_bounding_box(false); m_volumes.set_print_box(float(bed_bb.min.x()) - BedEpsilon, float(bed_bb.min.y()) - BedEpsilon, 0.0f, float(bed_bb.max.x()) + BedEpsilon, float(bed_bb.max.y()) + BedEpsilon, (float)m_config->opt_float("max_print_height")); -#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS +#endif // !ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS _update_sla_shells_outside_state(); _set_warning_notification_if_needed(EWarning::SlaSupportsOutside); } @@ -5101,6 +5073,9 @@ void GLCanvas3D::_render_objects(GLVolumeCollection::ERenderType type) if (m_picking_enabled) { // Update the layer editing selection to the first object selected, update the current object maximum Z. m_layers_editing.select_object(*m_model, this->is_layers_editing_enabled() ? m_selection.get_object_idx() : -1); +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + } +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS if (m_config != nullptr) { #if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS @@ -5144,7 +5119,9 @@ void GLCanvas3D::_render_objects(GLVolumeCollection::ERenderType type) m_volumes.check_outside_state(m_config, nullptr); #endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS } +#if !ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS } +#endif // !ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS if (m_use_clipping_planes) m_volumes.set_z_range(-m_clipping_planes[0].get_data()[3], m_clipping_planes[1].get_data()[3]); From 4eb21d478791986e338ecd54b6f9c33394cd01c7 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Thu, 30 Sep 2021 10:35:53 +0200 Subject: [PATCH 009/102] Tech ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION - Enable detection of collision with circular printbed also for SLA printers --- src/slic3r/GUI/3DScene.cpp | 31 ++++++++++++------------------- 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index e414a89ce..59fac373d 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -989,28 +989,21 @@ bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, M #if ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION bool contained = false; bool intersects = false; - if (GUI::wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA) { - const BoundingBoxf3& bb = volume->transformed_convex_hull_bounding_box(); - contained = print_volume.contains(bb); - intersects = print_volume.intersects(bb); - } - else { - const BoundingBoxf3& bb = volume->transformed_non_sinking_bounding_box(); + const BoundingBoxf3& bb = volume->transformed_non_sinking_bounding_box(); #if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS - const indexed_triangle_set& its = GUI::wxGetApp().plater()->model().objects[volume->object_idx()]->volumes[volume->volume_idx()]->mesh().its; - const Polygon volume_hull_2d = its_convex_hull_2d_above(its, volume->world_matrix().cast(), 0.0f); - Polygons intersection_polys = intersection(bed_poly, volume_hull_2d); - bool contained_xy = !intersection_polys.empty() && same(intersection_polys.front(), volume_hull_2d); - bool contained_z = -1e10 < bb.min.z() && bb.max.z() < bed_height; - contained = contained_xy && contained_z; - bool intersects_xy = !contained_xy && !intersection_polys.empty(); - bool intersects_z = !contained_z && bb.min.z() < bed_height && -1e10 < bb.max.z(); - intersects = intersects_xy || intersects_z; + const indexed_triangle_set& its = GUI::wxGetApp().plater()->model().objects[volume->object_idx()]->volumes[volume->volume_idx()]->mesh().its; + const Polygon volume_hull_2d = its_convex_hull_2d_above(its, volume->world_matrix().cast(), 0.0f); + Polygons intersection_polys = intersection(bed_poly, volume_hull_2d); + bool contained_xy = !intersection_polys.empty() && same(intersection_polys.front(), volume_hull_2d); + bool contained_z = -1e10 < bb.min.z() && bb.max.z() < bed_height; + contained = contained_xy && contained_z; + bool intersects_xy = !contained_xy && !intersection_polys.empty(); + bool intersects_z = !contained_z && bb.min.z() < bed_height && -1e10 < bb.max.z(); + intersects = intersects_xy || intersects_z; #else - contained = print_volume.contains(bb); - intersects = print_volume.intersects(bb); + contained = print_volume.contains(bb); + intersects = print_volume.intersects(bb); #endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS - } #else const BoundingBoxf3& bb = volume->transformed_convex_hull_bounding_box(); bool contained = print_volume.contains(bb); From 448911df9f859fb83c56d731cb0a9ffbdaa8eefb Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Thu, 30 Sep 2021 10:55:41 +0200 Subject: [PATCH 010/102] Tech ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS - Removed unused code --- src/slic3r/GUI/3DScene.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 59fac373d..26d32f91b 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -966,8 +966,7 @@ bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, M #if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS const Polygon bed_poly = offset(Polygon::new_scale(opt->values), static_cast(scale_(BedEpsilon))).front(); const float bed_height = config->opt_float("max_print_height"); -#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS - +#else const BoundingBox bed_box_2D = get_extents(Polygon::new_scale(opt->values)); BoundingBoxf3 print_volume({ unscale(bed_box_2D.min.x()), unscale(bed_box_2D.min.y()), 0.0 }, { unscale(bed_box_2D.max.x()), unscale(bed_box_2D.max.y()), config->opt_float("max_print_height") }); @@ -977,6 +976,7 @@ bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, M print_volume.min.y() -= BedEpsilon; print_volume.max.x() += BedEpsilon; print_volume.max.y() += BedEpsilon; +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS ModelInstanceEPrintVolumeState state = ModelInstancePVS_Inside; From 7cfe0826211e63f9d9de1be9967ff2f2d580ecaf Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Thu, 30 Sep 2021 12:08:05 +0200 Subject: [PATCH 011/102] Tech ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS - Enable detection of collision with circular printbed for toolpaths --- src/libslic3r/Geometry.hpp | 26 +++++++++++++ src/slic3r/GUI/3DScene.cpp | 73 +++++++++++++++-------------------- src/slic3r/GUI/3DScene.hpp | 5 +++ src/slic3r/GUI/GLCanvas3D.cpp | 16 ++++++++ 4 files changed, 79 insertions(+), 41 deletions(-) diff --git a/src/libslic3r/Geometry.hpp b/src/libslic3r/Geometry.hpp index 2ac19b502..11d405e4c 100644 --- a/src/libslic3r/Geometry.hpp +++ b/src/libslic3r/Geometry.hpp @@ -84,6 +84,32 @@ static inline bool is_ccw(const Polygon &poly) return o == ORIENTATION_CCW; } +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS +// returns true if the given polygons are identical +static bool are_approx(const Polygon& lhs, const Polygon& rhs) +{ + if (lhs.points.size() != rhs.points.size()) + return false; + + size_t rhs_id = 0; + while (rhs_id < rhs.points.size()) { + if (rhs.points[rhs_id].isApprox(lhs.points.front())) + break; + ++rhs_id; + } + + if (rhs_id == rhs.points.size()) + return false; + + for (size_t i = 0; i < lhs.points.size(); ++i) { + if (!lhs.points[i].isApprox(rhs.points[(i + rhs_id) % lhs.points.size()])) + return false; + } + + return true; +} +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + inline bool ray_ray_intersection(const Vec2d &p1, const Vec2d &v1, const Vec2d &p2, const Vec2d &v2, Vec2d &res) { double denom = v1(0) * v2(1) - v2(0) * v1(1); diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 26d32f91b..9664f27f6 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -10,6 +10,7 @@ #include "GLShader.hpp" #include "GUI_App.hpp" #include "Plater.hpp" +#include "BitmapCache.hpp" #include "libslic3r/ExtrusionEntity.hpp" #include "libslic3r/ExtrusionEntityCollection.hpp" @@ -17,7 +18,6 @@ #include "libslic3r/Print.hpp" #include "libslic3r/SLAPrint.hpp" #include "libslic3r/Slicing.hpp" -#include "slic3r/GUI/BitmapCache.hpp" #include "libslic3r/Format/STL.hpp" #include "libslic3r/Utils.hpp" #include "libslic3r/AppConfig.hpp" @@ -67,6 +67,26 @@ void glAssertRecentCallImpl(const char* file_name, unsigned int line, const char namespace Slic3r { +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS +ModelInstanceEPrintVolumeState printbed_collision_state(const Polygon& printbed_shape, double print_volume_height, const Polygon& obj_hull_2d, double obj_min_z, double obj_max_z) +{ + static const double Z_TOLERANCE = -1e10; + + const Polygons intersection_polys = intersection(printbed_shape, obj_hull_2d); + const bool contained_xy = !intersection_polys.empty() && Geometry::are_approx(intersection_polys.front(), obj_hull_2d); + const bool contained_z = Z_TOLERANCE < obj_min_z && obj_max_z < print_volume_height; + if (contained_xy && contained_z) + return ModelInstancePVS_Inside; + + const bool intersects_xy = !contained_xy && !intersection_polys.empty(); + const bool intersects_z = !contained_z && obj_min_z < print_volume_height && Z_TOLERANCE < obj_max_z; + if (intersects_xy || intersects_z) + return ModelInstancePVS_Partly_Outside; + + return ModelInstancePVS_Fully_Outside; +} +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + #if ENABLE_SMOOTH_NORMALS static void smooth_normals_corner(TriangleMesh& mesh, std::vector& normals) { @@ -929,31 +949,6 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type, bool disab glsafe(::glDisable(GL_BLEND)); } -#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS -static bool same(const Polygon& lhs, const Polygon& rhs) -{ - if (lhs.points.size() != rhs.points.size()) - return false; - - size_t rhs_id = 0; - while (rhs_id < rhs.points.size()) { - if (rhs.points[rhs_id].isApprox(lhs.points.front())) - break; - ++rhs_id; - } - - if (rhs_id == rhs.points.size()) - return false; - - for (size_t i = 0; i < lhs.points.size(); ++i) { - if (!lhs.points[i].isApprox(rhs.points[(i + rhs_id) % lhs.points.size()])) - return false; - } - - return true; -} -#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS - bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, ModelInstanceEPrintVolumeState* out_state) const { if (config == nullptr) @@ -978,7 +973,7 @@ bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, M print_volume.max.y() += BedEpsilon; #endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS - ModelInstanceEPrintVolumeState state = ModelInstancePVS_Inside; + ModelInstanceEPrintVolumeState overall_state = ModelInstancePVS_Inside; bool contained_min_one = false; @@ -993,13 +988,9 @@ bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, M #if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS const indexed_triangle_set& its = GUI::wxGetApp().plater()->model().objects[volume->object_idx()]->volumes[volume->volume_idx()]->mesh().its; const Polygon volume_hull_2d = its_convex_hull_2d_above(its, volume->world_matrix().cast(), 0.0f); - Polygons intersection_polys = intersection(bed_poly, volume_hull_2d); - bool contained_xy = !intersection_polys.empty() && same(intersection_polys.front(), volume_hull_2d); - bool contained_z = -1e10 < bb.min.z() && bb.max.z() < bed_height; - contained = contained_xy && contained_z; - bool intersects_xy = !contained_xy && !intersection_polys.empty(); - bool intersects_z = !contained_z && bb.min.z() < bed_height && -1e10 < bb.max.z(); - intersects = intersects_xy || intersects_z; + const ModelInstanceEPrintVolumeState volume_state = printbed_collision_state(bed_poly, bed_height, volume_hull_2d, bb.min.z(), bb.max.z()); + contained = (volume_state == ModelInstancePVS_Inside); + intersects = (volume_state == ModelInstancePVS_Partly_Outside); #else contained = print_volume.contains(bb); intersects = print_volume.intersects(bb); @@ -1015,20 +1006,20 @@ bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, M contained_min_one |= contained; - if (state == ModelInstancePVS_Inside && volume->is_outside) - state = ModelInstancePVS_Fully_Outside; + if (overall_state == ModelInstancePVS_Inside && volume->is_outside) + overall_state = ModelInstancePVS_Fully_Outside; #if ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION - if (state == ModelInstancePVS_Fully_Outside && volume->is_outside && intersects) - state = ModelInstancePVS_Partly_Outside; + if (overall_state == ModelInstancePVS_Fully_Outside && volume->is_outside && intersects) + overall_state = ModelInstancePVS_Partly_Outside; #else - if (state == ModelInstancePVS_Fully_Outside && volume->is_outside && print_volume.intersects(bb)) - state = ModelInstancePVS_Partly_Outside; + if (overall_state == ModelInstancePVS_Fully_Outside && volume->is_outside && print_volume.intersects(bb)) + overall_state = ModelInstancePVS_Partly_Outside; #endif // ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION } if (out_state != nullptr) - *out_state = state; + *out_state = overall_state; return contained_min_one; } diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index 9bfd6edeb..b305d0231 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -41,6 +41,11 @@ enum ModelInstanceEPrintVolumeState : unsigned char; // Return appropriate color based on the ModelVolume. std::array color_from_model_volume(const ModelVolume& model_volume); +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS +// return the state of given object volume (extrusion along z of obj_hull_2d by obj_height) +// with respect to the given print volume (extrusion along z of printbed_shape by print_volume_height) +ModelInstanceEPrintVolumeState printbed_collision_state(const Polygon& printbed_shape, double print_volume_height, const Polygon& obj_hull_2d, double obj_min_z, double obj_max_z); +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS // A container for interleaved arrays of 3D vertices and normals, // possibly indexed by triangles and / or quads. diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 80cf4f46e..12e829f8b 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -5011,9 +5011,25 @@ void GLCanvas3D::_render_background() const if (!m_volumes.empty()) use_error_color &= _is_any_volume_outside(); else { +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + const ConfigOptionPoints* opt = dynamic_cast(m_config->option("bed_shape")); + if (opt != nullptr) { + const Polygon bed_poly = offset(Polygon::new_scale(opt->values), static_cast(scale_(BedEpsilon))).front(); + const float bed_height = m_config->opt_float("max_print_height"); + const BoundingBoxf3& paths_volume = m_gcode_viewer.get_paths_bounding_box(); + Polygon paths_hull_2d; + paths_hull_2d.append({ scale_(paths_volume.min.x()), scale_(paths_volume.min.y()) }); + paths_hull_2d.append({ scale_(paths_volume.max.x()), scale_(paths_volume.min.y()) }); + paths_hull_2d.append({ scale_(paths_volume.max.x()), scale_(paths_volume.max.y()) }); + paths_hull_2d.append({ scale_(paths_volume.min.x()), scale_(paths_volume.max.y()) }); + const ModelInstanceEPrintVolumeState state = printbed_collision_state(bed_poly, bed_height, paths_hull_2d, paths_volume.min.z(), paths_volume.max.z()); + use_error_color &= state != ModelInstancePVS_Inside; + } +#else const BoundingBoxf3 test_volume = (m_config != nullptr) ? print_volume(*m_config) : BoundingBoxf3(); const BoundingBoxf3& paths_volume = m_gcode_viewer.get_paths_bounding_box(); use_error_color &= (test_volume.radius() > 0.0 && paths_volume.radius() > 0.0) ? !test_volume.contains(paths_volume) : false; +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS } } From 430c7a69b32171b1d04223a9430bd6b590b63f3c Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Thu, 30 Sep 2021 13:16:05 +0200 Subject: [PATCH 012/102] Tech ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS - Completed detection of collision with circular printbed for toolpaths and sla auxyliary volumes --- src/slic3r/GUI/3DScene.cpp | 25 +++++++++++--- src/slic3r/GUI/3DScene.hpp | 3 ++ src/slic3r/GUI/GLCanvas3D.cpp | 61 ++++++++++++++++++++++++++++------- 3 files changed, 73 insertions(+), 16 deletions(-) diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 9664f27f6..a0d2e8c51 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -85,6 +85,17 @@ ModelInstanceEPrintVolumeState printbed_collision_state(const Polygon& printbed_ return ModelInstancePVS_Fully_Outside; } + +ModelInstanceEPrintVolumeState printbed_collision_state(const Polygon& printbed_shape, double print_volume_height, const BoundingBoxf3& box) +{ + const Polygon box_hull_2d({ + { scale_(box.min.x()), scale_(box.min.y()) }, + { scale_(box.max.x()), scale_(box.min.y()) }, + { scale_(box.max.x()), scale_(box.max.y()) }, + { scale_(box.min.x()), scale_(box.max.y()) } + }); + return printbed_collision_state(printbed_shape, print_volume_height, box_hull_2d, box.min.z(), box.max.z()); +} #endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS #if ENABLE_SMOOTH_NORMALS @@ -984,11 +995,17 @@ bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, M #if ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION bool contained = false; bool intersects = false; - const BoundingBoxf3& bb = volume->transformed_non_sinking_bounding_box(); + bool is_sla = GUI::wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA; + const BoundingBoxf3 bb = is_sla ? volume->transformed_convex_hull_bounding_box() : volume->transformed_non_sinking_bounding_box(); #if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS - const indexed_triangle_set& its = GUI::wxGetApp().plater()->model().objects[volume->object_idx()]->volumes[volume->volume_idx()]->mesh().its; - const Polygon volume_hull_2d = its_convex_hull_2d_above(its, volume->world_matrix().cast(), 0.0f); - const ModelInstanceEPrintVolumeState volume_state = printbed_collision_state(bed_poly, bed_height, volume_hull_2d, bb.min.z(), bb.max.z()); + ModelInstanceEPrintVolumeState volume_state; + if (is_sla) + volume_state = printbed_collision_state(bed_poly, bed_height, bb); + else { + const indexed_triangle_set& its = GUI::wxGetApp().plater()->model().objects[volume->object_idx()]->volumes[volume->volume_idx()]->mesh().its; + const Polygon volume_hull_2d = its_convex_hull_2d_above(its, volume->world_matrix().cast(), 0.0f); + volume_state = printbed_collision_state(bed_poly, bed_height, volume_hull_2d, bb.min.z(), bb.max.z()); + } contained = (volume_state == ModelInstancePVS_Inside); intersects = (volume_state == ModelInstancePVS_Partly_Outside); #else diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index b305d0231..ce57d5410 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -45,6 +45,9 @@ std::array color_from_model_volume(const ModelVolume& model_volume); // return the state of given object volume (extrusion along z of obj_hull_2d by obj_height) // with respect to the given print volume (extrusion along z of printbed_shape by print_volume_height) ModelInstanceEPrintVolumeState printbed_collision_state(const Polygon& printbed_shape, double print_volume_height, const Polygon& obj_hull_2d, double obj_min_z, double obj_max_z); +// return the state of given box +// with respect to the given print volume (extrusion along z of printbed_shape by print_volume_height) +ModelInstanceEPrintVolumeState printbed_collision_state(const Polygon& printbed_shape, double print_volume_height, const BoundingBoxf3& box); #endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS // A container for interleaved arrays of 3D vertices and normals, diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 12e829f8b..a5bba3471 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -4984,6 +4984,7 @@ void GLCanvas3D::_rectangular_selection_picking_pass() _update_volumes_hover_state(); } +#if !ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS static BoundingBoxf3 print_volume(const DynamicPrintConfig& config) { // tolerance to avoid false detection at bed edges @@ -5000,6 +5001,7 @@ static BoundingBoxf3 print_volume(const DynamicPrintConfig& config) } return ret; } +#endif // !ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS void GLCanvas3D::_render_background() const { @@ -5013,18 +5015,17 @@ void GLCanvas3D::_render_background() const else { #if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS const ConfigOptionPoints* opt = dynamic_cast(m_config->option("bed_shape")); - if (opt != nullptr) { - const Polygon bed_poly = offset(Polygon::new_scale(opt->values), static_cast(scale_(BedEpsilon))).front(); - const float bed_height = m_config->opt_float("max_print_height"); - const BoundingBoxf3& paths_volume = m_gcode_viewer.get_paths_bounding_box(); - Polygon paths_hull_2d; - paths_hull_2d.append({ scale_(paths_volume.min.x()), scale_(paths_volume.min.y()) }); - paths_hull_2d.append({ scale_(paths_volume.max.x()), scale_(paths_volume.min.y()) }); - paths_hull_2d.append({ scale_(paths_volume.max.x()), scale_(paths_volume.max.y()) }); - paths_hull_2d.append({ scale_(paths_volume.min.x()), scale_(paths_volume.max.y()) }); - const ModelInstanceEPrintVolumeState state = printbed_collision_state(bed_poly, bed_height, paths_hull_2d, paths_volume.min.z(), paths_volume.max.z()); - use_error_color &= state != ModelInstancePVS_Inside; - } + const Polygon bed_poly = offset(Polygon::new_scale(opt->values), static_cast(scale_(BedEpsilon))).front(); + const float bed_height = m_config->opt_float("max_print_height"); + const ModelInstanceEPrintVolumeState state = printbed_collision_state(bed_poly, bed_height, m_gcode_viewer.get_paths_bounding_box()); +// const BoundingBoxf3& paths_volume = m_gcode_viewer.get_paths_bounding_box(); +// Polygon paths_hull_2d; +// paths_hull_2d.append({ scale_(paths_volume.min.x()), scale_(paths_volume.min.y()) }); +// paths_hull_2d.append({ scale_(paths_volume.max.x()), scale_(paths_volume.min.y()) }); +// paths_hull_2d.append({ scale_(paths_volume.max.x()), scale_(paths_volume.max.y()) }); +// paths_hull_2d.append({ scale_(paths_volume.min.x()), scale_(paths_volume.max.y()) }); +// const ModelInstanceEPrintVolumeState state = printbed_collision_state(bed_poly, bed_height, paths_hull_2d, paths_volume.min.z(), paths_volume.max.z()); + use_error_color &= state != ModelInstancePVS_Inside; #else const BoundingBoxf3 test_volume = (m_config != nullptr) ? print_volume(*m_config) : BoundingBoxf3(); const BoundingBoxf3& paths_volume = m_gcode_viewer.get_paths_bounding_box(); @@ -6355,18 +6356,46 @@ void GLCanvas3D::_load_sla_shells() void GLCanvas3D::_update_toolpath_volumes_outside_state() { +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + const ConfigOptionPoints* opt = dynamic_cast(m_config->option("bed_shape")); + const Polygon bed_poly = offset(Polygon::new_scale(opt->values), static_cast(scale_(BedEpsilon))).front(); + const float bed_height = m_config->opt_float("max_print_height"); + for (GLVolume* volume : m_volumes.volumes) { + if (volume->is_extrusion_path) { + const ModelInstanceEPrintVolumeState state = printbed_collision_state(bed_poly, bed_height, volume->bounding_box()); + volume->is_outside = (state != ModelInstancePVS_Inside); + } + else + volume->is_outside = false; + } +#else BoundingBoxf3 test_volume = (m_config != nullptr) ? print_volume(*m_config) : BoundingBoxf3(); for (GLVolume* volume : m_volumes.volumes) { volume->is_outside = (test_volume.radius() > 0.0 && volume->is_extrusion_path) ? !test_volume.contains(volume->bounding_box()) : false; } +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS } void GLCanvas3D::_update_sla_shells_outside_state() { +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + const ConfigOptionPoints* opt = dynamic_cast(m_config->option("bed_shape")); + const Polygon bed_poly = offset(Polygon::new_scale(opt->values), static_cast(scale_(BedEpsilon))).front(); + const float bed_height = m_config->opt_float("max_print_height"); + for (GLVolume* volume : m_volumes.volumes) { + if (volume->shader_outside_printer_detection_enabled) { + const ModelInstanceEPrintVolumeState state = printbed_collision_state(bed_poly, bed_height, volume->transformed_convex_hull_bounding_box()); + volume->is_outside = (state != ModelInstancePVS_Inside); + } + else + volume->is_outside = false; + } +#else BoundingBoxf3 test_volume = (m_config != nullptr) ? print_volume(*m_config) : BoundingBoxf3(); for (GLVolume* volume : m_volumes.volumes) { volume->is_outside = (test_volume.radius() > 0.0 && volume->shader_outside_printer_detection_enabled) ? !test_volume.contains(volume->transformed_convex_hull_bounding_box()) : false; } +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS } void GLCanvas3D::_set_warning_notification_if_needed(EWarning warning) @@ -6377,10 +6406,18 @@ void GLCanvas3D::_set_warning_notification_if_needed(EWarning warning) show = _is_any_volume_outside(); else { if (wxGetApp().is_editor()) { +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + const ConfigOptionPoints* opt = dynamic_cast(m_config->option("bed_shape")); + const Polygon bed_poly = offset(Polygon::new_scale(opt->values), static_cast(scale_(BedEpsilon))).front(); + const float bed_height = m_config->opt_float("max_print_height"); + const ModelInstanceEPrintVolumeState state = printbed_collision_state(bed_poly, bed_height, m_gcode_viewer.get_paths_bounding_box()); + show = state != ModelInstancePVS_Inside; +#else BoundingBoxf3 test_volume = (m_config != nullptr) ? print_volume(*m_config) : BoundingBoxf3(); const BoundingBoxf3& paths_volume = m_gcode_viewer.get_paths_bounding_box(); if (test_volume.radius() > 0.0 && paths_volume.radius() > 0.0) show = !test_volume.contains(paths_volume); +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS } } _set_warning_notification(warning, show); From 13ef817a994a4b944a613d0e70a6b20fafc4b861 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Thu, 30 Sep 2021 14:51:09 +0200 Subject: [PATCH 013/102] Tech ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS - Enable detection of collision with circular printbed in backend --- src/libslic3r/Model.cpp | 78 ++++++++++++++++++++++++++++++++++- src/libslic3r/Model.hpp | 18 +++++++- src/slic3r/GUI/3DScene.cpp | 31 -------------- src/slic3r/GUI/3DScene.hpp | 9 ---- src/slic3r/GUI/GLCanvas3D.cpp | 21 +++++----- src/slic3r/GUI/Plater.cpp | 7 ++++ 6 files changed, 111 insertions(+), 53 deletions(-) diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 7bc28f904..4546444ee 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -26,6 +26,37 @@ namespace Slic3r { +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS +ModelInstanceEPrintVolumeState printbed_collision_state(const Polygon& printbed_shape, double print_volume_height, const Polygon& obj_hull_2d, double obj_min_z, double obj_max_z) +{ + static const double Z_TOLERANCE = -1e10; + + const Polygons intersection_polys = intersection(printbed_shape, obj_hull_2d); + const bool contained_xy = !intersection_polys.empty() && Geometry::are_approx(intersection_polys.front(), obj_hull_2d); + const bool contained_z = Z_TOLERANCE < obj_min_z && obj_max_z < print_volume_height; + if (contained_xy && contained_z) + return ModelInstancePVS_Inside; + + const bool intersects_xy = !contained_xy && !intersection_polys.empty(); + const bool intersects_z = !contained_z && obj_min_z < print_volume_height&& Z_TOLERANCE < obj_max_z; + if (intersects_xy || intersects_z) + return ModelInstancePVS_Partly_Outside; + + return ModelInstancePVS_Fully_Outside; +} + +ModelInstanceEPrintVolumeState printbed_collision_state(const Polygon& printbed_shape, double print_volume_height, const BoundingBoxf3& box) +{ + const Polygon box_hull_2d({ + { scale_(box.min.x()), scale_(box.min.y()) }, + { scale_(box.max.x()), scale_(box.min.y()) }, + { scale_(box.max.x()), scale_(box.max.y()) }, + { scale_(box.min.x()), scale_(box.max.y()) } + }); + return printbed_collision_state(printbed_shape, print_volume_height, box_hull_2d, box.min.z(), box.max.z()); +} +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + Model& Model::assign_copy(const Model &rhs) { this->copy_id(rhs); @@ -330,13 +361,23 @@ BoundingBoxf3 Model::bounding_box() const return bb; } -unsigned int Model::update_print_volume_state(const BoundingBoxf3 &print_volume) +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS +unsigned int Model::update_print_volume_state(const Polygon& printbed_shape, double print_volume_height) +{ + unsigned int num_printable = 0; + for (ModelObject* model_object : this->objects) + num_printable += model_object->check_instances_print_volume_state(printbed_shape, print_volume_height); + return num_printable; +} +#else +unsigned int Model::update_print_volume_state(const BoundingBoxf3 &print_volume) { unsigned int num_printable = 0; for (ModelObject *model_object : this->objects) num_printable += model_object->check_instances_print_volume_state(print_volume); return num_printable; } +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS bool Model::center_instances_around_point(const Vec2d &point) { @@ -1513,6 +1554,40 @@ double ModelObject::get_instance_max_z(size_t instance_idx) const return max_z + inst->get_offset(Z); } +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS +unsigned int ModelObject::check_instances_print_volume_state(const Polygon& printbed_shape, double print_volume_height) +{ + unsigned int num_printable = 0; + enum { + INSIDE = 1, + OUTSIDE = 2 + }; + for (ModelInstance* model_instance : this->instances) { + unsigned int inside_outside = 0; + for (const ModelVolume* vol : this->volumes) + if (vol->is_model_part()) { +#if ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION + const BoundingBoxf3 bb = vol->mesh().transformed_bounding_box(model_instance->get_matrix() * vol->get_matrix(), 0.0); +#else + const BoundingBoxf3 bb = vol->get_convex_hull().transformed_bounding_box(model_instance->get_matrix() * vol->get_matrix()); +#endif // ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION + ModelInstanceEPrintVolumeState state = printbed_collision_state(printbed_shape, print_volume_height, bb); + if (state == ModelInstancePVS_Inside) + inside_outside |= INSIDE; + else if (state == ModelInstancePVS_Fully_Outside) + inside_outside |= OUTSIDE; + else + inside_outside |= INSIDE | OUTSIDE; + } + model_instance->print_volume_state = + (inside_outside == (INSIDE | OUTSIDE)) ? ModelInstancePVS_Partly_Outside : + (inside_outside == INSIDE) ? ModelInstancePVS_Inside : ModelInstancePVS_Fully_Outside; + if (inside_outside == INSIDE) + ++num_printable; + } + return num_printable; +} +#else unsigned int ModelObject::check_instances_print_volume_state(const BoundingBoxf3& print_volume) { unsigned int num_printable = 0; @@ -1544,6 +1619,7 @@ unsigned int ModelObject::check_instances_print_volume_state(const BoundingBoxf3 } return num_printable; } +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS void ModelObject::print_info() const { diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index ea1d0ed17..1b92e01ed 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -367,7 +367,11 @@ public: double get_instance_max_z(size_t instance_idx) const; // Called by Print::validate() from the UI thread. +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + unsigned int check_instances_print_volume_state(const Polygon& printbed_shape, double print_volume_height); +#else unsigned int check_instances_print_volume_state(const BoundingBoxf3& print_volume); +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS // Print object statistics to console. void print_info() const; @@ -904,6 +908,14 @@ enum ModelInstanceEPrintVolumeState : unsigned char ModelInstanceNum_BedStates }; +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS +// return the state of the given object's volume (extrusion along z of obj_hull_2d from obj_min_z to obj_max_z) +// with respect to the given print volume (extrusion along z of printbed_shape from zero to print_volume_height) +ModelInstanceEPrintVolumeState printbed_collision_state(const Polygon& printbed_shape, double print_volume_height, const Polygon& obj_hull_2d, double obj_min_z, double obj_max_z); +// return the state of the given box +// with respect to the given print volume (extrusion along z of printbed_shape from zero to print_volume_height) +ModelInstanceEPrintVolumeState printbed_collision_state(const Polygon& printbed_shape, double print_volume_height, const BoundingBoxf3& box); +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS // A single instance of a ModelObject. // Knows the affine transformation of an object. @@ -1109,8 +1121,12 @@ public: BoundingBoxf3 bounding_box() const; // Set the print_volume_state of PrintObject::instances, // return total number of printable objects. +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + unsigned int update_print_volume_state(const Polygon& printbed_shape, double print_volume_height); +#else unsigned int update_print_volume_state(const BoundingBoxf3 &print_volume); - // Returns true if any ModelObject was modified. +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + // Returns true if any ModelObject was modified. bool center_instances_around_point(const Vec2d &point); void translate(coordf_t x, coordf_t y, coordf_t z) { for (ModelObject *o : this->objects) o->translate(x, y, z); } TriangleMesh mesh() const; diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index a0d2e8c51..78da38b13 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -67,37 +67,6 @@ void glAssertRecentCallImpl(const char* file_name, unsigned int line, const char namespace Slic3r { -#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS -ModelInstanceEPrintVolumeState printbed_collision_state(const Polygon& printbed_shape, double print_volume_height, const Polygon& obj_hull_2d, double obj_min_z, double obj_max_z) -{ - static const double Z_TOLERANCE = -1e10; - - const Polygons intersection_polys = intersection(printbed_shape, obj_hull_2d); - const bool contained_xy = !intersection_polys.empty() && Geometry::are_approx(intersection_polys.front(), obj_hull_2d); - const bool contained_z = Z_TOLERANCE < obj_min_z && obj_max_z < print_volume_height; - if (contained_xy && contained_z) - return ModelInstancePVS_Inside; - - const bool intersects_xy = !contained_xy && !intersection_polys.empty(); - const bool intersects_z = !contained_z && obj_min_z < print_volume_height && Z_TOLERANCE < obj_max_z; - if (intersects_xy || intersects_z) - return ModelInstancePVS_Partly_Outside; - - return ModelInstancePVS_Fully_Outside; -} - -ModelInstanceEPrintVolumeState printbed_collision_state(const Polygon& printbed_shape, double print_volume_height, const BoundingBoxf3& box) -{ - const Polygon box_hull_2d({ - { scale_(box.min.x()), scale_(box.min.y()) }, - { scale_(box.max.x()), scale_(box.min.y()) }, - { scale_(box.max.x()), scale_(box.max.y()) }, - { scale_(box.min.x()), scale_(box.max.y()) } - }); - return printbed_collision_state(printbed_shape, print_volume_height, box_hull_2d, box.min.z(), box.max.z()); -} -#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS - #if ENABLE_SMOOTH_NORMALS static void smooth_normals_corner(TriangleMesh& mesh, std::vector& normals) { diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index ce57d5410..7df772c7f 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -41,15 +41,6 @@ enum ModelInstanceEPrintVolumeState : unsigned char; // Return appropriate color based on the ModelVolume. std::array color_from_model_volume(const ModelVolume& model_volume); -#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS -// return the state of given object volume (extrusion along z of obj_hull_2d by obj_height) -// with respect to the given print volume (extrusion along z of printbed_shape by print_volume_height) -ModelInstanceEPrintVolumeState printbed_collision_state(const Polygon& printbed_shape, double print_volume_height, const Polygon& obj_hull_2d, double obj_min_z, double obj_max_z); -// return the state of given box -// with respect to the given print volume (extrusion along z of printbed_shape by print_volume_height) -ModelInstanceEPrintVolumeState printbed_collision_state(const Polygon& printbed_shape, double print_volume_height, const BoundingBoxf3& box); -#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS - // A container for interleaved arrays of 3D vertices and normals, // possibly indexed by triangles and / or quads. class GLIndexedVertexArray { diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index a5bba3471..66e231566 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -5014,17 +5014,16 @@ void GLCanvas3D::_render_background() const use_error_color &= _is_any_volume_outside(); else { #if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS - const ConfigOptionPoints* opt = dynamic_cast(m_config->option("bed_shape")); - const Polygon bed_poly = offset(Polygon::new_scale(opt->values), static_cast(scale_(BedEpsilon))).front(); - const float bed_height = m_config->opt_float("max_print_height"); - const ModelInstanceEPrintVolumeState state = printbed_collision_state(bed_poly, bed_height, m_gcode_viewer.get_paths_bounding_box()); -// const BoundingBoxf3& paths_volume = m_gcode_viewer.get_paths_bounding_box(); -// Polygon paths_hull_2d; -// paths_hull_2d.append({ scale_(paths_volume.min.x()), scale_(paths_volume.min.y()) }); -// paths_hull_2d.append({ scale_(paths_volume.max.x()), scale_(paths_volume.min.y()) }); -// paths_hull_2d.append({ scale_(paths_volume.max.x()), scale_(paths_volume.max.y()) }); -// paths_hull_2d.append({ scale_(paths_volume.min.x()), scale_(paths_volume.max.y()) }); -// const ModelInstanceEPrintVolumeState state = printbed_collision_state(bed_poly, bed_height, paths_hull_2d, paths_volume.min.z(), paths_volume.max.z()); + ModelInstanceEPrintVolumeState state; + if (m_gcode_viewer.has_data()) { + const ConfigOptionPoints* opt = dynamic_cast(m_config->option("bed_shape")); + const Polygon bed_poly = offset(Polygon::new_scale(opt->values), static_cast(scale_(BedEpsilon))).front(); + const float bed_height = m_config->opt_float("max_print_height"); + state = printbed_collision_state(bed_poly, bed_height, m_gcode_viewer.get_paths_bounding_box()); + } + else + state = ModelInstancePVS_Inside; + use_error_color &= state != ModelInstancePVS_Inside; #else const BoundingBoxf3 test_volume = (m_config != nullptr) ? print_volume(*m_config) : BoundingBoxf3(); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 87b83ec24..373323038 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -2946,12 +2946,19 @@ void Plater::priv::schedule_background_process() void Plater::priv::update_print_volume_state() { +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + const ConfigOptionPoints* opt = dynamic_cast(this->config->option("bed_shape")); + const Polygon bed_poly = offset(Polygon::new_scale(opt->values), static_cast(scale_(BedEpsilon))).front(); + const float bed_height = this->config->opt_float("max_print_height"); + this->q->model().update_print_volume_state(bed_poly, bed_height); +#else BoundingBox bed_box_2D = get_extents(Polygon::new_scale(this->config->opt("bed_shape")->values)); BoundingBoxf3 print_volume(unscale(bed_box_2D.min(0), bed_box_2D.min(1), 0.0), unscale(bed_box_2D.max(0), bed_box_2D.max(1), scale_(this->config->opt_float("max_print_height")))); // Allow the objects to protrude below the print bed, only the part of the object above the print bed will be sliced. print_volume.offset(BedEpsilon); print_volume.min(2) = -1e10; this->q->model().update_print_volume_state(print_volume); +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS } From f3bd5e96c5769401caaac007fcae097d46f260e4 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 1 Oct 2021 07:28:10 +0200 Subject: [PATCH 014/102] Tech ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS - Fixed detection of collision with circular printbed in backend --- src/libslic3r/Geometry.hpp | 2 +- src/libslic3r/Model.cpp | 8 +++++--- src/libslic3r/Technologies.hpp | 9 ++++++++- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/libslic3r/Geometry.hpp b/src/libslic3r/Geometry.hpp index 11d405e4c..7c670bb7c 100644 --- a/src/libslic3r/Geometry.hpp +++ b/src/libslic3r/Geometry.hpp @@ -86,7 +86,7 @@ static inline bool is_ccw(const Polygon &poly) #if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS // returns true if the given polygons are identical -static bool are_approx(const Polygon& lhs, const Polygon& rhs) +static inline bool are_approx(const Polygon& lhs, const Polygon& rhs) { if (lhs.points.size() != rhs.points.size()) return false; diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 4546444ee..73661723a 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -1566,12 +1566,14 @@ unsigned int ModelObject::check_instances_print_volume_state(const Polygon& prin unsigned int inside_outside = 0; for (const ModelVolume* vol : this->volumes) if (vol->is_model_part()) { + const Transform3d matrix = model_instance->get_matrix() * vol->get_matrix(); #if ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION - const BoundingBoxf3 bb = vol->mesh().transformed_bounding_box(model_instance->get_matrix() * vol->get_matrix(), 0.0); + const BoundingBoxf3 bb = vol->mesh().transformed_bounding_box(matrix, 0.0); #else - const BoundingBoxf3 bb = vol->get_convex_hull().transformed_bounding_box(model_instance->get_matrix() * vol->get_matrix()); + const BoundingBoxf3 bb = vol->get_convex_hull().transformed_bounding_box(matrix); #endif // ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION - ModelInstanceEPrintVolumeState state = printbed_collision_state(printbed_shape, print_volume_height, bb); + const Polygon volume_hull_2d = its_convex_hull_2d_above(vol->mesh().its, matrix.cast(), 0.0f); + ModelInstanceEPrintVolumeState state = printbed_collision_state(printbed_shape, print_volume_height, volume_hull_2d, bb.min.z(), bb.max.z()); if (state == ModelInstancePVS_Inside) inside_outside |= INSIDE; else if (state == ModelInstancePVS_Fully_Outside) diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index c096dfcf6..365493a66 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -71,8 +71,15 @@ // Enable fixing loading of gcode files generated with SuperSlicer in GCodeViewer #define ENABLE_FIX_SUPERSLICER_GCODE_IMPORT (1 && ENABLE_2_4_0_ALPHA3) + + +//==================== +// 2.4.0.alpha4 techs +//==================== +#define ENABLE_2_4_0_ALPHA4 1 + // Enable the fix for the detection of the out of bed state for sinking objects -#define ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION (1 && ENABLE_2_4_0_ALPHA3) +#define ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION (1 && ENABLE_2_4_0_ALPHA4) // Enable detection of out of bed using the bed perimeter and other improvements #define ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS (1 && ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION) From 6ff4d6c3f5a748d4797a911e60064dcd6638422f Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 1 Oct 2021 12:15:14 +0200 Subject: [PATCH 015/102] Tech ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS - Fixed detection of collision with circular printbed for pre-gcode preview and sla preview --- src/slic3r/GUI/3DScene.cpp | 144 +++++++++++++++++++++++++++++----- src/slic3r/GUI/3DScene.hpp | 6 ++ src/slic3r/GUI/GLCanvas3D.cpp | 58 +++++++++----- 3 files changed, 170 insertions(+), 38 deletions(-) diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 78da38b13..4eb1837c7 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -37,6 +37,12 @@ #include +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS +#include +#include +#include +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + #ifdef HAS_GLSAFE void glAssertRecentCallImpl(const char* file_name, unsigned int line, const char* function_name) { @@ -614,6 +620,106 @@ void GLVolume::render_sinking_contours() m_sinking_contours.render(); } +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS +void GLVolume::calc_convex_hull_3d() +{ + if (this->indexed_vertex_array.vertices_and_normals_interleaved.empty()) + return; + + TriangleMesh mesh; + for (size_t i = 0; i < this->indexed_vertex_array.vertices_and_normals_interleaved.size(); i += 6) { + const size_t v_id = 3 + i; + mesh.its.vertices.push_back({ this->indexed_vertex_array.vertices_and_normals_interleaved[v_id + 0], + this->indexed_vertex_array.vertices_and_normals_interleaved[v_id + 1], + this->indexed_vertex_array.vertices_and_normals_interleaved[v_id + 2] + }); + } + + const std::vector& vertices = mesh.its.vertices; + + // The qhull call: + orgQhull::Qhull qhull; + qhull.disableOutputStream(); // we want qhull to be quiet + std::vector src_vertices; + try + { +#if REALfloat + qhull.runQhull("", 3, (int)vertices.size(), (const realT*)(vertices.front().data()), "Qt"); +#else + src_vertices.reserve(vertices.size() * 3); + // We will now fill the vector with input points for computation: + for (const stl_vertex& v : vertices) + for (int i = 0; i < 3; ++i) + src_vertices.emplace_back(v(i)); + qhull.runQhull("", 3, (int)src_vertices.size() / 3, src_vertices.data(), "Qt"); +#endif + } + catch (...) + { + std::cout << "GLVolume::calc_convex_hull_3d() - Unable to create convex hull" << std::endl; + return ; + } + + // Let's collect results: + std::vector dst_vertices; + std::vector dst_facets; + // Map of QHull's vertex ID to our own vertex ID (pointing to dst_vertices). + std::vector map_dst_vertices; +#ifndef NDEBUG + Vec3f centroid = Vec3f::Zero(); + for (const auto& pt : vertices) + centroid += pt; + centroid /= float(vertices.size()); +#endif // NDEBUG + for (const orgQhull::QhullFacet& facet : qhull.facetList()) { + // Collect face vertices first, allocate unique vertices in dst_vertices based on QHull's vertex ID. + Vec3i indices; + int cnt = 0; + for (const orgQhull::QhullVertex vertex : facet.vertices()) { + const int id = vertex.id(); + assert(id >= 0); + if (id >= int(map_dst_vertices.size())) + map_dst_vertices.resize(next_highest_power_of_2(size_t(id + 1)), -1); + if (int i = map_dst_vertices[id]; i == -1) { + // Allocate a new vertex. + i = int(dst_vertices.size()); + map_dst_vertices[id] = i; + orgQhull::QhullPoint pt(vertex.point()); + dst_vertices.emplace_back(pt[0], pt[1], pt[2]); + indices[cnt] = i; + } + else + // Reuse existing vertex. + indices[cnt] = i; + + if (cnt++ == 3) + break; + } + assert(cnt == 3); + if (cnt == 3) { + // QHull sorts vertices of a face lexicographically by their IDs, not by face normals. + // Calculate face normal based on the order of vertices. + const Vec3f n = (dst_vertices[indices(1)] - dst_vertices[indices(0)]).cross(dst_vertices[indices(2)] - dst_vertices[indices(1)]); + auto* n2 = facet.getBaseT()->normal; + const auto d = n.x() * n2[0] + n.y() * n2[1] + n.z() * n2[2]; +#ifndef NDEBUG + const Vec3f n3 = (dst_vertices[indices(0)] - centroid); + const auto d3 = n.dot(n3); + assert((d < 0.f) == (d3 < 0.f)); +#endif // NDEBUG + // Get the face normal from QHull. + if (d < 0.f) + // Fix face orientation. + std::swap(indices[1], indices[2]); + dst_facets.emplace_back(indices); + } + } + + TriangleMesh out_mesh{ std::move(dst_vertices), std::move(dst_facets) }; + this->set_convex_hull(out_mesh); +} +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + std::vector GLVolumeCollection::load_object( const ModelObject *model_object, int obj_idx, @@ -771,7 +877,10 @@ int GLVolumeCollection::load_wipe_tower_preview( volumes.emplace_back(new GLVolume(color)); GLVolume& v = *volumes.back(); - v.indexed_vertex_array.load_mesh(mesh); + v.indexed_vertex_array.load_mesh(mesh); +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + v.calc_convex_hull_3d(); +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS v.indexed_vertex_array.finalize_geometry(opengl_initialized); v.set_volume_offset(Vec3d(pos_x, pos_y, 0.0)); v.set_volume_rotation(Vec3d(0., 0., (M_PI / 180.) * rotation_angle)); @@ -964,12 +1073,16 @@ bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, M #if ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION bool contained = false; bool intersects = false; - bool is_sla = GUI::wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA; - const BoundingBoxf3 bb = is_sla ? volume->transformed_convex_hull_bounding_box() : volume->transformed_non_sinking_bounding_box(); + bool is_aux_volume = volume->is_sla_support() || volume->is_sla_pad() || volume->is_wipe_tower; + const BoundingBoxf3 bb = is_aux_volume ? volume->transformed_convex_hull_bounding_box() : volume->transformed_non_sinking_bounding_box(); #if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS ModelInstanceEPrintVolumeState volume_state; - if (is_sla) - volume_state = printbed_collision_state(bed_poly, bed_height, bb); + if (is_aux_volume) { + if (volume->is_sla_support() || volume->is_wipe_tower) { + const Polygon volume_hull_2d = its_convex_hull_2d_above(volume->convex_hull()->its, volume->world_matrix().cast(), 0.0f); + volume_state = printbed_collision_state(bed_poly, bed_height, volume_hull_2d, bb.min.z(), bb.max.z()); + } + } else { const indexed_triangle_set& its = GUI::wxGetApp().plater()->model().objects[volume->object_idx()]->volumes[volume->volume_idx()]->mesh().its; const Polygon volume_hull_2d = its_convex_hull_2d_above(its, volume->world_matrix().cast(), 0.0f); @@ -1061,35 +1174,28 @@ void GLVolumeCollection::update_colors_by_extruder(const DynamicPrintConfig* con std::vector colors(colors_count); unsigned char rgb[3]; - for (unsigned int i = 0; i < colors_count; ++i) - { + for (unsigned int i = 0; i < colors_count; ++i) { const std::string& txt_color = config->opt_string("extruder_colour", i); if (Slic3r::GUI::BitmapCache::parse_color(txt_color, rgb)) - { colors[i].set(txt_color, rgb); - } - else - { + else { const std::string& txt_color = config->opt_string("filament_colour", i); if (Slic3r::GUI::BitmapCache::parse_color(txt_color, rgb)) colors[i].set(txt_color, rgb); } } - for (GLVolume* volume : volumes) - { - if ((volume == nullptr) || volume->is_modifier || volume->is_wipe_tower || (volume->volume_idx() < 0)) + for (GLVolume* volume : volumes) { + if (volume == nullptr || volume->is_modifier || volume->is_wipe_tower || (volume->volume_idx() < 0)) continue; int extruder_id = volume->extruder_id - 1; - if ((extruder_id < 0) || ((int)colors.size() <= extruder_id)) + if (extruder_id < 0 || (int)colors.size() <= extruder_id) extruder_id = 0; const Color& color = colors[extruder_id]; - if (!color.text.empty()) - { - for (int i = 0; i < 3; ++i) - { + if (!color.text.empty()) { + for (int i = 0; i < 3; ++i) { volume->color[i] = (float)color.rgb[i] * inv_255; } } diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index 7df772c7f..8aaf48549 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -515,6 +515,12 @@ public: // Return an estimate of the memory held by GPU vertex buffers. size_t gpu_memory_used() const { return this->indexed_vertex_array.gpu_memory_used(); } size_t total_memory_used() const { return this->cpu_memory_used() + this->gpu_memory_used(); } + +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + // calculates the 3D convex hull from indexed_vertex_array.vertices_and_normals_interleaved + // must be called before calling indexed_vertex_array.finalize_geometry(); + void calc_convex_hull_3d(); +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS }; typedef std::vector GLVolumePtrs; diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 305cdd9d3..84c5053ef 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1826,8 +1826,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re assert(volume_idx_wipe_tower_old == -1); volume_idx_wipe_tower_old = (int)volume_id; } - if (!m_reload_delayed) - { + if (!m_reload_delayed) { deleted_volumes.emplace_back(volume, volume_id); delete volume; } @@ -5016,8 +5015,7 @@ void GLCanvas3D::_render_background() const #if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS ModelInstanceEPrintVolumeState state; if (m_gcode_viewer.has_data()) { - const ConfigOptionPoints* opt = dynamic_cast(m_config->option("bed_shape")); - const Polygon bed_poly = offset(Polygon::new_scale(opt->values), static_cast(scale_(BedEpsilon))).front(); + const Polygon bed_poly = offset(Polygon::new_scale(wxGetApp().plater()->get_bed().get_shape()), static_cast(scale_(BedEpsilon))).front(); const float bed_height = m_config->opt_float("max_print_height"); state = printbed_collision_state(bed_poly, bed_height, m_gcode_viewer.get_paths_bounding_box()); } @@ -5813,7 +5811,7 @@ void GLCanvas3D::_load_print_toolpaths() total_layer_count = std::max(total_layer_count, print_object->total_layer_count()); } size_t skirt_height = print->has_infinite_skirt() ? total_layer_count : std::min(print->config().skirt_height.value, total_layer_count); - if ((skirt_height == 0) && print->has_brim()) + if (skirt_height == 0 && print->has_brim()) skirt_height = 1; // Get first skirt_height layers. @@ -5846,6 +5844,9 @@ void GLCanvas3D::_load_print_toolpaths() reserve_new_volume_finalize_old_volume(*volume, vol, m_initialized); } } +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + volume->calc_convex_hull_3d(); +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS volume->indexed_vertex_array.finalize_geometry(m_initialized); } @@ -6136,8 +6137,16 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c std::remove_if(m_volumes.volumes.begin() + volumes_cnt_initial, m_volumes.volumes.end(), [](const GLVolume *volume) { return volume->empty(); }), m_volumes.volumes.end()); +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + for (size_t i = volumes_cnt_initial; i < m_volumes.volumes.size(); ++i) { + GLVolume* v = m_volumes.volumes[i]; + v->calc_convex_hull_3d(); + v->indexed_vertex_array.finalize_geometry(m_initialized); + } +#else for (size_t i = volumes_cnt_initial; i < m_volumes.volumes.size(); ++i) m_volumes.volumes[i]->indexed_vertex_array.finalize_geometry(m_initialized); +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS BOOST_LOG_TRIVIAL(debug) << "Loading print object toolpaths in parallel - end" << m_volumes.log_memory_info() << log_memory_info(); } @@ -6145,7 +6154,7 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c void GLCanvas3D::_load_wipe_tower_toolpaths(const std::vector& str_tool_colors) { const Print *print = this->fff_print(); - if ((print == nullptr) || print->wipe_tower_data().tool_changes.empty()) + if (print == nullptr || print->wipe_tower_data().tool_changes.empty()) return; if (!print->is_step_done(psWipeTower)) @@ -6293,8 +6302,16 @@ void GLCanvas3D::_load_wipe_tower_toolpaths(const std::vector& str_ std::remove_if(m_volumes.volumes.begin() + volumes_cnt_initial, m_volumes.volumes.end(), [](const GLVolume *volume) { return volume->empty(); }), m_volumes.volumes.end()); +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + for (size_t i = volumes_cnt_initial; i < m_volumes.volumes.size(); ++i) { + GLVolume* v = m_volumes.volumes[i]; + v->calc_convex_hull_3d(); + v->indexed_vertex_array.finalize_geometry(m_initialized); + } +#else for (size_t i = volumes_cnt_initial; i < m_volumes.volumes.size(); ++i) m_volumes.volumes[i]->indexed_vertex_array.finalize_geometry(m_initialized); +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS BOOST_LOG_TRIVIAL(debug) << "Loading wipe tower toolpaths in parallel - end" << m_volumes.log_memory_info() << log_memory_info(); } @@ -6357,12 +6374,13 @@ void GLCanvas3D::_load_sla_shells() void GLCanvas3D::_update_toolpath_volumes_outside_state() { #if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS - const ConfigOptionPoints* opt = dynamic_cast(m_config->option("bed_shape")); - const Polygon bed_poly = offset(Polygon::new_scale(opt->values), static_cast(scale_(BedEpsilon))).front(); + const Polygon bed_poly = offset(Polygon::new_scale(wxGetApp().plater()->get_bed().get_shape()), static_cast(scale_(BedEpsilon))).front(); const float bed_height = m_config->opt_float("max_print_height"); for (GLVolume* volume : m_volumes.volumes) { if (volume->is_extrusion_path) { - const ModelInstanceEPrintVolumeState state = printbed_collision_state(bed_poly, bed_height, volume->bounding_box()); + const BoundingBoxf3& bb = volume->transformed_convex_hull_bounding_box(); + const Polygon volume_hull_2d = its_convex_hull_2d_above(volume->convex_hull()->its, volume->world_matrix().cast(), 0.0f); + const ModelInstanceEPrintVolumeState state = printbed_collision_state(bed_poly, bed_height, volume_hull_2d, bb.min.z(), bb.max.z()); volume->is_outside = (state != ModelInstancePVS_Inside); } else @@ -6379,12 +6397,13 @@ void GLCanvas3D::_update_toolpath_volumes_outside_state() void GLCanvas3D::_update_sla_shells_outside_state() { #if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS - const ConfigOptionPoints* opt = dynamic_cast(m_config->option("bed_shape")); - const Polygon bed_poly = offset(Polygon::new_scale(opt->values), static_cast(scale_(BedEpsilon))).front(); + const Polygon bed_poly = offset(Polygon::new_scale(wxGetApp().plater()->get_bed().get_shape()), static_cast(scale_(BedEpsilon))).front(); const float bed_height = m_config->opt_float("max_print_height"); for (GLVolume* volume : m_volumes.volumes) { if (volume->shader_outside_printer_detection_enabled) { - const ModelInstanceEPrintVolumeState state = printbed_collision_state(bed_poly, bed_height, volume->transformed_convex_hull_bounding_box()); + const BoundingBoxf3& bb = volume->transformed_convex_hull_bounding_box(); + const Polygon volume_hull_2d = its_convex_hull_2d_above(volume->convex_hull()->its, volume->world_matrix().cast(), 0.0f); + const ModelInstanceEPrintVolumeState state = printbed_collision_state(bed_poly, bed_height, volume_hull_2d, bb.min.z(), bb.max.z()); volume->is_outside = (state != ModelInstancePVS_Inside); } else @@ -6407,11 +6426,12 @@ void GLCanvas3D::_set_warning_notification_if_needed(EWarning warning) else { if (wxGetApp().is_editor()) { #if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS - const ConfigOptionPoints* opt = dynamic_cast(m_config->option("bed_shape")); - const Polygon bed_poly = offset(Polygon::new_scale(opt->values), static_cast(scale_(BedEpsilon))).front(); - const float bed_height = m_config->opt_float("max_print_height"); - const ModelInstanceEPrintVolumeState state = printbed_collision_state(bed_poly, bed_height, m_gcode_viewer.get_paths_bounding_box()); - show = state != ModelInstancePVS_Inside; + if (current_printer_technology() != ptSLA) { + const Polygon bed_poly = offset(Polygon::new_scale(wxGetApp().plater()->get_bed().get_shape()), static_cast(scale_(BedEpsilon))).front(); + const float bed_height = m_config->opt_float("max_print_height"); + const ModelInstanceEPrintVolumeState state = printbed_collision_state(bed_poly, bed_height, m_gcode_viewer.get_paths_bounding_box()); + show = state != ModelInstancePVS_Inside; + } #else BoundingBoxf3 test_volume = (m_config != nullptr) ? print_volume(*m_config) : BoundingBoxf3(); const BoundingBoxf3& paths_volume = m_gcode_viewer.get_paths_bounding_box(); @@ -6464,7 +6484,7 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state) "Resolve the current problem to continue slicing."); error = ErrorType::PLATER_ERROR; break; -} + } auto& notification_manager = *wxGetApp().plater()->get_notification_manager(); switch (error) { @@ -6494,7 +6514,7 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state) bool GLCanvas3D::_is_any_volume_outside() const { for (const GLVolume* volume : m_volumes.volumes) { - if ((volume != nullptr) && volume->is_outside) + if (volume != nullptr && volume->is_outside) return true; } From f84838028b5a8b86338b861777eb507c298f7bba Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 1 Oct 2021 13:13:26 +0200 Subject: [PATCH 016/102] Tech ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION merged into tech ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS --- src/libslic3r/Model.cpp | 8 -------- src/libslic3r/Technologies.hpp | 5 ++--- src/libslic3r/TriangleMesh.cpp | 4 ++-- src/libslic3r/TriangleMesh.hpp | 4 ++-- src/slic3r/GUI/3DScene.cpp | 17 ++++++----------- src/slic3r/GUI/3DScene.hpp | 12 ++++++------ 6 files changed, 18 insertions(+), 32 deletions(-) diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 73661723a..95d2c8f81 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -1567,11 +1567,7 @@ unsigned int ModelObject::check_instances_print_volume_state(const Polygon& prin for (const ModelVolume* vol : this->volumes) if (vol->is_model_part()) { const Transform3d matrix = model_instance->get_matrix() * vol->get_matrix(); -#if ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION const BoundingBoxf3 bb = vol->mesh().transformed_bounding_box(matrix, 0.0); -#else - const BoundingBoxf3 bb = vol->get_convex_hull().transformed_bounding_box(matrix); -#endif // ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION const Polygon volume_hull_2d = its_convex_hull_2d_above(vol->mesh().its, matrix.cast(), 0.0f); ModelInstanceEPrintVolumeState state = printbed_collision_state(printbed_shape, print_volume_height, volume_hull_2d, bb.min.z(), bb.max.z()); if (state == ModelInstancePVS_Inside) @@ -1601,11 +1597,7 @@ unsigned int ModelObject::check_instances_print_volume_state(const BoundingBoxf3 unsigned int inside_outside = 0; for (const ModelVolume *vol : this->volumes) if (vol->is_model_part()) { -#if ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION - BoundingBoxf3 bb = vol->mesh().transformed_bounding_box(model_instance->get_matrix() * vol->get_matrix(), 0.0); -#else BoundingBoxf3 bb = vol->get_convex_hull().transformed_bounding_box(model_instance->get_matrix() * vol->get_matrix()); -#endif // ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION if (print_volume.contains(bb)) inside_outside |= INSIDE; else if (print_volume.intersects(bb)) diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index 365493a66..7f24b6ede 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -79,9 +79,8 @@ #define ENABLE_2_4_0_ALPHA4 1 // Enable the fix for the detection of the out of bed state for sinking objects -#define ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION (1 && ENABLE_2_4_0_ALPHA4) -// Enable detection of out of bed using the bed perimeter and other improvements -#define ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS (1 && ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION) +// and detection of out of bed using the bed perimeter +#define ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS (1 && ENABLE_2_4_0_ALPHA4) #endif // _prusaslicer_technologies_h_ diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp index 6386591ae..290cb95e1 100644 --- a/src/libslic3r/TriangleMesh.cpp +++ b/src/libslic3r/TriangleMesh.cpp @@ -429,7 +429,7 @@ BoundingBoxf3 TriangleMesh::transformed_bounding_box(const Transform3d &trafo) c return bbox; } -#if ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS BoundingBoxf3 TriangleMesh::transformed_bounding_box(const Transform3d& trafo, double world_min_z) const { BoundingBoxf3 bbox; @@ -452,7 +452,7 @@ BoundingBoxf3 TriangleMesh::transformed_bounding_box(const Transform3d& trafo, d } return bbox; } -#endif // ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS TriangleMesh TriangleMesh::convex_hull_3d() const { diff --git a/src/libslic3r/TriangleMesh.hpp b/src/libslic3r/TriangleMesh.hpp index b6a3c7249..b730a7608 100644 --- a/src/libslic3r/TriangleMesh.hpp +++ b/src/libslic3r/TriangleMesh.hpp @@ -113,10 +113,10 @@ public: BoundingBoxf3 bounding_box() const; // Returns the bbox of this TriangleMesh transformed by the given transformation BoundingBoxf3 transformed_bounding_box(const Transform3d &trafo) const; -#if ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS // Variant returning the bbox of the part of this TriangleMesh above the given world_min_z BoundingBoxf3 transformed_bounding_box(const Transform3d& trafo, double world_min_z) const; -#endif // ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS // Return the size of the mesh in coordinates. Vec3d size() const { return m_stats.size.cast(); } /// Return the center of the related bounding box. diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 4eb1837c7..f3e4cfad1 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -529,7 +529,7 @@ BoundingBoxf3 GLVolume::transformed_convex_hull_bounding_box(const Transform3d & bounding_box().transformed(trafo); } -#if ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS BoundingBoxf3 GLVolume::transformed_non_sinking_bounding_box(const Transform3d& trafo) const { return GUI::wxGetApp().plater()->model().objects[object_idx()]->volumes[volume_idx()]->mesh().transformed_bounding_box(trafo, 0.0); @@ -544,7 +544,7 @@ const BoundingBoxf3& GLVolume::transformed_non_sinking_bounding_box() const } return *m_transformed_non_sinking_bounding_box; } -#endif // ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS void GLVolume::set_range(double min_z, double max_z) { @@ -1070,12 +1070,11 @@ bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, M if (volume->is_modifier || (!volume->shader_outside_printer_detection_enabled && (volume->is_wipe_tower || volume->composite_id.volume_id < 0))) continue; -#if ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS bool contained = false; bool intersects = false; bool is_aux_volume = volume->is_sla_support() || volume->is_sla_pad() || volume->is_wipe_tower; const BoundingBoxf3 bb = is_aux_volume ? volume->transformed_convex_hull_bounding_box() : volume->transformed_non_sinking_bounding_box(); -#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS ModelInstanceEPrintVolumeState volume_state; if (is_aux_volume) { if (volume->is_sla_support() || volume->is_wipe_tower) { @@ -1090,14 +1089,10 @@ bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, M } contained = (volume_state == ModelInstancePVS_Inside); intersects = (volume_state == ModelInstancePVS_Partly_Outside); -#else - contained = print_volume.contains(bb); - intersects = print_volume.intersects(bb); -#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS #else const BoundingBoxf3& bb = volume->transformed_convex_hull_bounding_box(); bool contained = print_volume.contains(bb); -#endif // ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS volume->is_outside = !contained; if (!volume->printable) @@ -1108,13 +1103,13 @@ bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, M if (overall_state == ModelInstancePVS_Inside && volume->is_outside) overall_state = ModelInstancePVS_Fully_Outside; -#if ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS if (overall_state == ModelInstancePVS_Fully_Outside && volume->is_outside && intersects) overall_state = ModelInstancePVS_Partly_Outside; #else if (overall_state == ModelInstancePVS_Fully_Outside && volume->is_outside && print_volume.intersects(bb)) overall_state = ModelInstancePVS_Partly_Outside; -#endif // ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS } if (out_state != nullptr) diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index 8aaf48549..0b1293f56 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -278,10 +278,10 @@ private: std::shared_ptr m_convex_hull; // Bounding box of this volume, in unscaled coordinates. std::optional m_transformed_convex_hull_bounding_box; -#if ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS // Bounding box of the non sinking part of this volume, in unscaled coordinates. std::optional m_transformed_non_sinking_bounding_box; -#endif // ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS class SinkingContours { @@ -472,12 +472,12 @@ public: BoundingBoxf3 transformed_convex_hull_bounding_box(const Transform3d &trafo) const; // caching variant const BoundingBoxf3& transformed_convex_hull_bounding_box() const; -#if ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS // non-caching variant BoundingBoxf3 transformed_non_sinking_bounding_box(const Transform3d& trafo) const; // caching variant const BoundingBoxf3& transformed_non_sinking_bounding_box() const; -#endif // ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS // convex hull const TriangleMesh* convex_hull() const { return m_convex_hull.get(); } @@ -490,7 +490,7 @@ public: void finalize_geometry(bool opengl_initialized) { this->indexed_vertex_array.finalize_geometry(opengl_initialized); } void release_geometry() { this->indexed_vertex_array.release_geometry(); } -#if ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS void set_bounding_boxes_as_dirty() { m_transformed_bounding_box.reset(); m_transformed_convex_hull_bounding_box.reset(); @@ -498,7 +498,7 @@ public: } #else void set_bounding_boxes_as_dirty() { m_transformed_bounding_box.reset(); m_transformed_convex_hull_bounding_box.reset(); } -#endif // ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS bool is_sla_support() const; bool is_sla_pad() const; From 45db1c13bad6d0558a35a977e7378edbf1b8b2ce Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 4 Oct 2021 08:30:04 +0200 Subject: [PATCH 017/102] Tech ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS - Faster update of object manipulation fields while dragging gizmo Move/Rotate/Scale --- src/slic3r/GUI/GLCanvas3D.cpp | 5 +++++ src/slic3r/GUI/GUI_ObjectManipulation.cpp | 7 ++++++- src/slic3r/GUI/Selection.cpp | 7 +++++++ src/slic3r/GUI/Selection.hpp | 8 ++++++++ 4 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 84c5053ef..2cc92f987 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -3215,6 +3215,11 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) } } else if (evt.LeftUp() || evt.MiddleUp() || evt.RightUp()) { +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + if (evt.LeftUp()) + m_selection.stop_dragging(); +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + if (m_layers_editing.state != LayersEditing::Unknown) { m_layers_editing.state = LayersEditing::Unknown; _stop_timer(); diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp index 6eaa6316d..0f68d01c9 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp @@ -631,7 +631,6 @@ void ObjectManipulation::update_if_dirty() update(m_cache.rotation, m_cache.rotation_rounded, meRotation, m_new_rotation); } - if (selection.requires_uniform_scale()) { m_lock_bnt->SetLock(true); m_lock_bnt->SetToolTip(_L("You cannot use non-uniform scaling mode for multiple objects/parts selection")); @@ -654,8 +653,14 @@ void ObjectManipulation::update_if_dirty() else m_og->disable(); +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + if (!selection.is_dragging()) { +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS update_reset_buttons_visibility(); update_mirror_buttons_visibility(); +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + } +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS m_dirty = false; } diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index 0c863665d..6aff77cf7 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -112,6 +112,9 @@ Selection::Selection() , m_type(Empty) , m_valid(false) , m_scale_factor(1.0f) +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + , m_dragging(false) +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS { this->set_bounding_boxes_dirty(); } @@ -676,6 +679,10 @@ void Selection::start_dragging() if (!m_valid) return; +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + m_dragging = true; +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + set_caches(); } diff --git a/src/slic3r/GUI/Selection.hpp b/src/slic3r/GUI/Selection.hpp index dea507511..cb8f38d50 100644 --- a/src/slic3r/GUI/Selection.hpp +++ b/src/slic3r/GUI/Selection.hpp @@ -220,6 +220,10 @@ private: float m_scale_factor; +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + bool m_dragging; +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + public: Selection(); @@ -312,6 +316,10 @@ public: const BoundingBoxf3& get_scaled_instance_bounding_box() const; void start_dragging(); +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + void stop_dragging() { m_dragging = false; } + bool is_dragging() const { return m_dragging; } +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS void translate(const Vec3d& displacement, bool local = false); void rotate(const Vec3d& rotation, TransformationType transformation_type); From 4521945bb3aaafdc63b4ed54c03c753dfa08594c Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 4 Oct 2021 14:07:45 +0200 Subject: [PATCH 018/102] Tech ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS - Faster printbed collision detection using the new function Geometry::intersect() --- src/libslic3r/Model.cpp | 24 +++++++++++------------- src/slic3r/GUI/3DScene.cpp | 4 ++-- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 95d2c8f81..885e620e0 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -29,20 +29,18 @@ namespace Slic3r { #if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS ModelInstanceEPrintVolumeState printbed_collision_state(const Polygon& printbed_shape, double print_volume_height, const Polygon& obj_hull_2d, double obj_min_z, double obj_max_z) { - static const double Z_TOLERANCE = -1e10; + if (!Geometry::intersects(printbed_shape, obj_hull_2d)) + return ModelInstancePVS_Fully_Outside; - const Polygons intersection_polys = intersection(printbed_shape, obj_hull_2d); - const bool contained_xy = !intersection_polys.empty() && Geometry::are_approx(intersection_polys.front(), obj_hull_2d); - const bool contained_z = Z_TOLERANCE < obj_min_z && obj_max_z < print_volume_height; - if (contained_xy && contained_z) - return ModelInstancePVS_Inside; - - const bool intersects_xy = !contained_xy && !intersection_polys.empty(); - const bool intersects_z = !contained_z && obj_min_z < print_volume_height&& Z_TOLERANCE < obj_max_z; - if (intersects_xy || intersects_z) - return ModelInstancePVS_Partly_Outside; - - return ModelInstancePVS_Fully_Outside; + bool contained_xy = true; + for (const Point& p : obj_hull_2d) { + if (!printbed_shape.contains(p)) { + contained_xy = false; + break; + } + } + const bool contained_z = -1e10 < obj_min_z && obj_max_z < print_volume_height; + return (contained_xy && contained_z) ? ModelInstancePVS_Inside : ModelInstancePVS_Partly_Outside; } ModelInstanceEPrintVolumeState printbed_collision_state(const Polygon& printbed_shape, double print_volume_height, const BoundingBoxf3& box) diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index f3e4cfad1..3cba38a6e 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -1083,8 +1083,8 @@ bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, M } } else { - const indexed_triangle_set& its = GUI::wxGetApp().plater()->model().objects[volume->object_idx()]->volumes[volume->volume_idx()]->mesh().its; - const Polygon volume_hull_2d = its_convex_hull_2d_above(its, volume->world_matrix().cast(), 0.0f); + const TriangleMesh* mesh = volume->is_sinking() ? &GUI::wxGetApp().plater()->model().objects[volume->object_idx()]->volumes[volume->volume_idx()]->mesh() : volume->convex_hull(); + const Polygon volume_hull_2d = its_convex_hull_2d_above(mesh->its, volume->world_matrix().cast(), 0.0f); volume_state = printbed_collision_state(bed_poly, bed_height, volume_hull_2d, bb.min.z(), bb.max.z()); } contained = (volume_state == ModelInstancePVS_Inside); From 4ff13a5d63297438d1c489c40936c4274bb5f562 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 6 Oct 2021 13:47:54 +0200 Subject: [PATCH 019/102] Tech ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS - Reworked detection of collision with printbed. The detection uses now different algorithms in dependence of the printbed type (rectangular, circular, convex) to improve performance. --- src/libslic3r/GCode/GCodeProcessor.cpp | 16 ++++ src/libslic3r/GCode/GCodeProcessor.hpp | 3 + src/slic3r/GUI/3DBed.cpp | 9 +- src/slic3r/GUI/3DBed.hpp | 1 + src/slic3r/GUI/3DScene.cpp | 115 ++++++++++++++++++------- src/slic3r/GUI/3DScene.hpp | 4 + src/slic3r/GUI/GCodeViewer.cpp | 61 ++++++++++++- src/slic3r/GUI/GCodeViewer.hpp | 11 +++ src/slic3r/GUI/GLCanvas3D.cpp | 59 ++++--------- src/slic3r/GUI/GLCanvas3D.hpp | 4 + 10 files changed, 209 insertions(+), 74 deletions(-) diff --git a/src/libslic3r/GCode/GCodeProcessor.cpp b/src/libslic3r/GCode/GCodeProcessor.cpp index 9c90535c4..45c0de616 100644 --- a/src/libslic3r/GCode/GCodeProcessor.cpp +++ b/src/libslic3r/GCode/GCodeProcessor.cpp @@ -720,6 +720,9 @@ void GCodeProcessor::UsedFilaments::process_caches(GCodeProcessor* processor) void GCodeProcessor::Result::reset() { moves = std::vector(); bed_shape = Pointfs(); +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + max_print_height = 0.0f; +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS settings_ids.reset(); extruders_count = 0; extruder_colors = std::vector(); @@ -734,6 +737,9 @@ void GCodeProcessor::Result::reset() { moves.clear(); lines_ends.clear(); bed_shape = Pointfs(); +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + max_print_height = 0.0f; +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS settings_ids.reset(); extruders_count = 0; extruder_colors = std::vector(); @@ -883,6 +889,10 @@ void GCodeProcessor::apply_config(const PrintConfig& config) const ConfigOptionFloatOrPercent* first_layer_height = config.option("first_layer_height"); if (first_layer_height != nullptr) m_first_layer_height = std::abs(first_layer_height->value); + +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + m_result.max_print_height = config.max_print_height; +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS } void GCodeProcessor::apply_config(const DynamicPrintConfig& config) @@ -1112,6 +1122,12 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config) const ConfigOptionFloatOrPercent* first_layer_height = config.option("first_layer_height"); if (first_layer_height != nullptr) m_first_layer_height = std::abs(first_layer_height->value); + +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + const ConfigOptionFloat* max_print_height = config.option("max_print_height"); + if (max_print_height != nullptr) + m_result.max_print_height = max_print_height->value; +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS } void GCodeProcessor::enable_stealth_time_estimator(bool enabled) diff --git a/src/libslic3r/GCode/GCodeProcessor.hpp b/src/libslic3r/GCode/GCodeProcessor.hpp index fce888233..e7d602155 100644 --- a/src/libslic3r/GCode/GCodeProcessor.hpp +++ b/src/libslic3r/GCode/GCodeProcessor.hpp @@ -351,6 +351,9 @@ namespace Slic3r { // Positions of ends of lines of the final G-code this->filename after TimeProcessor::post_process() finalizes the G-code. std::vector lines_ends; Pointfs bed_shape; +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + float max_print_height; +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS SettingsIds settings_ids; size_t extruders_count; std::vector extruder_colors; diff --git a/src/slic3r/GUI/3DBed.cpp b/src/slic3r/GUI/3DBed.cpp index 6e04664e2..18c017da1 100644 --- a/src/slic3r/GUI/3DBed.cpp +++ b/src/slic3r/GUI/3DBed.cpp @@ -282,9 +282,11 @@ bool Bed3D::is_circle(const Pointfs& shape, Vec2d* center, double* radius) avg_dist /= vertex_distances.size(); + double tolerance = avg_dist * 0.01; + bool defined_value = true; for (double el : vertex_distances) { - if (fabs(el - avg_dist) > 10.0 * SCALED_EPSILON) + if (fabs(el - avg_dist) > tolerance) defined_value = false; break; } @@ -298,6 +300,11 @@ bool Bed3D::is_circle(const Pointfs& shape, Vec2d* center, double* radius) return defined_value; } +bool Bed3D::is_convex(const Pointfs& shape) +{ + return Polygon::new_scale(shape).convex_points().size() == shape.size(); +} + Bed3D::EShapeType Bed3D::detect_shape_type(const Pointfs& shape) { if (shape.size() < 3) diff --git a/src/slic3r/GUI/3DBed.hpp b/src/slic3r/GUI/3DBed.hpp index baa0ef5b7..07b9f1758 100644 --- a/src/slic3r/GUI/3DBed.hpp +++ b/src/slic3r/GUI/3DBed.hpp @@ -139,6 +139,7 @@ public: #if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS static bool is_rectangle(const Pointfs& shape, Vec2d* min = nullptr, Vec2d* max = nullptr); static bool is_circle(const Pointfs& shape, Vec2d* center = nullptr, double* radius = nullptr); + static bool is_convex(const Pointfs& shape); static EShapeType detect_shape_type(const Pointfs& shape); #endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 3cba38a6e..d6999df61 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -11,6 +11,9 @@ #include "GUI_App.hpp" #include "Plater.hpp" #include "BitmapCache.hpp" +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS +#include "3DBed.hpp" +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS #include "libslic3r/ExtrusionEntity.hpp" #include "libslic3r/ExtrusionEntityCollection.hpp" @@ -267,6 +270,12 @@ void GLIndexedVertexArray::render( const std::pair& tverts_range, const std::pair& qverts_range) const { +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + // this method has been called before calling finalize() ? + if (this->vertices_and_normals_interleaved_VBO_id == 0 && !this->vertices_and_normals_interleaved.empty()) + return; +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + assert(this->vertices_and_normals_interleaved_VBO_id != 0); assert(this->triangle_indices_VBO_id != 0 || this->quad_indices_VBO_id != 0); @@ -879,7 +888,7 @@ int GLVolumeCollection::load_wipe_tower_preview( GLVolume& v = *volumes.back(); v.indexed_vertex_array.load_mesh(mesh); #if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS - v.calc_convex_hull_3d(); + v.set_convex_hull(mesh.convex_hull_3d()); #endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS v.indexed_vertex_array.finalize_geometry(opengl_initialized); v.set_volume_offset(Vec3d(pos_x, pos_y, 0.0)); @@ -1038,7 +1047,11 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type, bool disab glsafe(::glDisable(GL_BLEND)); } +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS +bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, ModelInstanceEPrintVolumeState* out_state, bool as_toolpaths) const +#else bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, ModelInstanceEPrintVolumeState* out_state) const +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS { if (config == nullptr) return false; @@ -1050,10 +1063,61 @@ bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, M #if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS const Polygon bed_poly = offset(Polygon::new_scale(opt->values), static_cast(scale_(BedEpsilon))).front(); const float bed_height = config->opt_float("max_print_height"); + const BoundingBox bed_box_2D = get_extents(bed_poly); + BoundingBoxf3 print_volume({ unscale(bed_box_2D.min.x()), unscale(bed_box_2D.min.y()), -1e10 }, + { unscale(bed_box_2D.max.x()), unscale(bed_box_2D.max.y()), bed_height }); + + auto check_against_rectangular_bed = [&print_volume](GLVolume& volume, ModelInstanceEPrintVolumeState& state) { + const BoundingBoxf3* const bb = volume.is_sinking() ? &volume.transformed_non_sinking_bounding_box() : &volume.transformed_convex_hull_bounding_box(); + volume.is_outside = !print_volume.contains(*bb); + if (volume.printable) { + if (state == ModelInstancePVS_Inside && volume.is_outside) + state = ModelInstancePVS_Fully_Outside; + if (state == ModelInstancePVS_Fully_Outside && volume.is_outside && print_volume.intersects(*bb)) + state = ModelInstancePVS_Partly_Outside; + } + }; + + auto check_against_circular_bed = [](GLVolume& volume, ModelInstanceEPrintVolumeState& state, const Vec2d& center, double radius) { + const TriangleMesh* mesh = volume.is_sinking() ? &GUI::wxGetApp().plater()->model().objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh() : volume.convex_hull(); + const Polygon volume_hull_2d = its_convex_hull_2d_above(mesh->its, volume.world_matrix().cast(), 0.0f); + size_t outside_count = 0; + const double sq_radius = sqr(radius); + for (const Point& p : volume_hull_2d.points) { + if (sq_radius < (unscale(p) - center).squaredNorm()) + ++outside_count; + } + + volume.is_outside = outside_count > 0; + if (volume.printable) { + if (state == ModelInstancePVS_Inside && volume.is_outside) + state = ModelInstancePVS_Fully_Outside; + if (state == ModelInstancePVS_Fully_Outside && volume.is_outside && outside_count < volume_hull_2d.size()) + state = ModelInstancePVS_Partly_Outside; + } + }; + + auto check_against_convex_bed = [&bed_poly, bed_height](GLVolume& volume, ModelInstanceEPrintVolumeState& state) { + const TriangleMesh* mesh = volume.is_sinking() ? &GUI::wxGetApp().plater()->model().objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh() : volume.convex_hull(); + const Polygon volume_hull_2d = its_convex_hull_2d_above(mesh->its, volume.world_matrix().cast(), 0.0f); + const BoundingBoxf3* const bb = volume.is_sinking() ? &volume.transformed_non_sinking_bounding_box() : &volume.transformed_convex_hull_bounding_box(); + ModelInstanceEPrintVolumeState volume_state = printbed_collision_state(bed_poly, bed_height, volume_hull_2d, bb->min.z(), bb->max.z()); + bool contained = (volume_state == ModelInstancePVS_Inside); + bool intersects = (volume_state == ModelInstancePVS_Partly_Outside); + + volume.is_outside = !contained; + if (volume.printable) { + if (state == ModelInstancePVS_Inside && volume.is_outside) + state = ModelInstancePVS_Fully_Outside; + + if (state == ModelInstancePVS_Fully_Outside && volume.is_outside && intersects) + state = ModelInstancePVS_Partly_Outside; + } + }; #else const BoundingBox bed_box_2D = get_extents(Polygon::new_scale(opt->values)); - BoundingBoxf3 print_volume({ unscale(bed_box_2D.min.x()), unscale(bed_box_2D.min.y()), 0.0 }, - { unscale(bed_box_2D.max.x()), unscale(bed_box_2D.max.y()), config->opt_float("max_print_height") }); + BoundingBoxf3 print_volume({ unscale(bed_box_2D.min.x()), unscale(bed_box_2D.min.y()), 0.0 }, + { unscale(bed_box_2D.max.x()), unscale(bed_box_2D.max.y()), config->opt_float("max_print_height") }); // Allow the objects to protrude below the print bed print_volume.min.z() = -1e10; print_volume.min.x() -= BedEpsilon; @@ -1063,36 +1127,33 @@ bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, M #endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS ModelInstanceEPrintVolumeState overall_state = ModelInstancePVS_Inside; - bool contained_min_one = false; for (GLVolume* volume : this->volumes) { +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + if (as_toolpaths && !volume->is_extrusion_path) + continue; + else if (!as_toolpaths && (volume->is_modifier || (!volume->shader_outside_printer_detection_enabled && (volume->is_wipe_tower || volume->composite_id.volume_id < 0)))) + continue; + + if (GUI::Bed3D::is_rectangle(opt->values)) + check_against_rectangular_bed(*volume, overall_state); + else { + Vec2d center; + double radius; + if (GUI::Bed3D::is_circle(opt->values, ¢er, &radius)) + check_against_circular_bed(*volume, overall_state, center, radius); + else if (GUI::Bed3D::is_convex(opt->values)) + check_against_convex_bed(*volume, overall_state); + } + + contained_min_one |= !volume->is_outside; +#else if (volume->is_modifier || (!volume->shader_outside_printer_detection_enabled && (volume->is_wipe_tower || volume->composite_id.volume_id < 0))) continue; -#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS - bool contained = false; - bool intersects = false; - bool is_aux_volume = volume->is_sla_support() || volume->is_sla_pad() || volume->is_wipe_tower; - const BoundingBoxf3 bb = is_aux_volume ? volume->transformed_convex_hull_bounding_box() : volume->transformed_non_sinking_bounding_box(); - ModelInstanceEPrintVolumeState volume_state; - if (is_aux_volume) { - if (volume->is_sla_support() || volume->is_wipe_tower) { - const Polygon volume_hull_2d = its_convex_hull_2d_above(volume->convex_hull()->its, volume->world_matrix().cast(), 0.0f); - volume_state = printbed_collision_state(bed_poly, bed_height, volume_hull_2d, bb.min.z(), bb.max.z()); - } - } - else { - const TriangleMesh* mesh = volume->is_sinking() ? &GUI::wxGetApp().plater()->model().objects[volume->object_idx()]->volumes[volume->volume_idx()]->mesh() : volume->convex_hull(); - const Polygon volume_hull_2d = its_convex_hull_2d_above(mesh->its, volume->world_matrix().cast(), 0.0f); - volume_state = printbed_collision_state(bed_poly, bed_height, volume_hull_2d, bb.min.z(), bb.max.z()); - } - contained = (volume_state == ModelInstancePVS_Inside); - intersects = (volume_state == ModelInstancePVS_Partly_Outside); -#else const BoundingBoxf3& bb = volume->transformed_convex_hull_bounding_box(); bool contained = print_volume.contains(bb); -#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS volume->is_outside = !contained; if (!volume->printable) @@ -1103,10 +1164,6 @@ bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, M if (overall_state == ModelInstancePVS_Inside && volume->is_outside) overall_state = ModelInstancePVS_Fully_Outside; -#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS - if (overall_state == ModelInstancePVS_Fully_Outside && volume->is_outside && intersects) - overall_state = ModelInstancePVS_Partly_Outside; -#else if (overall_state == ModelInstancePVS_Fully_Outside && volume->is_outside && print_volume.intersects(bb)) overall_state = ModelInstancePVS_Partly_Outside; #endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index 0b1293f56..14597f22a 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -654,7 +654,11 @@ public: // returns true if all the volumes are completely contained in the print volume // returns the containment state in the given out_state, if non-null +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + bool check_outside_state(const DynamicPrintConfig* config, ModelInstanceEPrintVolumeState* out_state, bool as_toolpaths = false) const; +#else bool check_outside_state(const DynamicPrintConfig* config, ModelInstanceEPrintVolumeState* out_state) const; +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS void reset_outside_state(); void update_colors_by_extruder(const DynamicPrintConfig* config); diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index fd2fe9cbc..00fa066c9 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -6,10 +6,11 @@ #include "libslic3r/Model.hpp" #include "libslic3r/Utils.hpp" #include "libslic3r/LocalesUtils.hpp" +#include "libslic3r/PresetBundle.hpp" + #include "GUI_App.hpp" #include "MainFrame.hpp" #include "Plater.hpp" -#include "libslic3r/PresetBundle.hpp" #include "Camera.hpp" #include "I18N.hpp" #include "GUI_Utils.hpp" @@ -19,6 +20,10 @@ #include "GLToolbar.hpp" #include "GUI_Preview.hpp" #include "GUI_ObjectManipulation.hpp" +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS +#include "3DBed.hpp" +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + #include #include @@ -674,6 +679,10 @@ void GCodeViewer::load(const GCodeProcessor::Result& gcode_result, const Print& if (wxGetApp().is_gcode_viewer()) m_custom_gcode_per_print_z = gcode_result.custom_gcode_per_print_z; +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + m_max_print_height = gcode_result.max_print_height; +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + load_toolpaths(gcode_result); if (m_layers.empty()) @@ -819,6 +828,9 @@ void GCodeViewer::reset() m_paths_bounding_box = BoundingBoxf3(); m_max_bounding_box = BoundingBoxf3(); +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + m_max_print_height = 0.0f; +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS m_tool_colors = std::vector(); m_extruders_count = 0; m_extruder_ids = std::vector(); @@ -835,6 +847,9 @@ void GCodeViewer::reset() #if ENABLE_GCODE_VIEWER_STATISTICS m_statistics.reset_all(); #endif // ENABLE_GCODE_VIEWER_STATISTICS +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + m_contained_in_bed = true; +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS } void GCodeViewer::render() @@ -1554,7 +1569,49 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result) // set approximate max bounding box (take in account also the tool marker) m_max_bounding_box = m_paths_bounding_box; - m_max_bounding_box.merge(m_paths_bounding_box.max + m_sequential_view.marker.get_bounding_box().size()[2] * Vec3d::UnitZ()); + m_max_bounding_box.merge(m_paths_bounding_box.max + m_sequential_view.marker.get_bounding_box().size().z() * Vec3d::UnitZ()); + +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + if (wxGetApp().is_editor()) { + const Bed3D::EShapeType bed_type = wxGetApp().plater()->get_bed().get_shape_type(); + if (bed_type == Bed3D::EShapeType::Rectangle) { + BoundingBoxf3 print_volume = wxGetApp().plater()->get_bed().get_bounding_box(false); + print_volume.min.z() = -1e10; + print_volume.max.z() = m_max_print_height; + print_volume.min -= Vec3f(BedEpsilon, BedEpsilon, 0.0f).cast(); + print_volume.max += Vec3f(BedEpsilon, BedEpsilon, 0.0f).cast(); + m_contained_in_bed = print_volume.contains(m_paths_bounding_box); + } + else if (bed_type == Bed3D::EShapeType::Circle) { + Vec2d center; + double radius; + Bed3D::is_circle(wxGetApp().plater()->get_bed().get_shape(), ¢er, &radius); + const double sq_radius = sqr(radius); + for (const GCodeProcessor::MoveVertex& move : gcode_result.moves) { + if (move.type == EMoveType::Extrude && move.extrusion_role != erCustom && move.width != 0.0f && move.height != 0.0f) { + if (sq_radius < (Vec2d(move.position.x(), move.position.y()) - center).squaredNorm()) { + m_contained_in_bed = false; + break; + } + } + } + } + else if (bed_type == Bed3D::EShapeType::Custom) { + const Pointfs& shape = wxGetApp().plater()->get_bed().get_shape(); + if (Bed3D::is_convex(shape)) { + const Polygon poly = Polygon::new_scale(shape); + for (const GCodeProcessor::MoveVertex& move : gcode_result.moves) { + if (move.type == EMoveType::Extrude && move.extrusion_role != erCustom && move.width != 0.0f && move.height != 0.0f) { + if (!poly.contains(Point::new_scale(Vec2d(move.position.x(), move.position.y())))) { + m_contained_in_bed = false; + break; + } + } + } + } + } + } +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS #if ENABLE_FIX_SEAMS_SYNCH m_sequential_view.gcode_ids.clear(); diff --git a/src/slic3r/GUI/GCodeViewer.hpp b/src/slic3r/GUI/GCodeViewer.hpp index 1b5a53f9d..66fcba2bc 100644 --- a/src/slic3r/GUI/GCodeViewer.hpp +++ b/src/slic3r/GUI/GCodeViewer.hpp @@ -780,6 +780,9 @@ private: BoundingBoxf3 m_paths_bounding_box; // bounding box of toolpaths + marker tools BoundingBoxf3 m_max_bounding_box; +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + float m_max_print_height{ 0.0f }; +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS std::vector m_tool_colors; Layers m_layers; std::array m_layers_z_range; @@ -804,6 +807,10 @@ private: std::vector m_custom_gcode_per_print_z; +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + bool m_contained_in_bed{ true }; +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + public: GCodeViewer(); ~GCodeViewer() { reset(); } @@ -832,6 +839,10 @@ public: const SequentialView& get_sequential_view() const { return m_sequential_view; } void update_sequential_view_current(unsigned int first, unsigned int last); +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + bool is_contained_in_bed() const { return m_contained_in_bed; } +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + EViewType get_view_type() const { return m_view_type; } void set_view_type(EViewType type) { if (type == EViewType::Count) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 2cc92f987..2d8c2f9bd 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1108,10 +1108,18 @@ void GLCanvas3D::reset_volumes() _set_warning_notification(EWarning::ObjectOutside, false); } +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS +ModelInstanceEPrintVolumeState GLCanvas3D::check_volumes_outside_state(bool as_toolpaths) const +#else ModelInstanceEPrintVolumeState GLCanvas3D::check_volumes_outside_state() const +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS { ModelInstanceEPrintVolumeState state; +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + m_volumes.check_outside_state(m_config, &state, as_toolpaths); +#else m_volumes.check_outside_state(m_config, &state); +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS return state; } @@ -5016,24 +5024,16 @@ void GLCanvas3D::_render_background() const if (!m_volumes.empty()) use_error_color &= _is_any_volume_outside(); - else { + else #if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS - ModelInstanceEPrintVolumeState state; - if (m_gcode_viewer.has_data()) { - const Polygon bed_poly = offset(Polygon::new_scale(wxGetApp().plater()->get_bed().get_shape()), static_cast(scale_(BedEpsilon))).front(); - const float bed_height = m_config->opt_float("max_print_height"); - state = printbed_collision_state(bed_poly, bed_height, m_gcode_viewer.get_paths_bounding_box()); - } - else - state = ModelInstancePVS_Inside; - - use_error_color &= state != ModelInstancePVS_Inside; + use_error_color &= m_gcode_viewer.has_data() && !m_gcode_viewer.is_contained_in_bed(); #else + { const BoundingBoxf3 test_volume = (m_config != nullptr) ? print_volume(*m_config) : BoundingBoxf3(); const BoundingBoxf3& paths_volume = m_gcode_viewer.get_paths_bounding_box(); use_error_color &= (test_volume.radius() > 0.0 && paths_volume.radius() > 0.0) ? !test_volume.contains(paths_volume) : false; -#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS } +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS } glsafe(::glPushMatrix()); @@ -6379,18 +6379,7 @@ void GLCanvas3D::_load_sla_shells() void GLCanvas3D::_update_toolpath_volumes_outside_state() { #if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS - const Polygon bed_poly = offset(Polygon::new_scale(wxGetApp().plater()->get_bed().get_shape()), static_cast(scale_(BedEpsilon))).front(); - const float bed_height = m_config->opt_float("max_print_height"); - for (GLVolume* volume : m_volumes.volumes) { - if (volume->is_extrusion_path) { - const BoundingBoxf3& bb = volume->transformed_convex_hull_bounding_box(); - const Polygon volume_hull_2d = its_convex_hull_2d_above(volume->convex_hull()->its, volume->world_matrix().cast(), 0.0f); - const ModelInstanceEPrintVolumeState state = printbed_collision_state(bed_poly, bed_height, volume_hull_2d, bb.min.z(), bb.max.z()); - volume->is_outside = (state != ModelInstancePVS_Inside); - } - else - volume->is_outside = false; - } + check_volumes_outside_state(true); #else BoundingBoxf3 test_volume = (m_config != nullptr) ? print_volume(*m_config) : BoundingBoxf3(); for (GLVolume* volume : m_volumes.volumes) { @@ -6402,18 +6391,7 @@ void GLCanvas3D::_update_toolpath_volumes_outside_state() void GLCanvas3D::_update_sla_shells_outside_state() { #if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS - const Polygon bed_poly = offset(Polygon::new_scale(wxGetApp().plater()->get_bed().get_shape()), static_cast(scale_(BedEpsilon))).front(); - const float bed_height = m_config->opt_float("max_print_height"); - for (GLVolume* volume : m_volumes.volumes) { - if (volume->shader_outside_printer_detection_enabled) { - const BoundingBoxf3& bb = volume->transformed_convex_hull_bounding_box(); - const Polygon volume_hull_2d = its_convex_hull_2d_above(volume->convex_hull()->its, volume->world_matrix().cast(), 0.0f); - const ModelInstanceEPrintVolumeState state = printbed_collision_state(bed_poly, bed_height, volume_hull_2d, bb.min.z(), bb.max.z()); - volume->is_outside = (state != ModelInstancePVS_Inside); - } - else - volume->is_outside = false; - } + check_volumes_outside_state(); #else BoundingBoxf3 test_volume = (m_config != nullptr) ? print_volume(*m_config) : BoundingBoxf3(); for (GLVolume* volume : m_volumes.volumes) { @@ -6431,12 +6409,8 @@ void GLCanvas3D::_set_warning_notification_if_needed(EWarning warning) else { if (wxGetApp().is_editor()) { #if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS - if (current_printer_technology() != ptSLA) { - const Polygon bed_poly = offset(Polygon::new_scale(wxGetApp().plater()->get_bed().get_shape()), static_cast(scale_(BedEpsilon))).front(); - const float bed_height = m_config->opt_float("max_print_height"); - const ModelInstanceEPrintVolumeState state = printbed_collision_state(bed_poly, bed_height, m_gcode_viewer.get_paths_bounding_box()); - show = state != ModelInstancePVS_Inside; - } + if (current_printer_technology() != ptSLA) + show = m_gcode_viewer.has_data() && !m_gcode_viewer.is_contained_in_bed(); #else BoundingBoxf3 test_volume = (m_config != nullptr) ? print_volume(*m_config) : BoundingBoxf3(); const BoundingBoxf3& paths_volume = m_gcode_viewer.get_paths_bounding_box(); @@ -6445,6 +6419,7 @@ void GLCanvas3D::_set_warning_notification_if_needed(EWarning warning) #endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS } } + _set_warning_notification(warning, show); } diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index beb33c89b..d3c24694c 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -621,7 +621,11 @@ public: unsigned int get_volumes_count() const; const GLVolumeCollection& get_volumes() const { return m_volumes; } void reset_volumes(); +#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + ModelInstanceEPrintVolumeState check_volumes_outside_state(bool as_toolpaths = false) const; +#else ModelInstanceEPrintVolumeState check_volumes_outside_state() const; +#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS #if ENABLE_SEAMS_USING_MODELS void init_gcode_viewer() { m_gcode_viewer.init(); } From c15be26bff17ed0354323f047ba56cb317d6c63b Mon Sep 17 00:00:00 2001 From: YuSanka Date: Thu, 7 Oct 2021 09:12:31 +0200 Subject: [PATCH 020/102] Check if object's size appears to be zero, when loading the model file. --- src/libslic3r/Model.cpp | 16 ++++++++++++++++ src/libslic3r/Model.hpp | 1 + src/slic3r/GUI/Plater.cpp | 8 ++++++++ 3 files changed, 25 insertions(+) diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 8659e6961..1ade36e36 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -513,6 +513,22 @@ void Model::convert_from_meters(bool only_small_volumes) } } +static constexpr const double zero_volume = 0.0000000001; + +int Model::removed_objects_with_zero_volume() +{ + if (objects.size() == 0) + return 0; + + int removed = 0; + for (int i = int(objects.size()) - 1; i >= 0; i--) + if (objects[i]->get_object_stl_stats().volume < zero_volume) { + delete_object(size_t(i)); + removed++; + } + return removed; +} + void Model::adjust_min_z() { if (objects.empty()) diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 6e0063f1b..11cbdc0cf 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -1124,6 +1124,7 @@ public: void convert_from_imperial_units(bool only_small_volumes); bool looks_like_saved_in_meters() const; void convert_from_meters(bool only_small_volumes); + int removed_objects_with_zero_volume(); // Ensures that the min z of the model is not negative void adjust_min_z(); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 68c20d497..0710c0916 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -2438,6 +2438,14 @@ std::vector Plater::priv::load_files(const std::vector& input_ }; if (!is_project_file) { + if (int deleted_objects = model.removed_objects_with_zero_volume(); deleted_objects > 0) { + MessageDialog(q, format_wxstr(_L_PLURAL( + "Object size from file %s appears to be zero.\n" + "This object has been removed from the model", + "Objects size from file %s appear to be zero.\n" + "These objects have been removed from the model", deleted_objects), from_path(filename)) + "\n", + _L("Object size is zero"), wxICON_INFORMATION | wxOK).ShowModal(); + } if (imperial_units) // Convert even if the object is big. convert_from_imperial_units(model, false); From 1b828ca7f5a70b81a6c35c6d5755879a01f09128 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Thu, 7 Oct 2021 10:14:55 +0200 Subject: [PATCH 021/102] Deleted unused PNG-files. Added mirroring_transparent.svg (thanks for @AkiraNorthstar) --- resources/icons/colorchange_add_off.png | Bin 600 -> 0 bytes resources/icons/colorchange_add_on.png | Bin 695 -> 0 bytes resources/icons/colorchange_delete_off.png | Bin 589 -> 0 bytes resources/icons/colorchange_delete_on.png | Bin 628 -> 0 bytes resources/icons/down_half_circle.png | Bin 631 -> 0 bytes resources/icons/left_half_circle.png | Bin 651 -> 0 bytes resources/icons/mirroring_transparent.png | Bin 93 -> 0 bytes resources/icons/mirroring_transparent.svg | 4 ++++ resources/icons/mode_advanced_.png | Bin 1466 -> 0 bytes resources/icons/mode_advanced_sq.png | Bin 158 -> 0 bytes resources/icons/mode_expert_.png | Bin 1379 -> 0 bytes resources/icons/mode_expert_sq.png | Bin 164 -> 0 bytes resources/icons/mode_simple_.png | Bin 1164 -> 0 bytes resources/icons/mode_simple_sq.png | Bin 158 -> 0 bytes resources/icons/one_layer_lock_off.png | Bin 1001 -> 0 bytes resources/icons/one_layer_lock_on.png | Bin 1106 -> 0 bytes resources/icons/one_layer_unlock_off.png | Bin 997 -> 0 bytes resources/icons/one_layer_unlock_on.png | Bin 1129 -> 0 bytes resources/icons/pause_add.png | Bin 5883 -> 0 bytes resources/icons/right_half_circle.png | Bin 654 -> 0 bytes resources/icons/row.png | Bin 1923 -> 0 bytes resources/icons/shape_ungroup.png | Bin 803 -> 0 bytes resources/icons/table.png | Bin 465 -> 0 bytes resources/icons/up_half_circle.png | Bin 650 -> 0 bytes resources/icons/variable_layer_height_reset.png | Bin 1050 -> 0 bytes .../icons/variable_layer_height_tooltip.png | Bin 10017 -> 0 bytes 26 files changed, 4 insertions(+) delete mode 100644 resources/icons/colorchange_add_off.png delete mode 100644 resources/icons/colorchange_add_on.png delete mode 100644 resources/icons/colorchange_delete_off.png delete mode 100644 resources/icons/colorchange_delete_on.png delete mode 100644 resources/icons/down_half_circle.png delete mode 100644 resources/icons/left_half_circle.png delete mode 100644 resources/icons/mirroring_transparent.png create mode 100644 resources/icons/mirroring_transparent.svg delete mode 100644 resources/icons/mode_advanced_.png delete mode 100644 resources/icons/mode_advanced_sq.png delete mode 100644 resources/icons/mode_expert_.png delete mode 100644 resources/icons/mode_expert_sq.png delete mode 100644 resources/icons/mode_simple_.png delete mode 100644 resources/icons/mode_simple_sq.png delete mode 100644 resources/icons/one_layer_lock_off.png delete mode 100644 resources/icons/one_layer_lock_on.png delete mode 100644 resources/icons/one_layer_unlock_off.png delete mode 100644 resources/icons/one_layer_unlock_on.png delete mode 100644 resources/icons/pause_add.png delete mode 100644 resources/icons/right_half_circle.png delete mode 100644 resources/icons/row.png delete mode 100644 resources/icons/shape_ungroup.png delete mode 100644 resources/icons/table.png delete mode 100644 resources/icons/up_half_circle.png delete mode 100644 resources/icons/variable_layer_height_reset.png delete mode 100644 resources/icons/variable_layer_height_tooltip.png diff --git a/resources/icons/colorchange_add_off.png b/resources/icons/colorchange_add_off.png deleted file mode 100644 index 6ddeccbe0a2a82019c5c2efd1773c20c0833c4d4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 600 zcmeAS@N?(olHy`uVBq!ia0vp^!XV7S3?yCqj{O5tEa{HEjtmSN`?>!lvI6-E$sR$z z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBC{YpM6XNqfL!5oT`ng2Uv7KO- z`>oK>c;wi#w-Y8-9OfwbtPfPmnB?v5!uX#__a2bLS>O>_%)p?h48n{ROYO^mg6t)p zzOL*KxFrR+#s37PM*)TAdb&7gOf=4WlTK;F^nd^Dc_ijpxxR1T zX#3n&TDl=r(%}>cpt3=meXk`S|u=mmKH$V*x Mp00i_>zopr04OBpdH?_b diff --git a/resources/icons/colorchange_add_on.png b/resources/icons/colorchange_add_on.png deleted file mode 100644 index cc800b81e8a6355877fa8cf58fee3731540f5dbb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 695 zcmeAS@N?(olHy`uVBq!ia0vp^!XV7S3?yCqj{O5tEa{HEjtmSN`?>!lvI6-E$sR$z z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBD6u8LC&cwX?ZDQK|Lu1F z3#9(1u>Ehd{lBC4e=5iS1cv`9?Ekm-{NK>{f7gWnt9$>~IQ`$*4|2u&`v2?e{dfTo%*MD>FcgxMz#tc&>wjKYvlkv2}>W3ZX<P)+_zJD`=!SuPm-m%Y^cA85^??v;%fYzs559euLSj6?CPDVv# z8OPo07q)BrukMjxdUaSr{b2Kv9pC;|`Sb4o|Mpw@uyeDVx zW$1|Bsj=8bi@Q>L-?mjR+Ky$nt-EqlSb4pc^PF5&HlSxzOI#yLQW8s2t&)pUffR$0 zfuWhMp`oskX^5ejm7%GXsj;?!p_PHb`H8EHQ8eV{r(~v8qH8d;GO~ndkeu{n5l{nz Mr>mdKI;Vst0C-YMUjP6A diff --git a/resources/icons/colorchange_delete_off.png b/resources/icons/colorchange_delete_off.png deleted file mode 100644 index c16655271a7e10d9d83047189086d4d6b509abc3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 589 zcmeAS@N?(olHy`uVBq!ia0vp^!XV7S0wixl{&NRXEa{HEjtmSN`?>!lvI6-E$sR$z z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBD8ZEE?e4>iGH4#PT$HOWYUVmw=D)W4<$2R?NV2M}KA?FdtNTmJp~!15S*|LT8;MoC zXsZ3%W24$-moh2c@9l*fmo+q>Gq62KSXA699k*xgMiDE{G|yhA4QhurtG<}@uu!C_ z<$>}m-=I62B~!k9UHS2l6URxP__|{b{!P~`Som^z%$(k+UE0pWDc5vL>wMPBh1~ac zOgPu;&>~>6W*@_Frwy&D=l0S8q@B+Qm*U`007}-kq7#>;Nm&p5M&yqHoBEQzy zY0CSzuP^(vnT8meSs9vI xnHp;w7+M(^oS(SL7)3*FeoAIqCAtPfD`O*whU@kljsZ0=c)I$ztaD0e0ssxu+3)}W diff --git a/resources/icons/colorchange_delete_on.png b/resources/icons/colorchange_delete_on.png deleted file mode 100644 index 8f27ce9fe684cca59295bd787f0c564f14a56a25..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 628 zcmeAS@N?(olHy`uVBq!ia0vp^!XV7S0wixl{&NRXEa{HEjtmSN`?>!lvI6-E$sR$z z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBD8ZEE?e4yA$Thpan!eyJ5ZE|lwT7;ffcnvE zS;w+UCtS;Nk}WE(*0icP_POSv<^KD{Mb$yQ(FI4REZ!IK`2_R)UyEa!cz3P+`04`t z{hZU%K_&mTt8UMEpM2aV&hod9dl<8x*4CJ9HxKi5&!3)Df4S#W*Q&b>yI22j=vX^V zN2n)Lr+H5h+lo`osZwf9*@ahFFK4ad3^C7@C^3O zPrjD~3a37HGZKiN!`D`B)H&;x+upMdZvr^>@ujWVCAfaBxAC{SdtoWHFMjlkyh{DG za*j&_)BC37>U<7=kI(V^<2moiw_|H`-C}#RDkiV9dRkkwNm};kgU!{O7tC!`5!kGA z^GE;ee@5|{S6i4p0)jJVZr^=>`yT6c`+I)XS|^=q?fadV_WRo97S>|Fv|GC`%Kv5L zl`d>pzF+$gFcwrxTq8h@qL4p{bRrv9^Jsm4U(e niK~oJH00)|WTsW3YcRAjHic*qn$hP0)WG2B>gTe~DWM4f)HnL< diff --git a/resources/icons/down_half_circle.png b/resources/icons/down_half_circle.png deleted file mode 100644 index f86a2932c1da84cc5e4b9214b26e04a49542af73..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 631 zcmV--0*L*IP)5rH9Dk4UMwL=F#Vj*HNvx$E|B9UM+u!@1iBF%Gd+oU3TUe39n_r2$wci*{SUruWo zvta--*}M@BO?a0hE8eCToOFu!(G}H9eSCg?mb&)!fK9FUeX3Xeynn4_J#K1Xa|(}X zx{(*25}w=2>x%bVl8E4 zgolNFne?VsJ&*bmS3JA4pmgyLOu~eiz{@m~1PL(6sKkIw$4|e!QK#NtuAd_(wVFho zZ45R@k|Iy9sGHI~E^9*cxIAge5L0*XceZ9?$Y1$_YX%x$E$g!fnvS5fXIbATmQ^|h zhs@=sSgX$!VdP!(LQV4>gL@Y)uWMTD46X{${;WrhXjyWI+Y<@+IEU5=j6wYYx57>K1)u*YSQLCnrxtjJS&=pv;pY$dTN+FA5|tC)r3t?7 z#8at`%Ao_oMjA?6ya>;Tn{PLl>!_?;FXgL84|*7&kEh?!9t+H*c~lM;a|SCBFkA-% R>c#*7002ovPDHLkV1nhP51#-4 diff --git a/resources/icons/left_half_circle.png b/resources/icons/left_half_circle.png deleted file mode 100644 index 3bdc4c3eefbecd5a7625dbb118f1ef39e879fbd4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 651 zcmV;60(AX}P)5rH9Dk4UMwL=F#Vj*HNvx$E|B9UM+u!@1iBF%Gd+oU3TUe39n_r2$wci*{SUruWo zvta--*}M@BO?a0hE8eCToOFu!(G}H9eSCg?mb&)!fK9FUeX3Xeynn4_J#K1Xa|(}X zx{(*25}w=2>x%bVl8E4 zgolNFne?VsJ&*bmS3JA4pmgyLOu~eiz{@m~1PL(6sKkIw$4|e!QK#NtuAd_(wVFho zZ45R@k|Iy9sGHI~E^9*cxIAge5L0*XceZ9?$Y1$_YX%x$E$g!fnvS5fXIbATmQ^|h zhs@=sSgX$!VdP!(LQV4>gL@Y)uWMTD46X{${;WrhXjyWI+Y<@+IEU5~(?C#d28Jphg%k%)>W?G;E`!6C3*rXk@BgrEk| zC2Z1#9sA$R&xCq%AyoPp2~$ikEFqVA3Iky-%!J3wVwnq}G*I{y-teF?rAoiv{1-y6 z?wqxSe;`boooyE;x55h;-UlJOF8p?ZZ5LQe$J-$7u)?Vo#Frz!r40^k6@(o=q#tR| l^|NT|eD|dAf>(_3d + + + \ No newline at end of file diff --git a/resources/icons/mode_advanced_.png b/resources/icons/mode_advanced_.png deleted file mode 100644 index d98d8f7091d0fcebd33a354a11feb8cd0a08f5bf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1466 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 diff --git a/resources/icons/mode_expert_sq.png b/resources/icons/mode_expert_sq.png deleted file mode 100644 index 742ffc08891d60c465c4cba7bf33cbf207579870..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 164 zcmeAS@N?(olHy`uVBq!ia0vp^96&6jA5L~c#`DCC7XMsm# zF$0582?#UZOOvkv3bL1Y`ns||X5`{9kU8CJ7y}eC^mK6y(Kw%+AW?B($K2kx`_HY9 z=ZP`W;*p!0fTkU4d1!`vSboFyt=akR{ E05GC4r2qf` diff --git a/resources/icons/mode_simple_.png b/resources/icons/mode_simple_.png deleted file mode 100644 index aac2b61b042094981b9e8f37da32662fb48b8c5c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1164 zcmV;71atd|P) zaB^>EX>4U6ba`-PAZ2)IW&i+q+O3vrlEfwqg#YUlIRX+0!EwMqRc?^ur?Hv0vx#Rj z)Y^=UCAq&gv(*3kbI>37h~q#(EyWz8!zbjBrC^fW@j1@y!hU>?&F?R9;;=3tt@Akh z<7@0|eL-9wH`rRw^)*hmtvqQZx>a5Y{j4mQtaWK6@^Zv)jZj|qmGIR1`pa!^-tk)W z{yiAPXo`GZNV;e5aE!BxM+ZLnGGjQ37jbJIyzTLLt{ojRe~NdXy=mvliu+e7$lVgf zH;q=D^<2AMp%-e8$}bnTbT9Ft-54#6(T}GqAwsE0>!EIsvd^%vLQ22i7BLKein;A0 zVNzJ?)!P;4J`)gVmOOz;`dncCRw%}N|=L(n9sfu7>VCN z%_A)LUU;vY_j(&ARBnuw!brxG=KG+t;5Xx*XpCuHW|t0~U<>pm)6-~UlAA}Y0uUZc zQ{DC52R-@5J%RNgsJqMw4_I71QdH%KxBSl8W1YG{hv^+#TL~Z$YAc#y4+1W-SB~sV z#F(LD0-u7;#RsV%z^c-i2H1EX0Vm0-B zUIVFWRMVtcOY|{BjWJrBdsH!R!PKIeCCgTlPa$cF$x=!=l`Pp~3)394QBFDMQc$!Y zb-~>QD@v(SeGOG>tX5OawQR7@7B=1DW?S0wR+=>5@cOsdj9O~BmChYj>Y;0o-FoV| zmjSO0Kf=%vhmADyD0gbSUfUOH{6_9)YP_gTVqsrr4{8XT-BR$}PINK@F$oOfHVMGc zGMTx=A;=^*nYk=@DO5m>b;4;piGg6~EIRnk?m_NHZlvK7H~A-WG|~MZRWtds8cwV;;SRF>2M3%U0w3fzW{81y@op*u0!Z zpoyd634F=KwfBr`$w_W);Jq%5@A=GTKAZWpS4$mRT9E`5us+S1TW546KlbCLC0DbG z>uHLZ@mtH9;DOZv_Uzde;ToE-m(s}m)?4cyJLOS(uHR=*=gM>|4%e<6kM07r`4?&K z%FvSLJ7J!5p-*A<-u|mJcV*~9nk&LQL7`vB@?seJl`v1b&~?Y08-}hs=G-v!wKQ*r zpx?|1_L)RU1ZW#Jnm^Z`Fcd~pMhORs2+%Ry9}$3|)83 zxnbzKW6ljj*Bx_i7`pD5bHmVe$DA96t~=)3Fm&B9=Z2x{jyX3BU3bijVLblP$@DkZ z+afZyIfuyr000JJOGiWi{{a60|De66lK=n!32;bRa{vGmbN~PnbOGLGA9w%&00(qQ zO+^Rd3Kj@25=Sf;RsaA1DoI2^R4C75oO43_zpx}T0~;$d!>`|e8Qwns%YY1+7zlt- e1)~b6s{jD4<_My71_K=c0000jA5L~c#`DCC7XMsm# zF$0582?#UZOOvkv3bL1Y`ns||X5`|qGM=^hNk7N{PZ!4!jq}L~5)}t5p11s{PxMS< wGYd;=i{Jm>Xix1waaTrRMd7ygrh^O&r^`9I`v3VK2Wn&RboFyt=akR{00Jy79RL6T diff --git a/resources/icons/one_layer_lock_off.png b/resources/icons/one_layer_lock_off.png deleted file mode 100644 index f6e61d058cd6b9d384d80e95b5689b4a8658b1ee..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1001 zcmV5rH9Dk4UMwL=F#Vj*HNvx$E|B9UM+u!@1iBF%Gd+oU3TUe39n_r2$wci*{SUruWo zvta--*}M@BO?a0hE8eCToOFu!(G}H9eSCg?mb&)!fK9FUeX3Xeynn4_J#K1Xa|(}X zx{(*25}w=2>x%bVl8E4 zgolNFne?VsJ&*bmS3JA4pmgyLOu~eiz{@m~1PL(6sKkIw$4|e!QK#NtuAd_(wVFho zZ45R@k|Iy9sGHI~E^9*cxIAge5L0*XceZ9?$Y1$_YX%x$E$g!fnvS5fXIbATmQ^|h zhs@=sSgX$!VdP!(LQV4>gL@Y)uWMTD46X{${;WrhXjyWI+Y<@+IEU5ue@z1?;r=>zE+9su?6S43Tu_%p%zkrHJM37X(%2tFBm55l0#9uH8 zk&slPTRRD1!J@H|CQ>ieqOa;@w9{UTJ7(rih~MU%Joov1&v~A6?g`W=?$w5aIDj4V zVO?`}ac&r|Fo1y|?^CrWs4{190+-QI3$M~pDd%307ndO=z(w?_YoPlWdry(cGX0Td zO=OqyqMt{%D9jdd9yf!$#i&F-iA$h4$G+2y4=0AP*EF`$b%fk*p5CS~8{ry0;9eB> zT8-<-fcj;`F+)#y`;xgI%zk0XavD}vcc30O;$DwKY(-PK;^|SojWhW^0sPVAduB$H z@+xY>p$MB(ZEM>?7$s$Oc2S&DF0-+fj-9-DUhU|K(2|1m^s%~~ruFPPN|>SeD;XPB zC6H@-svX-S)TJPuUCG$k%Gb|KjU><&rM1>>Or;lts3pYDR5Xq&^JjOtbB3pPDzU5rH9Dk4UMwL=F#Vj*HNvx$E|B9UM+u!@1iBF%Gd+oU3TUe39n_r2$wci*{SUruWo zvta--*}M@BO?a0hE8eCToOFu!(G}H9eSCg?mb&)!fK9FUeX3Xeynn4_J#K1Xa|(}X zx{(*25}w=2>x%bVl8E4 zgolNFne?VsJ&*bmS3JA4pmgyLOu~eiz{@m~1PL(6sKkIw$4|e!QK#NtuAd_(wVFho zZ45R@k|Iy9sGHI~E^9*cxIAge5L0*XceZ9?$Y1$_YX%x$E$g!fnvS5fXIbATmQ^|h zhs@=sSgX$!VdP!(LQV4>gL@Y)uWMTD46X{${;WrhXjyWI+Y<@+IEU54V+L&fRh&|M+UcJ7qZ*PhJ7U$-tVgrXW%>3tn&I~gHn?zEwB(J2m zlE!4@m!xJ%rII|GW2|+-k-&MNinjW6x|?9I8$t`PBOa17A-5QcO8bB+pwY4{t&xNY zDrtXIP5WcmeGm#SgDVn(BM{?;$Y|(%0sWnD<@E}14Y+Gr*6Kf!GT;Ff9v875xbzSv z`l0ncjP^oYBIKWev}}0lHRN^QL%;>gvKsAhjR18Sa*8u~cU~U|SzCh0_ zm>4jh5Bz}JN27o{l9FuT2rakV40fC11pP2S0aHHsz35bL$_F!klO90tduXdq22R*O z9-mtraPlFrBOqZfWaL9yjyW0mCav^52ix@$pdvH`*rgc&j}6Qd<6hrwj{fl( zG{>0$V@ytO|y3!ujay2w86I4sN26ZXP^B1p+} zY_`kMbBh6*kmQjxsj3|5BGT%r)+F##>g$lEe2y)&U~sjCk~AbKDO?7XNm`NDZ35>f zrJ!G$8I@)OMi2U>xp8Uan{+i@l9nW$1&9cL>AFhlPnk~rpX@7ulQjT0fakDr zilZ=7e4W;N>2x=nc3+%-Ncrq&Jevx7sIv Y0T%OASmVe+!2kdN07*qoM6N<$g0ThsfdBvi diff --git a/resources/icons/one_layer_unlock_off.png b/resources/icons/one_layer_unlock_off.png deleted file mode 100644 index 46fabfb0501592fb64bb87d32eaa658fc455941a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 997 zcmV5rH9Dk4UMwL=F#Vj*HNvx$E|B9UM+u!@1iBF%Gd+oU3TUe39n_r2$wci*{SUruWo zvta--*}M@BO?a0hE8eCToOFu!(G}H9eSCg?mb&)!fK9FUeX3Xeynn4_J#K1Xa|(}X zx{(*25}w=2>x%bVl8E4 zgolNFne?VsJ&*bmS3JA4pmgyLOu~eiz{@m~1PL(6sKkIw$4|e!QK#NtuAd_(wVFho zZ45R@k|Iy9sGHI~E^9*cxIAge5L0*XceZ9?$Y1$_YX%x$E$g!fnvS5fXIbATmQ^|h zhs@=sSgX$!VdP!(LQV4>gL@Y)uWMTD46X{${;WrhXjyWI+Y<@+IEU5?kFhlSJFEMxp0StFCt(VK?^-86Z<~th; zh-YSIOixd%)oOwuFfcG+YirBK#)dRavqX73$9F6SNs^4>3x?+B=k4t5SYKZk1cBMv zS;ND_*4Eb4>-E27wU1kQ%wY)5&(9qk9Dp=U?d|Ppx7%8+)@7xQ;eH-dUC;6Hu{2GE zVW_XKPZUK8g@P!GgkdNM0_}ENqtVC`-Ob~A*IHd&Rj=2TN+ol1bBe{H{{DWGlao$P zPNZq7*=$-`TFR14QHb#_Kqa+hnAmi;kW=z-`>{TTgyq6CbeDt0%tzFTJ+D THHORC00000NkvXXu0mjfwn)tq diff --git a/resources/icons/one_layer_unlock_on.png b/resources/icons/one_layer_unlock_on.png deleted file mode 100644 index 265b926101933cce7995dccd8e0220bd8a862eea..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1129 zcmV-v1eW`WP)5rH9Dk4UMwL=F#Vj*HNvx$E|B9UM+u!@1iBF%Gd+oU3TUe39n_r2$wci*{SUruWo zvta--*}M@BO?a0hE8eCToOFu!(G}H9eSCg?mb&)!fK9FUeX3Xeynn4_J#K1Xa|(}X zx{(*25}w=2>x%bVl8E4 zgolNFne?VsJ&*bmS3JA4pmgyLOu~eiz{@m~1PL(6sKkIw$4|e!QK#NtuAd_(wVFho zZ45R@k|Iy9sGHI~E^9*cxIAge5L0*XceZ9?$Y1$_YX%x$E$g!fnvS5fXIbATmQ^|h zhs@=sSgX$!VdP!(LQV4>gL@Y)uWMTD46X{${;WrhXjyWI+Y<@+IEU5&TVWK2pYO(ypL_8q%8fK)8q|Ow1xeaP3gYBe=pIUk7HWmAg_izoo$S`h zp<^x7pr47`OZ1K?}1Aak%)*q6_M{E zV#}F+ipVz+c_bp?%Qfmku@^`Iuk!hP)UqsW+osWI5DW$}O_Q;)F(xM`E#MWfq?D32 zzaYioFTm{cm&0-gi!l~SiJvTd8w(^E>NlDi{{#UiCriB_w1WvpVcNIsvB0QWWEj%8T@RI61) z1dqpquIm_vf!FKBFbsmhAiA#O_xszRot+(kdtJcIa=8pZHk+kZs}YOENG6l`d_Htt zXJTT4sWBT zUIz$kKs68ubj<5Q0k*cbNT<`-w%s1tmCxq`ur**W6bfBgoGXvVgV*bI3p!+)Ccuv_ zAU8TX%I@xN`%$U3k%>m5^!D~*7zO~ErnTSV@i@R&4aiPSP5lms|3<=b92$)V)oK;P zFo;AVIF7^7(GitO1vv9bGMU^1zH~TtVPU~@a&q#|(OmWP^e{g^?*I>#QlH%3J_7G% zW@Z>19Q-d}XlRJ(>1lvBz-Q=8v5&J9zs%)wQOmL@m&-VgLm&{qG)?01IEh5U0^V|# v;;U9Zhebr>nTTXA+>>7-k`|FC*WHsp>Q69+U?zjU00000NkvXXu0mjf%y$mq diff --git a/resources/icons/pause_add.png b/resources/icons/pause_add.png deleted file mode 100644 index afe881de8bbea4b942cc0e9ae35bfba53c9dc057..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5883 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 S?=bzFkEE)orBEYh5&nO)^r2<| diff --git a/resources/icons/right_half_circle.png b/resources/icons/right_half_circle.png deleted file mode 100644 index ecc8980b3286942886d30c3a170691e848adc9df..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 654 zcmV;90&)F`P)5rH9Dk4UMwL=F#Vj*HNvx$E|B9UM+u!@1iBF%Gd+oU3TUe39n_r2$wci*{SUruWo zvta--*}M@BO?a0hE8eCToOFu!(G}H9eSCg?mb&)!fK9FUeX3Xeynn4_J#K1Xa|(}X zx{(*25}w=2>x%bVl8E4 zgolNFne?VsJ&*bmS3JA4pmgyLOu~eiz{@m~1PL(6sKkIw$4|e!QK#NtuAd_(wVFho zZ45R@k|Iy9sGHI~E^9*cxIAge5L0*XceZ9?$Y1$_YX%x$E$g!fnvS5fXIbATmQ^|h zhs@=sSgX$!VdP!(LQV4>gL@Y)uWMTD46X{${;WrhXjyWI+Y<@+IEU5-#MTcL~B zeAB7|aE})aPj!IsfKELi@O%kC`x>bH;07*qoM6N<$g1VU`!2kdN diff --git a/resources/icons/row.png b/resources/icons/row.png deleted file mode 100644 index 18a6034fd597baffa886ed65145183a5627310d5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1923 zcmV-}2YmR6P) zaB^>EX>4U6ba`-PAZ2)IW&i+q+SONCmh2`B{bv2UMA8^>9>^_xpz(Zwiv zHGSLq3H|aI5Zvz1_kI(~wxin+U54kwW9Cucdb$m`J;B*OTejJ4{I%@@ zf>8zb*c#iI_`uhXSr{I0`E;)}#d9y*CP-YE^8KLAk%;OFC3F=|K z5w8Mb0b>(YG>U3={5Vr{c}XN_K%`<^x0tPRH8)C&*R&>g~Qf<`)#!5J8{j=*>r z3}8Xq!P%kYoE^*!&W>oYDa3*`l0i~Wj#K!Y^M|GRS;c!vrK}pckmGR4kTeUIs5#m$l@Jfwcz(V#zdB%*-p;@{ z&0L$;Nq;}I3(mEZ$j$}FlujvxM;AT$`>r%UQuwY!nm(5in*!(hIsNi&ud3RXZ)pp$ zSG2QV!WNGn>(dHd>xiq}wqoX{+DVpvQ7++aLD#g6OX>b-w4wFj`cYopZmnHz27ov& z5EDbYVJOR^3q<=2g57eW1;#aGgHH#V8;toH4K8`Jl}d&3@=}pfYw|Zxy9G?+ zsK^?gJuWRdZ^M>r;TGyMwx;$WbzHnR+oX2uy5DFDarF!UONb2Jf_vlM#f{w;Bs8QE z+5XuPwKw%8geQmw^0j~X#Wyz1pz{?)dT67m@{lr6*c*tjg=V1mlmY3}l6LO{%-17B z-RS~5Z{`bWI1M~?$8|MV7PDs-OD04cvU^A~ZUHMPBAWzlulxR?oMS80WF^jEN+huL zrk<8h(j|rBsl?qxB1`(FEp_E1tdZCxcFuPg?hb=b7$G7r2DyY7ZOt=`a3**ihxJbI z9tZqVy5MX8VWE+}=pQ=-$N7Y_OZi@ z=tF5w2o#apMis&FL3ii|c!_OOF@z@JT9LNYQDc2QFIw3yVCUxp#&_7Q3pMKNafE2* zJDmIk=j||hL$Obh31bl6A21yL`M$%Dhfx36arDtpD7D^Vd@h<53F|1d^8f$=eMv+?R5;6}lfP>eaS+8nyPOg{@Cs48h+uV9gzJ*R ze?TEk3T?&Uk3t2p5eq?xjgf;uuCc!qDe^a@NFkU)61#ALG>U?O&gG~L@2O~EF6Js96?B2zL=jM9-h43{auge5rD+;k#$uJ=f*m}I4TM;NkL?DUCb0n2FpujP_3yERzEr4X!YfPEZ{sG~-EP|Z%oVWl0002ov JPDHLkV1lKIrrrPm diff --git a/resources/icons/shape_ungroup.png b/resources/icons/shape_ungroup.png deleted file mode 100644 index 97aaceb23d4f899af7d44f31934bfd3418e0b04d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 803 zcmV+;1Kj+HP)004R>004l5008;`004mK004C`008P>0026e000+ooVrmw0004x zP)t-s|NsAqiHV1Yhj@5+adB~mhK65XUqV7cI5;>bCns=la9>|vRaI3pGcyMV2O}dR zA0HnY8X5!y1ONa4h=_=Db90G_iPO{5goK2y%k`|t^{dGBsm1lD#r1D*Z^_BYXJ==F zgM*BbnZVWezSZ}=)Azg5_qx&deS?i-V`Hqz^}p5kzSQ@;)Azd4_qfsbx6t>s&i9+X z^@E3vadB~Vd48|P>$J}Iv(5LJyYoFgJz`>FgsIntujPfT72UgnYiagOH?c@ENg3Pc6)<}ujQh^>!7~sp1kOr zy6Bj<=9RSNlCk7$mfFU~#$8=qn!NL$zUrO3=$g3bm$v4Vv*nSo`&BV;i&CJcs;?~Xn$GgOfc=y%-0004EOGiWihy@);0002NNkllm#LnCN3cC$9hzU{zF7R#8<`*U)5x>e15H(bdy8Ff@W0BCTp{Vrph? zVadR5#Q_qKQInImwz0LdcW`ua1_`+6ySll1czSvJ`1)}I`CR@1=7B-MA)#U65s@GT z3Q^H9cCm5s35iL`DIfvvR33&jZ=dvx%&hDjm_@lj<$3u9g+)+4Z*fUda%ow4MI|3Z zpsKp2wl1frzM-)RBET;o2&RRag)u!30LOeLiBJkwz5oCK8FWQhbW?9;ba!ELWdK2B hZ(?O2No`?gWm08fWO;GPWjp`?002ovPDHLkV1nO6dG!DQ diff --git a/resources/icons/table.png b/resources/icons/table.png deleted file mode 100644 index 3bc0bd32fceb21d70368f7842a00a53d6369ba48..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 465 zcmV;?0WSWDP)zJNu3H-P zO&@UpeyZQXi7jKe-Hk?r-sue;aDce_XqkvXP+W#F_*ot`jB?BS93Uw71|U^ZjLH`yP%FO7U<6!nLCG} z$SDlW5rH9Dk4UMwL=F#Vj*HNvx$E|B9UM+u!@1iBF%Gd+oU3TUe39n_r2$wci*{SUruWo zvta--*}M@BO?a0hE8eCToOFu!(G}H9eSCg?mb&)!fK9FUeX3Xeynn4_J#K1Xa|(}X zx{(*25}w=2>x%bVl8E4 zgolNFne?VsJ&*bmS3JA4pmgyLOu~eiz{@m~1PL(6sKkIw$4|e!QK#NtuAd_(wVFho zZ45R@k|Iy9sGHI~E^9*cxIAge5L0*XceZ9?$Y1$_YX%x$E$g!fnvS5fXIbATmQ^|h zhs@=sSgX$!VdP!(LQV4>gL@Y)uWMTD46X{${;WrhXjyWI+Y<@+IEU5z>% diff --git a/resources/icons/variable_layer_height_reset.png b/resources/icons/variable_layer_height_reset.png deleted file mode 100644 index 6e051fe95104027f06f524c7e60e090dcdc05bce..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1050 zcmV+#1m*jQP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!~g&e!~vBn4jTXf1FuO$K~z{r?U>7J z6Hye#zf5A2rb(MV6k01dMRcY*JQ}3Bi`bxVCE#POqs!t-;76OIta?#Gyc|1#~*RY&!*OSs9OVC$B&p8 z9K_8JeTcG5ZvZy9LJW*zNqf=3qkmF1R|w3zxL?W%W}1K)uDdb&?Hi&aBM=JpQ0esu z9y*Mt`S}^wNL0$o`*$%Djq)sI>b~s*ELN(exYDaCwW6ezPsBoSB@(mc z#peA^Ghp{fu~0HeR^k%NTBlaC@#7~MyLg$g);7kDwK8`80vp-0muUqdV@|4VjBb+A zjirpK#1q$acvHs&LQG)vD2%AE5c4v6;6yy`oO$u_ytop}R!m$qblRu|YN}L0n4JY^ zn~7Fy)Tp7}qf}<6pRcMPjXkuj_I1YsHW#|=VYsjGF)7e_6+Uw#jwBY@j^^~8rzmgn zQUqp0NeP}dHbG521`&c%RYk6pz-TEJ*t!k13gIMrjKfEeE~PbJGo1eUTf##qxB{K9 z)VpEv#A2yiB1hgYN*0U+WnU9C1VwDLQ`AqsK7WScU=S01AD}BMg|@U5Pd08st$3^} zRreLR!*+C~JfIH_-k6iNpfkY3A{=SXfe=+*vTw`e{ep6Wk)YV)P>L`$Fo21nAyhwl zfK`Df80+uHkKT9CSCpfW-eVrETaR_i3V61h0_eOtuWACf(6azkHoeB1F#oDFFQv)L zD<_!c1qEQyIch~wf-;2hPXy)hL+SJpUGqGM?*si9d)o^^5TGJgkQJ-@Hm!BMZxAR; zJ$f4BJ%~Hxiak(=ciy}o&X5DK_9T-hUU91jVY3r{n*VL5()O})Hr8~I4e!{Q@$}KE zRIG2UnSI&3h1s;a1@R^9jFTyDFqv{5$s(M83<}HtgO^2%XbAt8@?f$k4<@64pX?TS U6@jyFr~m)}07*qoM6N<$f;Z&d_5c6? diff --git a/resources/icons/variable_layer_height_tooltip.png b/resources/icons/variable_layer_height_tooltip.png deleted file mode 100644 index 18200529278f5b24de50c01de9121a884db25052..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10017 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 From 34f5dde024839adecb919e07aef5edfb5dd63a07 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Thu, 7 Oct 2021 10:37:49 +0200 Subject: [PATCH 022/102] #6380 - Fixed non-uniform scaling of a volume using the sidebar fields --- src/slic3r/GUI/GUI_ObjectManipulation.cpp | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp index b8c053f88..d5a1a5659 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp @@ -547,8 +547,8 @@ void ObjectManipulation::update_settings_value(const Selection& selection) } else { m_new_rotation = volume->get_instance_rotation() * (180. / M_PI); - m_new_size = volume->get_instance_transformation().get_scaling_factor().cwiseProduct(wxGetApp().model().objects[volume->object_idx()]->raw_mesh_bounding_box().size()); - m_new_scale = volume->get_instance_scaling_factor() * 100.; + m_new_size = volume->get_instance_scaling_factor().cwiseProduct(wxGetApp().model().objects[volume->object_idx()]->raw_mesh_bounding_box().size()); + m_new_scale = volume->get_instance_scaling_factor() * 100.; } m_new_enabled = true; @@ -569,7 +569,7 @@ void ObjectManipulation::update_settings_value(const Selection& selection) m_new_position = volume->get_volume_offset(); m_new_rotation = volume->get_volume_rotation() * (180. / M_PI); m_new_scale = volume->get_volume_scaling_factor() * 100.; - m_new_size = volume->get_instance_transformation().get_scaling_factor().cwiseProduct(volume->get_volume_transformation().get_scaling_factor().cwiseProduct(volume->bounding_box().size())); + m_new_size = volume->get_instance_scaling_factor().cwiseProduct(volume->get_volume_scaling_factor().cwiseProduct(volume->bounding_box().size())); m_new_enabled = true; } else if (obj_list->multiple_selection() || obj_list->is_selected(itInstanceRoot)) { @@ -861,7 +861,7 @@ void ObjectManipulation::change_scale_value(int axis, double value) Vec3d scale = m_cache.scale; scale(axis) = value; - this->do_scale(axis, scale); + this->do_scale(axis, 0.01 * scale); m_cache.scale = scale; m_cache.scale_rounded(axis) = DBL_MAX; @@ -880,14 +880,21 @@ void ObjectManipulation::change_size_value(int axis, double value) const Selection& selection = wxGetApp().plater()->canvas3D()->get_selection(); Vec3d ref_size = m_cache.size; - if (selection.is_single_volume() || selection.is_single_modifier()) - ref_size = selection.get_volume(*selection.get_volume_idxs().begin())->bounding_box().size(); + if (selection.is_single_volume() || selection.is_single_modifier()) { + const GLVolume* v = selection.get_volume(*selection.get_volume_idxs().begin()); + const Vec3d local_size = size.cwiseQuotient(v->get_instance_scaling_factor()); + const Vec3d local_ref_size = v->bounding_box().size().cwiseProduct(v->get_volume_scaling_factor()); + const Vec3d local_change = local_size.cwiseQuotient(local_ref_size); + + size = local_change.cwiseProduct(v->get_volume_scaling_factor()); + ref_size = Vec3d::Ones(); + } else if (selection.is_single_full_instance()) ref_size = m_world_coordinates ? selection.get_unscaled_instance_bounding_box().size() : wxGetApp().model().objects[selection.get_volume(*selection.get_volume_idxs().begin())->object_idx()]->raw_mesh_bounding_box().size(); - this->do_scale(axis, 100. * Vec3d(size(0) / ref_size(0), size(1) / ref_size(1), size(2) / ref_size(2))); + this->do_scale(axis, size.cwiseQuotient(ref_size)); m_cache.size = size; m_cache.size_rounded(axis) = DBL_MAX; @@ -910,7 +917,7 @@ void ObjectManipulation::do_scale(int axis, const Vec3d &scale) const scaling_factor = scale(axis) * Vec3d::Ones(); selection.start_dragging(); - selection.scale(scaling_factor * 0.01, transformation_type); + selection.scale(scaling_factor, transformation_type); wxGetApp().plater()->canvas3D()->do_scale(L("Set Scale")); } From 68fd37b300e18052a5b445080dac721f26da05ee Mon Sep 17 00:00:00 2001 From: YuSanka Date: Thu, 7 Oct 2021 11:49:34 +0200 Subject: [PATCH 023/102] Added SVG-file for G-CodeViewer logo --- resources/icons/PrusaSlicer-gcodeviewer.svg | 73 +++++++++++++++++++ ...{prusa_slicer_logo.svg => PrusaSlicer.svg} | 0 src/slic3r/GUI/AboutDialog.cpp | 2 +- src/slic3r/GUI/GUI_App.cpp | 4 +- src/slic3r/GUI/GUI_App.hpp | 1 + src/slic3r/GUI/KBShortcutsDialog.cpp | 2 +- src/slic3r/GUI/SysInfoDialog.cpp | 2 +- 7 files changed, 79 insertions(+), 5 deletions(-) create mode 100644 resources/icons/PrusaSlicer-gcodeviewer.svg rename resources/icons/{prusa_slicer_logo.svg => PrusaSlicer.svg} (100%) diff --git a/resources/icons/PrusaSlicer-gcodeviewer.svg b/resources/icons/PrusaSlicer-gcodeviewer.svg new file mode 100644 index 000000000..6312beee3 --- /dev/null +++ b/resources/icons/PrusaSlicer-gcodeviewer.svg @@ -0,0 +1,73 @@ + + + + + + + diff --git a/resources/icons/prusa_slicer_logo.svg b/resources/icons/PrusaSlicer.svg similarity index 100% rename from resources/icons/prusa_slicer_logo.svg rename to resources/icons/PrusaSlicer.svg diff --git a/src/slic3r/GUI/AboutDialog.cpp b/src/slic3r/GUI/AboutDialog.cpp index a6b99a08b..05f301186 100644 --- a/src/slic3r/GUI/AboutDialog.cpp +++ b/src/slic3r/GUI/AboutDialog.cpp @@ -220,7 +220,7 @@ AboutDialog::AboutDialog() main_sizer->Add(hsizer, 0, wxEXPAND | wxALL, 20); // logo - m_logo_bitmap = ScalableBitmap(this, wxGetApp().is_editor() ? "PrusaSlicer_192px.png" : "PrusaSlicer-gcodeviewer_192px.png", 192); + m_logo_bitmap = ScalableBitmap(this, wxGetApp().logo_name(), 192); m_logo = new wxStaticBitmap(this, wxID_ANY, m_logo_bitmap.bmp()); hsizer->Add(m_logo, 1, wxALIGN_CENTER_VERTICAL); diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index e1fcc029a..e2a9df25d 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -193,7 +193,7 @@ public: // load bitmap for logo BitmapCache bmp_cache; int logo_size = lround(width * 0.25); - wxBitmap logo_bmp = *bmp_cache.load_svg(wxGetApp().is_editor() ? "prusa_slicer_logo" : "add_gcode", logo_size, logo_size); + wxBitmap logo_bmp = *bmp_cache.load_svg(wxGetApp().logo_name(), logo_size, logo_size); wxCoord margin = int(m_scale * 20); @@ -883,7 +883,7 @@ bool GUI_App::on_init_inner() } // create splash screen with updated bmp - scrn = new SplashScreen(bmp.IsOk() ? bmp : create_scaled_bitmap("prusa_slicer_logo", nullptr, 400), + scrn = new SplashScreen(bmp.IsOk() ? bmp : create_scaled_bitmap("PrusaSlicer", nullptr, 400), wxSPLASH_CENTRE_ON_SCREEN | wxSPLASH_TIMEOUT, 4000, splashscreen_pos); #ifndef __linux__ wxYield(); diff --git a/src/slic3r/GUI/GUI_App.hpp b/src/slic3r/GUI/GUI_App.hpp index a581cf8b3..3061bbe13 100644 --- a/src/slic3r/GUI/GUI_App.hpp +++ b/src/slic3r/GUI/GUI_App.hpp @@ -166,6 +166,7 @@ public: bool is_editor() const { return m_app_mode == EAppMode::Editor; } bool is_gcode_viewer() const { return m_app_mode == EAppMode::GCodeViewer; } bool is_recreating_gui() const { return m_is_recreating_gui; } + std::string logo_name() const { return is_editor() ? "PrusaSlicer" : "PrusaSlicer-gcodeviewer"; } // To be called after the GUI is fully built up. // Process command line parameters cached in this->init_params, diff --git a/src/slic3r/GUI/KBShortcutsDialog.cpp b/src/slic3r/GUI/KBShortcutsDialog.cpp index 0bed7eb74..d16161f89 100644 --- a/src/slic3r/GUI/KBShortcutsDialog.cpp +++ b/src/slic3r/GUI/KBShortcutsDialog.cpp @@ -270,7 +270,7 @@ wxPanel* KBShortcutsDialog::create_header(wxWindow* parent, const wxFont& bold_f sizer->AddStretchSpacer(); // logo - m_logo_bmp = ScalableBitmap(this, wxGetApp().is_editor() ? "PrusaSlicer_32px.png" : "PrusaSlicer-gcodeviewer_32px.png", 32); + m_logo_bmp = ScalableBitmap(this, wxGetApp().logo_name(), 32); m_header_bitmap = new wxStaticBitmap(panel, wxID_ANY, m_logo_bmp.bmp()); sizer->Add(m_header_bitmap, 0, wxEXPAND | wxLEFT | wxRIGHT, 10); diff --git a/src/slic3r/GUI/SysInfoDialog.cpp b/src/slic3r/GUI/SysInfoDialog.cpp index 6f8eeedcc..5475a36ea 100644 --- a/src/slic3r/GUI/SysInfoDialog.cpp +++ b/src/slic3r/GUI/SysInfoDialog.cpp @@ -94,7 +94,7 @@ SysInfoDialog::SysInfoDialog() main_sizer->Add(hsizer, 1, wxEXPAND | wxALL, 10); // logo - m_logo_bmp = ScalableBitmap(this, wxGetApp().is_editor() ? "PrusaSlicer_192px.png" : "PrusaSlicer-gcodeviewer_192px.png", 192); + m_logo_bmp = ScalableBitmap(this, wxGetApp().logo_name(), 192); m_logo = new wxStaticBitmap(this, wxID_ANY, m_logo_bmp.bmp()); hsizer->Add(m_logo, 0, wxALIGN_CENTER_VERTICAL); From a2b99db0df1be25d1e21c052f2fc33ca45a199d3 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Thu, 7 Oct 2021 11:51:12 +0200 Subject: [PATCH 024/102] MSW specific:Added dark mode for G-CodeViewer --- src/libslic3r/AppConfig.cpp | 6 +++--- src/slic3r/GUI/Preferences.cpp | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/libslic3r/AppConfig.cpp b/src/libslic3r/AppConfig.cpp index 26c5b470e..fd2c4f865 100644 --- a/src/libslic3r/AppConfig.cpp +++ b/src/libslic3r/AppConfig.cpp @@ -85,9 +85,6 @@ void AppConfig::set_defaults() if (get("associate_stl").empty()) set("associate_stl", "0"); - if (get("dark_color_mode").empty()) - set("dark_color_mode", "0"); - if (get("tabs_as_menu").empty()) set("tabs_as_menu", "0"); #endif // _WIN32 @@ -179,6 +176,9 @@ void AppConfig::set_defaults() #ifdef _WIN32 if (get("use_legacy_3DConnexion").empty()) set("use_legacy_3DConnexion", "0"); + + if (get("dark_color_mode").empty()) + set("dark_color_mode", "0"); #endif // _WIN32 // Remove legacy window positions/sizes diff --git a/src/slic3r/GUI/Preferences.cpp b/src/slic3r/GUI/Preferences.cpp index 880723693..9d1236922 100644 --- a/src/slic3r/GUI/Preferences.cpp +++ b/src/slic3r/GUI/Preferences.cpp @@ -343,6 +343,7 @@ void PreferencesDialog::build(size_t selected_tab) m_optgroup_gui->append_single_option_line(option); #ifdef _MSW_DARK_MODE + } def.label = L("Use Dark color mode (experimental)"); def.type = coBool; def.tooltip = L("If enabled, UI will use Dark mode colors. " @@ -351,6 +352,7 @@ void PreferencesDialog::build(size_t selected_tab) option = Option(def, "dark_color_mode"); m_optgroup_gui->append_single_option_line(option); + if (is_editor) { def.label = L("Set settings tabs as menu items (experimental)"); def.type = coBool; def.tooltip = L("If enabled, Settings Tabs will be placed as menu items. " From fb3ed367ad71b589b328f02b5532b76ef399080f Mon Sep 17 00:00:00 2001 From: YuSanka Date: Thu, 7 Oct 2021 11:53:04 +0200 Subject: [PATCH 025/102] Try to fix a focus for Application after closing of the "fix thought NetFab" ProgressBarDialog --- src/slic3r/GUI/GUI_ObjectList.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index d2a6b6e9a..e6e7336f7 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -4123,8 +4123,7 @@ void ObjectList::fix_through_netfabb() Plater::TakeSnapshot snapshot(plater, _L("Fix through NetFabb")); // Open a progress dialog. - wxProgressDialog progress_dlg(_L("Fixing through NetFabb"), "", 100, - nullptr, // ! parent of the wxProgressDialog should be nullptr to avoid flickering during the model fixing + wxProgressDialog progress_dlg(_L("Fixing through NetFabb"), "", 100, plater, wxPD_AUTO_HIDE | wxPD_APP_MODAL | wxPD_CAN_ABORT); int model_idx{ 0 }; if (vol_idxs.empty()) { From 992a279bef876b8ad9622a1f8f512136b7c408a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Thu, 7 Oct 2021 11:25:17 +0200 Subject: [PATCH 026/102] Removed the vertical space in the below information about how to use gizmo for all painting gizmos. --- src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp | 1 - src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp | 5 +---- src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp | 2 +- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp index 437106fed..6f1132941 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp @@ -129,7 +129,6 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l for (const auto &t : std::array{"enforce", "block", "remove"}) draw_text_with_caption(m_desc.at(t + "_caption"), m_desc.at(t)); - m_imgui->text(""); ImGui::Separator(); ImGui::AlignTextToFramePadding(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp index d7824357f..7bd444952 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp @@ -42,7 +42,6 @@ void GLGizmoMmuSegmentation::on_shutdown() std::string GLGizmoMmuSegmentation::on_get_name() const { - // FIXME Lukas H.: Discuss and change shortcut return _u8L("Multimaterial painting"); } @@ -107,7 +106,6 @@ void GLGizmoMmuSegmentation::init_extruders_data() bool GLGizmoMmuSegmentation::on_init() { - // FIXME Lukas H.: Discuss and change shortcut m_shortcut_key = WXK_CONTROL_N; m_desc["reset_direction"] = _L("Reset direction"); @@ -289,7 +287,6 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott for (const auto &t : std::array{"first_color", "second_color", "remove"}) draw_text_with_caption(m_desc.at(t + "_caption"), m_desc.at(t)); - m_imgui->text(""); ImGui::Separator(); ImGui::AlignTextToFramePadding(); @@ -400,7 +397,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott ImGui::EndTooltip(); } - ImGui::SameLine(cursor_type_offset +cursor_type_radio_sphere + m_imgui->scaled(0.f)); + ImGui::SameLine(cursor_type_offset + cursor_type_radio_sphere + m_imgui->scaled(0.f)); ImGui::PushItemWidth(cursor_type_radio_circle); if (m_imgui->radio_button(m_desc["circle"], m_cursor_type == TriangleSelector::CursorType::CIRCLE)) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp index b23528772..286d32256 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp @@ -119,7 +119,7 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit) for (const auto &t : std::array{"enforce", "block", "remove"}) draw_text_with_caption(m_desc.at(t + "_caption"), m_desc.at(t)); - m_imgui->text(""); + ImGui::Separator(); if (m_imgui->button(m_desc.at("remove_all"))) { Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Reset selection"), From 6012bf1e038fca849e39e902513fa453fada74d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Wed, 6 Oct 2021 15:34:28 +0200 Subject: [PATCH 027/102] Removed unintended space after ImGui::SliderFloat in all painting gizmos. --- src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp | 6 +++--- src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp | 4 ++-- src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp index 6f1132941..9a9739b90 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp @@ -139,7 +139,7 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l "placed after the number with no whitespace in between."); ImGui::SameLine(autoset_slider_left); ImGui::PushItemWidth(window_width - autoset_slider_left); - if (m_imgui->slider_float("", &m_angle_threshold_deg, 0.f, 90.f, format_str.data())) { + if (m_imgui->slider_float("##angle_threshold_deg", &m_angle_threshold_deg, 0.f, 90.f, format_str.data())) { m_parent.set_slope_normal_angle(90.f - m_angle_threshold_deg); if (! m_parent.is_using_slope()) { m_parent.use_slope(true); @@ -188,7 +188,7 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l m_imgui->text(m_desc.at("cursor_size")); ImGui::SameLine(cursor_slider_left); ImGui::PushItemWidth(window_width - cursor_slider_left); - m_imgui->slider_float(" ", &m_cursor_radius, CursorRadiusMin, CursorRadiusMax, "%.2f"); + m_imgui->slider_float("##cursor_radius", &m_cursor_radius, CursorRadiusMin, CursorRadiusMax, "%.2f"); if (ImGui::IsItemHovered()) { ImGui::BeginTooltip(); ImGui::PushTextWrapPos(max_tooltip_width); @@ -252,7 +252,7 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l ImGui::SameLine(clipping_slider_left); ImGui::PushItemWidth(window_width - clipping_slider_left); auto clp_dist = float(m_c->object_clipper()->get_position()); - if (m_imgui->slider_float(" ", &clp_dist, 0.f, 1.f, "%.2f")) + if (m_imgui->slider_float("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f")) m_c->object_clipper()->set_position(clp_dist, true); if (ImGui::IsItemHovered()) { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp index 7bd444952..16310cbc5 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp @@ -431,7 +431,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott m_imgui->text(m_desc.at("cursor_size")); ImGui::SameLine(sliders_width); ImGui::PushItemWidth(window_width - sliders_width); - m_imgui->slider_float(" ", &m_cursor_radius, CursorRadiusMin, CursorRadiusMax, "%.2f"); + m_imgui->slider_float("##cursor_radius", &m_cursor_radius, CursorRadiusMin, CursorRadiusMax, "%.2f"); if (ImGui::IsItemHovered()) { ImGui::BeginTooltip(); ImGui::PushTextWrapPos(max_tooltip_width); @@ -489,7 +489,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott ImGui::SameLine(sliders_width); ImGui::PushItemWidth(window_width - sliders_width); auto clp_dist = float(m_c->object_clipper()->get_position()); - if (m_imgui->slider_float(" ", &clp_dist, 0.f, 1.f, "%.2f")) + if (m_imgui->slider_float("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f")) m_c->object_clipper()->set_position(clp_dist, true); if (ImGui::IsItemHovered()) { ImGui::BeginTooltip(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp index 286d32256..3d897b0de 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp @@ -144,7 +144,7 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit) m_imgui->text(m_desc.at("cursor_size")); ImGui::SameLine(cursor_size_slider_left); ImGui::PushItemWidth(window_width - cursor_size_slider_left); - m_imgui->slider_float(" ", &m_cursor_radius, CursorRadiusMin, CursorRadiusMax, "%.2f"); + m_imgui->slider_float("##cursor_radius", &m_cursor_radius, CursorRadiusMin, CursorRadiusMax, "%.2f"); if (ImGui::IsItemHovered()) { ImGui::BeginTooltip(); ImGui::PushTextWrapPos(max_tooltip_width); @@ -206,7 +206,7 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit) ImGui::SameLine(clipping_slider_left); ImGui::PushItemWidth(window_width - clipping_slider_left); auto clp_dist = float(m_c->object_clipper()->get_position()); - if (m_imgui->slider_float(" ", &clp_dist, 0.f, 1.f, "%.2f")) + if (m_imgui->slider_float("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f")) m_c->object_clipper()->set_position(clp_dist, true); if (ImGui::IsItemHovered()) { From 925d3fad1f20fbb5edfdbee0be9407acf8e20350 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Wed, 6 Oct 2021 21:54:40 +0200 Subject: [PATCH 028/102] Fixed the wrong calculation of caption text size in all painting gizmos, which could lead to showing unintended space after ImGui::SliderFloat. --- src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp | 11 ++++++----- src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp | 10 +++++----- src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp | 11 ++++++----- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp index 9a9739b90..6a892e9c1 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp @@ -108,13 +108,14 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l float caption_max = 0.f; float total_text_max = 0.f; for (const auto &t : std::array{"enforce", "block", "remove"}) { - caption_max = std::max(caption_max, m_imgui->calc_text_size(m_desc.at(t + "_caption")).x); - total_text_max = std::max(total_text_max, caption_max + m_imgui->calc_text_size(m_desc.at(t)).x); + caption_max = std::max(caption_max, m_imgui->calc_text_size(m_desc[t + "_caption"]).x); + total_text_max = std::max(total_text_max, m_imgui->calc_text_size(m_desc[t]).x); } - caption_max += m_imgui->scaled(1.f); - total_text_max += m_imgui->scaled(1.f); + total_text_max += caption_max + m_imgui->scaled(1.f); + caption_max += m_imgui->scaled(1.f); - float window_width = minimal_slider_width + std::max(autoset_slider_left, std::max(cursor_slider_left, clipping_slider_left)); + float sliders_width = std::max(autoset_slider_left, std::max(cursor_slider_left, clipping_slider_left)); + float window_width = minimal_slider_width + sliders_width; window_width = std::max(window_width, total_text_max); window_width = std::max(window_width, button_width); window_width = std::max(window_width, cursor_type_radio_left + cursor_type_radio_width1 + cursor_type_radio_width2); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp index 16310cbc5..c9edb6c93 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp @@ -262,13 +262,13 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott const float tool_type_radio_smart_fill = m_imgui->calc_text_size(m_desc["tool_smart_fill"]).x + m_imgui->scaled(2.5f); float caption_max = 0.f; - float total_text_max = 0.; + float total_text_max = 0.f; for (const auto &t : std::array{"first_color", "second_color", "remove"}) { - caption_max = std::max(caption_max, m_imgui->calc_text_size(m_desc.at(t + "_caption")).x); - total_text_max = std::max(total_text_max, caption_max + m_imgui->calc_text_size(m_desc.at(t)).x); + caption_max = std::max(caption_max, m_imgui->calc_text_size(m_desc[t + "_caption"]).x); + total_text_max = std::max(total_text_max, m_imgui->calc_text_size(m_desc[t]).x); } - caption_max += m_imgui->scaled(1.f); - total_text_max += m_imgui->scaled(1.f); + total_text_max += caption_max + m_imgui->scaled(1.f); + caption_max += m_imgui->scaled(1.f); float sliders_width = std::max(smart_fill_slider_left, std::max(cursor_slider_left, clipping_slider_left)); float window_width = minimal_slider_width + sliders_width; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp index 3d897b0de..fea506eaa 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp @@ -98,13 +98,14 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit) float caption_max = 0.f; float total_text_max = 0.f; for (const auto &t : std::array{"enforce", "block", "remove"}) { - caption_max = std::max(caption_max, m_imgui->calc_text_size(m_desc.at(t + "_caption")).x); - total_text_max = std::max(total_text_max, caption_max + m_imgui->calc_text_size(m_desc.at(t)).x); + caption_max = std::max(caption_max, m_imgui->calc_text_size(m_desc[t + "_caption"]).x); + total_text_max = std::max(total_text_max, m_imgui->calc_text_size(m_desc[t]).x); } - caption_max += m_imgui->scaled(1.f); - total_text_max += m_imgui->scaled(1.f); + total_text_max += caption_max + m_imgui->scaled(1.f); + caption_max += m_imgui->scaled(1.f); - float window_width = minimal_slider_width + std::max(cursor_size_slider_left, clipping_slider_left); + float sliders_width = std::max(cursor_size_slider_left, clipping_slider_left); + float window_width = minimal_slider_width + sliders_width; window_width = std::max(window_width, total_text_max); window_width = std::max(window_width, button_width); window_width = std::max(window_width, cursor_type_radio_left + cursor_type_radio_width1 + cursor_type_radio_width2); From dfb4ccdb13fa514c718b8f451fb71e7e3764ce58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Thu, 7 Oct 2021 11:51:38 +0200 Subject: [PATCH 029/102] Reworked seam painting gizmo to the same layout as multi-material painting gizmo. --- src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp | 78 ++++++++++++--------------- 1 file changed, 35 insertions(+), 43 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp index fea506eaa..672381835 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp @@ -87,11 +87,11 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit) m_imgui->calc_text_size(m_desc.at("reset_direction")).x) + m_imgui->scaled(1.5f); const float cursor_size_slider_left = m_imgui->calc_text_size(m_desc.at("cursor_size")).x + m_imgui->scaled(1.f); - const float cursor_type_radio_left = m_imgui->calc_text_size(m_desc.at("cursor_type")).x + m_imgui->scaled(1.f); - const float cursor_type_radio_width1 = m_imgui->calc_text_size(m_desc["circle"]).x - + m_imgui->scaled(2.5f); - const float cursor_type_radio_width2 = m_imgui->calc_text_size(m_desc["sphere"]).x - + m_imgui->scaled(2.5f); + + const float cursor_type_radio_left = m_imgui->calc_text_size(m_desc["cursor_type"]).x + m_imgui->scaled(1.f); + const float cursor_type_radio_sphere = m_imgui->calc_text_size(m_desc["sphere"]).x + m_imgui->scaled(2.5f); + const float cursor_type_radio_circle = m_imgui->calc_text_size(m_desc["circle"]).x + m_imgui->scaled(2.5f); + 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); @@ -108,7 +108,7 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit) float window_width = minimal_slider_width + sliders_width; window_width = std::max(window_width, total_text_max); window_width = std::max(window_width, button_width); - window_width = std::max(window_width, cursor_type_radio_left + cursor_type_radio_width1 + cursor_type_radio_width2); + window_width = std::max(window_width, cursor_type_radio_left + cursor_type_radio_sphere + cursor_type_radio_circle); 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); @@ -122,29 +122,12 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit) ImGui::Separator(); - if (m_imgui->button(m_desc.at("remove_all"))) { - Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Reset selection"), - UndoRedo::SnapshotType::GizmoAction); - ModelObject* mo = m_c->selection_info()->model_object(); - int idx = -1; - for (ModelVolume* mv : mo->volumes) { - if (mv->is_model_part()) { - ++idx; - m_triangle_selectors[idx]->reset(); - m_triangle_selectors[idx]->request_update_render_data(); - } - } - - update_model_object(); - m_parent.set_as_dirty(); - } - const float max_tooltip_width = ImGui::GetFontSize() * 20.0f; ImGui::AlignTextToFramePadding(); m_imgui->text(m_desc.at("cursor_size")); - ImGui::SameLine(cursor_size_slider_left); - ImGui::PushItemWidth(window_width - cursor_size_slider_left); + ImGui::SameLine(sliders_width); + ImGui::PushItemWidth(window_width - sliders_width); m_imgui->slider_float("##cursor_radius", &m_cursor_radius, CursorRadiusMin, CursorRadiusMax, "%.2f"); if (ImGui::IsItemHovered()) { ImGui::BeginTooltip(); @@ -156,12 +139,12 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit) ImGui::AlignTextToFramePadding(); m_imgui->text(m_desc.at("cursor_type")); - ImGui::SameLine(cursor_type_radio_left + m_imgui->scaled(0.f)); - ImGui::PushItemWidth(cursor_type_radio_width1); - bool sphere_sel = m_cursor_type == TriangleSelector::CursorType::SPHERE; - if (m_imgui->radio_button(m_desc["sphere"], sphere_sel)) - sphere_sel = true; + float cursor_type_offset = cursor_type_radio_left + (window_width - cursor_type_radio_left - cursor_type_radio_sphere - cursor_type_radio_circle + m_imgui->scaled(0.5f)) / 2.f; + ImGui::SameLine(cursor_type_offset); + ImGui::PushItemWidth(cursor_type_radio_sphere); + if (m_imgui->radio_button(m_desc["sphere"], m_cursor_type == TriangleSelector::CursorType::SPHERE)) + m_cursor_type = TriangleSelector::CursorType::SPHERE; if (ImGui::IsItemHovered()) { ImGui::BeginTooltip(); @@ -171,11 +154,10 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit) ImGui::EndTooltip(); } - ImGui::SameLine(cursor_type_radio_left + cursor_type_radio_width2 + m_imgui->scaled(0.f)); - ImGui::PushItemWidth(cursor_type_radio_width2); - - if (m_imgui->radio_button(m_desc["circle"], ! sphere_sel)) - sphere_sel = false; + ImGui::SameLine(cursor_type_offset + cursor_type_radio_sphere); + ImGui::PushItemWidth(cursor_type_radio_circle); + if (m_imgui->radio_button(m_desc["circle"], m_cursor_type == TriangleSelector::CursorType::CIRCLE)) + m_cursor_type = TriangleSelector::CursorType::CIRCLE; if (ImGui::IsItemHovered()) { ImGui::BeginTooltip(); @@ -185,12 +167,6 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit) ImGui::EndTooltip(); } - m_cursor_type = sphere_sel - ? TriangleSelector::CursorType::SPHERE - : TriangleSelector::CursorType::CIRCLE; - - - ImGui::Separator(); if (m_c->object_clipper()->get_position() == 0.f) { ImGui::AlignTextToFramePadding(); @@ -204,8 +180,8 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit) } } - ImGui::SameLine(clipping_slider_left); - ImGui::PushItemWidth(window_width - clipping_slider_left); + ImGui::SameLine(sliders_width); + ImGui::PushItemWidth(window_width - sliders_width); auto clp_dist = float(m_c->object_clipper()->get_position()); if (m_imgui->slider_float("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f")) m_c->object_clipper()->set_position(clp_dist, true); @@ -218,6 +194,22 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit) ImGui::EndTooltip(); } + ImGui::Separator(); + if (m_imgui->button(m_desc.at("remove_all"))) { + Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Reset selection"), UndoRedo::SnapshotType::GizmoAction); + ModelObject *mo = m_c->selection_info()->model_object(); + int idx = -1; + for (ModelVolume *mv : mo->volumes) + if (mv->is_model_part()) { + ++idx; + m_triangle_selectors[idx]->reset(); + m_triangle_selectors[idx]->request_update_render_data(); + } + + update_model_object(); + m_parent.set_as_dirty(); + } + m_imgui->end(); } From 99edfd22ce17895051a6a2e9325806aff174ae29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Thu, 7 Oct 2021 11:59:37 +0200 Subject: [PATCH 030/102] Improved the alignment of tool type and brush type in the multi-material gizmo. --- .../GUI/Gizmos/GLGizmoMmuSegmentation.cpp | 31 +++++++++---------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp index c9edb6c93..e2088d4ac 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp @@ -318,15 +318,13 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott ImGui::Separator(); m_imgui->text(m_desc.at("tool_type")); - - float tool_type_offset = (window_width - tool_type_radio_brush - tool_type_radio_bucket_fill - tool_type_radio_smart_fill + m_imgui->scaled(2.f)) / 2.f; - ImGui::NewLine(); - ImGui::SameLine(tool_type_offset + m_imgui->scaled(0.f)); + float tool_type_offset = (window_width - tool_type_radio_brush - tool_type_radio_bucket_fill - tool_type_radio_smart_fill + m_imgui->scaled(1.5f)) / 2.f; + ImGui::SameLine(tool_type_offset); ImGui::PushItemWidth(tool_type_radio_brush); - if (m_imgui->radio_button(m_desc["tool_brush"], m_tool_type == GLGizmoMmuSegmentation::ToolType::BRUSH)) { - m_tool_type = GLGizmoMmuSegmentation::ToolType::BRUSH; + if (m_imgui->radio_button(m_desc["tool_brush"], m_tool_type == ToolType::BRUSH)) { + m_tool_type = ToolType::BRUSH; for (auto &triangle_selector : m_triangle_selectors) { triangle_selector->seed_fill_unselect_all_triangles(); triangle_selector->request_update_render_data(); @@ -341,10 +339,10 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott ImGui::EndTooltip(); } - ImGui::SameLine(tool_type_offset + tool_type_radio_brush + m_imgui->scaled(0.f)); + ImGui::SameLine(tool_type_offset + tool_type_radio_brush); ImGui::PushItemWidth(tool_type_radio_smart_fill); - if (m_imgui->radio_button(m_desc["tool_smart_fill"], m_tool_type == GLGizmoMmuSegmentation::ToolType::SMART_FILL)) { - m_tool_type = GLGizmoMmuSegmentation::ToolType::SMART_FILL; + if (m_imgui->radio_button(m_desc["tool_smart_fill"], m_tool_type == ToolType::SMART_FILL)) { + m_tool_type = ToolType::SMART_FILL; for (auto &triangle_selector : m_triangle_selectors) { triangle_selector->seed_fill_unselect_all_triangles(); triangle_selector->request_update_render_data(); @@ -359,10 +357,10 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott ImGui::EndTooltip(); } - ImGui::SameLine(tool_type_offset + tool_type_radio_brush + tool_type_radio_smart_fill + m_imgui->scaled(0.f)); + ImGui::SameLine(tool_type_offset + tool_type_radio_brush + tool_type_radio_smart_fill); ImGui::PushItemWidth(tool_type_radio_bucket_fill); - if (m_imgui->radio_button(m_desc["tool_bucket_fill"], m_tool_type == GLGizmoMmuSegmentation::ToolType::BUCKET_FILL)) { - m_tool_type = GLGizmoMmuSegmentation::ToolType::BUCKET_FILL; + if (m_imgui->radio_button(m_desc["tool_bucket_fill"], m_tool_type == ToolType::BUCKET_FILL)) { + m_tool_type = ToolType::BUCKET_FILL; for (auto &triangle_selector : m_triangle_selectors) { triangle_selector->seed_fill_unselect_all_triangles(); triangle_selector->request_update_render_data(); @@ -383,8 +381,8 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott m_imgui->text(m_desc.at("cursor_type")); ImGui::NewLine(); - float cursor_type_offset = (window_width - cursor_type_radio_sphere - cursor_type_radio_circle - cursor_type_radio_pointer + m_imgui->scaled(2.f)) / 2.f; - ImGui::SameLine(cursor_type_offset + m_imgui->scaled(0.f)); + float cursor_type_offset = (window_width - cursor_type_radio_sphere - cursor_type_radio_circle - cursor_type_radio_pointer + m_imgui->scaled(1.5f)) / 2.f; + ImGui::SameLine(cursor_type_offset); ImGui::PushItemWidth(cursor_type_radio_sphere); if (m_imgui->radio_button(m_desc["sphere"], m_cursor_type == TriangleSelector::CursorType::SPHERE)) m_cursor_type = TriangleSelector::CursorType::SPHERE; @@ -397,7 +395,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott ImGui::EndTooltip(); } - ImGui::SameLine(cursor_type_offset + cursor_type_radio_sphere + m_imgui->scaled(0.f)); + ImGui::SameLine(cursor_type_offset + cursor_type_radio_sphere); ImGui::PushItemWidth(cursor_type_radio_circle); if (m_imgui->radio_button(m_desc["circle"], m_cursor_type == TriangleSelector::CursorType::CIRCLE)) @@ -411,7 +409,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott ImGui::EndTooltip(); } - ImGui::SameLine(cursor_type_offset + cursor_type_radio_sphere + cursor_type_radio_circle + m_imgui->scaled(0.f)); + ImGui::SameLine(cursor_type_offset + cursor_type_radio_sphere + cursor_type_radio_circle); ImGui::PushItemWidth(cursor_type_radio_pointer); if (m_imgui->radio_button(m_desc["pointer"], m_cursor_type == TriangleSelector::CursorType::POINTER)) @@ -491,6 +489,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott auto clp_dist = float(m_c->object_clipper()->get_position()); if (m_imgui->slider_float("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f")) m_c->object_clipper()->set_position(clp_dist, true); + if (ImGui::IsItemHovered()) { ImGui::BeginTooltip(); ImGui::PushTextWrapPos(max_tooltip_width); From 8c9c8a9cc4590e99c2032d9897654d921627bdd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Thu, 7 Oct 2021 12:11:26 +0200 Subject: [PATCH 031/102] Prepared the FDM support gizmo for smart fill. --- src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp | 218 +++++++++++++------ 1 file changed, 152 insertions(+), 66 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp index 6a892e9c1..307f0d028 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp @@ -51,10 +51,17 @@ bool GLGizmoFdmSupports::on_init() m_desc["remove_all"] = _L("Remove all selection"); m_desc["circle"] = _L("Circle"); m_desc["sphere"] = _L("Sphere"); + m_desc["pointer"] = _L("Pointer"); m_desc["highlight_by_angle"] = _L("Highlight by angle"); m_desc["enforce_button"] = _L("Enforce"); m_desc["cancel"] = _L("Cancel"); + m_desc["tool_type"] = _L("Tool type") + ": "; + m_desc["tool_brush"] = _L("Brush"); + m_desc["tool_smart_fill"] = _L("Smart fill"); + + m_desc["smart_fill_angle"] = _L("Smart fill angle"); + return true; } @@ -89,22 +96,26 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l m_imgui->begin(get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse); // 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 autoset_slider_left = m_imgui->calc_text_size(m_desc.at("highlight_by_angle")).x + m_imgui->scaled(1.f); - const float cursor_type_radio_left = m_imgui->calc_text_size(m_desc.at("cursor_type")).x + m_imgui->scaled(1.f); - const float cursor_type_radio_width1 = m_imgui->calc_text_size(m_desc["circle"]).x - + m_imgui->scaled(2.5f); - const float cursor_type_radio_width2 = m_imgui->calc_text_size(m_desc["sphere"]).x - + m_imgui->scaled(2.5f); + 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 autoset_slider_left = m_imgui->calc_text_size(m_desc.at("highlight_by_angle")).x + m_imgui->scaled(1.f); + const float smart_fill_slider_left = m_imgui->calc_text_size(m_desc.at("smart_fill_angle")).x + m_imgui->scaled(1.f); + + const float cursor_type_radio_circle = m_imgui->calc_text_size(m_desc["circle"]).x + m_imgui->scaled(2.5f); + const float cursor_type_radio_sphere = m_imgui->calc_text_size(m_desc["sphere"]).x + m_imgui->scaled(2.5f); + const float cursor_type_radio_pointer = m_imgui->calc_text_size(m_desc["pointer"]).x + m_imgui->scaled(2.5f); + const float button_width = m_imgui->calc_text_size(m_desc.at("remove_all")).x + m_imgui->scaled(1.f); const float button_enforce_width = m_imgui->calc_text_size(m_desc.at("enforce_button")).x; const float button_cancel_width = m_imgui->calc_text_size(m_desc.at("cancel")).x; const float buttons_width = std::max(button_enforce_width, button_cancel_width) + m_imgui->scaled(0.5f); const float minimal_slider_width = m_imgui->scaled(4.f); + const float tool_type_radio_left = m_imgui->calc_text_size(m_desc["tool_type"]).x + m_imgui->scaled(1.f); + const float tool_type_radio_brush = m_imgui->calc_text_size(m_desc["tool_brush"]).x + m_imgui->scaled(2.5f); + const float tool_type_radio_smart_fill = m_imgui->calc_text_size(m_desc["tool_smart_fill"]).x + m_imgui->scaled(2.5f); + float caption_max = 0.f; float total_text_max = 0.f; for (const auto &t : std::array{"enforce", "block", "remove"}) { @@ -114,11 +125,12 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l total_text_max += caption_max + m_imgui->scaled(1.f); caption_max += m_imgui->scaled(1.f); - float sliders_width = std::max(autoset_slider_left, std::max(cursor_slider_left, clipping_slider_left)); + float sliders_width = std::max(std::max(autoset_slider_left, smart_fill_slider_left), std::max(cursor_slider_left, clipping_slider_left)); float window_width = minimal_slider_width + sliders_width; window_width = std::max(window_width, total_text_max); window_width = std::max(window_width, button_width); - window_width = std::max(window_width, cursor_type_radio_left + cursor_type_radio_width1 + cursor_type_radio_width2); + window_width = std::max(window_width, cursor_type_radio_circle + cursor_type_radio_sphere + cursor_type_radio_pointer); + window_width = std::max(window_width, tool_type_radio_left + tool_type_radio_brush + tool_type_radio_smart_fill); window_width = std::max(window_width, 2.f * buttons_width + m_imgui->scaled(1.f)); auto draw_text_with_caption = [this, &caption_max](const wxString& caption, const wxString& text) { @@ -138,8 +150,8 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l std::string format_str = std::string("%.f") + I18N::translate_utf8("°", "Degree sign to use in the respective slider in FDM supports gizmo," "placed after the number with no whitespace in between."); - ImGui::SameLine(autoset_slider_left); - ImGui::PushItemWidth(window_width - autoset_slider_left); + ImGui::SameLine(sliders_width); + ImGui::PushItemWidth(window_width - sliders_width); if (m_imgui->slider_float("##angle_threshold_deg", &m_angle_threshold_deg, 0.f, 90.f, format_str.data())) { m_parent.set_slope_normal_angle(90.f - m_angle_threshold_deg); if (! m_parent.is_using_slope()) { @@ -163,79 +175,136 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l } m_imgui->disabled_end(); - ImGui::Separator(); - - if (m_imgui->button(m_desc.at("remove_all"))) { - Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Reset selection"), - UndoRedo::SnapshotType::GizmoAction); - ModelObject* mo = m_c->selection_info()->model_object(); - int idx = -1; - for (ModelVolume* mv : mo->volumes) { - if (mv->is_model_part()) { - ++idx; - m_triangle_selectors[idx]->reset(); - m_triangle_selectors[idx]->request_update_render_data(); - } - } - - update_model_object(); - m_parent.set_as_dirty(); - } - - const float max_tooltip_width = ImGui::GetFontSize() * 20.0f; - ImGui::AlignTextToFramePadding(); - m_imgui->text(m_desc.at("cursor_size")); - ImGui::SameLine(cursor_slider_left); - ImGui::PushItemWidth(window_width - cursor_slider_left); - m_imgui->slider_float("##cursor_radius", &m_cursor_radius, CursorRadiusMin, CursorRadiusMax, "%.2f"); - if (ImGui::IsItemHovered()) { - ImGui::BeginTooltip(); - ImGui::PushTextWrapPos(max_tooltip_width); - ImGui::TextUnformatted(_L("Alt + Mouse wheel").ToUTF8().data()); - ImGui::PopTextWrapPos(); - ImGui::EndTooltip(); - } - + ImGui::Separator(); ImGui::AlignTextToFramePadding(); - m_imgui->text(m_desc.at("cursor_type")); - ImGui::SameLine(cursor_type_radio_left + m_imgui->scaled(0.f)); - ImGui::PushItemWidth(cursor_type_radio_width1); + m_imgui->text(m_desc["tool_type"]); - bool sphere_sel = m_cursor_type == TriangleSelector::CursorType::SPHERE; - if (m_imgui->radio_button(m_desc["sphere"], sphere_sel)) - sphere_sel = true; + float tool_type_offset = tool_type_radio_left + (window_width - tool_type_radio_left - tool_type_radio_brush - tool_type_radio_smart_fill + m_imgui->scaled(0.5f)) / 2.f; + ImGui::SameLine(tool_type_offset); + ImGui::PushItemWidth(tool_type_radio_brush); + if (m_imgui->radio_button(m_desc["tool_brush"], m_tool_type == ToolType::BRUSH)) + m_tool_type = ToolType::BRUSH; if (ImGui::IsItemHovered()) { ImGui::BeginTooltip(); ImGui::PushTextWrapPos(max_tooltip_width); - ImGui::TextUnformatted(_L("Paints all facets inside, regardless of their orientation.").ToUTF8().data()); + ImGui::TextUnformatted(_L("Paints facets according to the chosen painting brush.").ToUTF8().data()); ImGui::PopTextWrapPos(); ImGui::EndTooltip(); } - ImGui::SameLine(cursor_type_radio_left + cursor_type_radio_width2 + m_imgui->scaled(0.f)); - ImGui::PushItemWidth(cursor_type_radio_width2); - - if (m_imgui->radio_button(m_desc["circle"], ! sphere_sel)) - sphere_sel = false; + ImGui::SameLine(tool_type_offset + tool_type_radio_brush); + ImGui::PushItemWidth(tool_type_radio_smart_fill); + if (m_imgui->radio_button(m_desc["tool_smart_fill"], m_tool_type == ToolType::SMART_FILL)) + m_tool_type = ToolType::SMART_FILL; if (ImGui::IsItemHovered()) { ImGui::BeginTooltip(); ImGui::PushTextWrapPos(max_tooltip_width); - ImGui::TextUnformatted(_L("Ignores facets facing away from the camera.").ToUTF8().data()); + ImGui::TextUnformatted(_L("Paints neighboring facets whose relative angle is less or equal to set angle.").ToUTF8().data()); ImGui::PopTextWrapPos(); ImGui::EndTooltip(); } - m_cursor_type = sphere_sel - ? TriangleSelector::CursorType::SPHERE - : TriangleSelector::CursorType::CIRCLE; + ImGui::Separator(); + if (m_tool_type == ToolType::BRUSH) { + m_imgui->text(m_desc.at("cursor_type")); + ImGui::NewLine(); + float cursor_type_offset = (window_width - cursor_type_radio_sphere - cursor_type_radio_circle - cursor_type_radio_pointer + m_imgui->scaled(1.5f)) / 2.f; + ImGui::SameLine(cursor_type_offset); + ImGui::PushItemWidth(cursor_type_radio_sphere); + if (m_imgui->radio_button(m_desc["sphere"], m_cursor_type == TriangleSelector::CursorType::SPHERE)) + m_cursor_type = TriangleSelector::CursorType::SPHERE; + if (ImGui::IsItemHovered()) { + ImGui::BeginTooltip(); + ImGui::PushTextWrapPos(max_tooltip_width); + ImGui::TextUnformatted(_L("Paints all facets inside, regardless of their orientation.").ToUTF8().data()); + ImGui::PopTextWrapPos(); + ImGui::EndTooltip(); + } + + ImGui::SameLine(cursor_type_offset + cursor_type_radio_sphere); + ImGui::PushItemWidth(cursor_type_radio_circle); + + if (m_imgui->radio_button(m_desc["circle"], m_cursor_type == TriangleSelector::CursorType::CIRCLE)) + m_cursor_type = TriangleSelector::CursorType::CIRCLE; + + if (ImGui::IsItemHovered()) { + ImGui::BeginTooltip(); + ImGui::PushTextWrapPos(max_tooltip_width); + ImGui::TextUnformatted(_L("Ignores facets facing away from the camera.").ToUTF8().data()); + ImGui::PopTextWrapPos(); + ImGui::EndTooltip(); + } + + ImGui::SameLine(cursor_type_offset + cursor_type_radio_sphere + cursor_type_radio_circle); + ImGui::PushItemWidth(cursor_type_radio_pointer); + + if (m_imgui->radio_button(m_desc["pointer"], m_cursor_type == TriangleSelector::CursorType::POINTER)) + m_cursor_type = TriangleSelector::CursorType::POINTER; + + if (ImGui::IsItemHovered()) { + ImGui::BeginTooltip(); + ImGui::PushTextWrapPos(max_tooltip_width); + ImGui::TextUnformatted(_L("Paints only one facet.").ToUTF8().data()); + ImGui::PopTextWrapPos(); + ImGui::EndTooltip(); + } + + m_imgui->disabled_begin(m_cursor_type != TriangleSelector::CursorType::SPHERE && m_cursor_type != TriangleSelector::CursorType::CIRCLE); + + ImGui::AlignTextToFramePadding(); + m_imgui->text(m_desc.at("cursor_size")); + ImGui::SameLine(sliders_width); + ImGui::PushItemWidth(window_width - sliders_width); + m_imgui->slider_float("##cursor_radius", &m_cursor_radius, CursorRadiusMin, CursorRadiusMax, "%.2f"); + if (ImGui::IsItemHovered()) { + ImGui::BeginTooltip(); + ImGui::PushTextWrapPos(max_tooltip_width); + ImGui::TextUnformatted(_L("Alt + Mouse wheel").ToUTF8().data()); + ImGui::PopTextWrapPos(); + ImGui::EndTooltip(); + } + + m_imgui->checkbox(_L("Split triangles"), m_triangle_splitting_enabled); + + if (ImGui::IsItemHovered()) { + ImGui::BeginTooltip(); + ImGui::PushTextWrapPos(max_tooltip_width); + ImGui::TextUnformatted(_L("Split bigger facets into smaller ones while the object is painted.").ToUTF8().data()); + ImGui::PopTextWrapPos(); + ImGui::EndTooltip(); + } + + m_imgui->disabled_end(); + } else { + assert(m_tool_type == ToolType::SMART_FILL); + ImGui::AlignTextToFramePadding(); + m_imgui->text(m_desc["smart_fill_angle"] + ":"); + std::string format_str = std::string("%.f") + I18N::translate_utf8("°", "Degree sign to use in the respective slider in MMU gizmo," + "placed after the number with no whitespace in between."); + ImGui::SameLine(sliders_width); + ImGui::PushItemWidth(window_width - sliders_width); + if (m_imgui->slider_float("##smart_fill_angle", &m_smart_fill_angle, SmartFillAngleMin, SmartFillAngleMax, format_str.data())) + for (auto &triangle_selector : m_triangle_selectors) { + triangle_selector->seed_fill_unselect_all_triangles(); + triangle_selector->request_update_render_data(); + } + + if (ImGui::IsItemHovered()) { + ImGui::BeginTooltip(); + ImGui::PushTextWrapPos(max_tooltip_width); + ImGui::TextUnformatted(_L("Alt + Mouse wheel").ToUTF8().data()); + ImGui::PopTextWrapPos(); + ImGui::EndTooltip(); + } + } ImGui::Separator(); if (m_c->object_clipper()->get_position() == 0.f) { @@ -250,8 +319,8 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l } } - ImGui::SameLine(clipping_slider_left); - ImGui::PushItemWidth(window_width - clipping_slider_left); + ImGui::SameLine(sliders_width); + ImGui::PushItemWidth(window_width - sliders_width); auto clp_dist = float(m_c->object_clipper()->get_position()); if (m_imgui->slider_float("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f")) m_c->object_clipper()->set_position(clp_dist, true); @@ -263,6 +332,23 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l ImGui::PopTextWrapPos(); ImGui::EndTooltip(); } + + ImGui::Separator(); + if (m_imgui->button(m_desc.at("remove_all"))) { + Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Reset selection"), UndoRedo::SnapshotType::GizmoAction); + ModelObject *mo = m_c->selection_info()->model_object(); + int idx = -1; + for (ModelVolume *mv : mo->volumes) + if (mv->is_model_part()) { + ++idx; + m_triangle_selectors[idx]->reset(); + m_triangle_selectors[idx]->request_update_render_data(); + } + + update_model_object(); + m_parent.set_as_dirty(); + } + m_imgui->end(); } @@ -291,7 +377,7 @@ void GLGizmoFdmSupports::select_facets_by_angle(float threshold_deg, bool block) // Now calculate dot product of vert_direction and facets' normals. int idx = 0; const indexed_triangle_set &its = mv->mesh().its; - for (stl_triangle_vertex_indices face : its.indices) { + for (const stl_triangle_vertex_indices &face : its.indices) { if (its_face_normal(its, face).dot(down) > dot_limit) { m_triangle_selectors[mesh_id]->set_facet(idx, block ? EnforcerBlockerType::BLOCKER : EnforcerBlockerType::ENFORCER); m_triangle_selectors.back()->request_update_render_data(); From 2b59a16dc7d3206a52eee5201df1bf21eb21e06f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Thu, 7 Oct 2021 12:45:53 +0200 Subject: [PATCH 032/102] Refactored rendering of the contour around areas selected by smart fill to prepare it for the FDM supports painting gizmo. --- .../GUI/Gizmos/GLGizmoMmuSegmentation.cpp | 87 ++++--------------- .../GUI/Gizmos/GLGizmoMmuSegmentation.hpp | 18 ---- src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp | 63 +++++++++++++- src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp | 41 +++++++++ 4 files changed, 116 insertions(+), 93 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp index e2088d4ac..3153b880b 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp @@ -592,11 +592,6 @@ std::array GLGizmoMmuSegmentation::get_cursor_sphere_right_button_colo return {color[0], color[1], color[2], 0.25f}; } -static std::array get_seed_fill_color(const std::array &base_color) -{ - return {base_color[0] * 0.75f, base_color[1] * 0.75f, base_color[2] * 0.75f, 1.f}; -} - void TriangleSelectorMmGui::render(ImGuiWrapper *imgui) { if (m_update_render_data) @@ -612,14 +607,14 @@ void TriangleSelectorMmGui::render(ImGuiWrapper *imgui) for (size_t color_idx = 0; color_idx < m_gizmo_scene.triangle_indices.size(); ++color_idx) if (m_gizmo_scene.has_VBOs(color_idx)) { if (color_idx > m_colors.size()) // Seed fill VBO - shader->set_uniform("uniform_color", get_seed_fill_color(color_idx == (m_colors.size() + 1) ? m_default_volume_color : m_colors[color_idx - (m_colors.size() + 1) - 1])); + shader->set_uniform("uniform_color", TriangleSelectorGUI::get_seed_fill_color(color_idx == (m_colors.size() + 1) ? m_default_volume_color : m_colors[color_idx - (m_colors.size() + 1) - 1])); else // Normal VBO shader->set_uniform("uniform_color", color_idx == 0 ? m_default_volume_color : m_colors[color_idx - 1]); m_gizmo_scene.render(color_idx); } - if (m_gizmo_scene.has_contour_VBO()) { + if (m_paint_contour.has_VBO()) { ScopeGuard guard_gouraud([shader]() { shader->start_using(); }); shader->stop_using(); @@ -627,7 +622,7 @@ void TriangleSelectorMmGui::render(ImGuiWrapper *imgui) contour_shader->start_using(); glsafe(::glDepthFunc(GL_LEQUAL)); - m_gizmo_scene.render_contour(); + m_paint_contour.render(); glsafe(::glDepthFunc(GL_LESS)); contour_shader->stop_using(); @@ -666,23 +661,24 @@ void TriangleSelectorMmGui::update_render_data() m_gizmo_scene.finalize_triangle_indices(); + m_paint_contour.release_geometry(); std::vector contour_edges = this->get_seed_fill_contour(); - m_gizmo_scene.contour_vertices.reserve(contour_edges.size() * 6); + m_paint_contour.contour_vertices.reserve(contour_edges.size() * 6); for (const Vec2i &edge : contour_edges) { - m_gizmo_scene.contour_vertices.emplace_back(m_vertices[edge(0)].v.x()); - m_gizmo_scene.contour_vertices.emplace_back(m_vertices[edge(0)].v.y()); - m_gizmo_scene.contour_vertices.emplace_back(m_vertices[edge(0)].v.z()); + m_paint_contour.contour_vertices.emplace_back(m_vertices[edge(0)].v.x()); + m_paint_contour.contour_vertices.emplace_back(m_vertices[edge(0)].v.y()); + m_paint_contour.contour_vertices.emplace_back(m_vertices[edge(0)].v.z()); - m_gizmo_scene.contour_vertices.emplace_back(m_vertices[edge(1)].v.x()); - m_gizmo_scene.contour_vertices.emplace_back(m_vertices[edge(1)].v.y()); - m_gizmo_scene.contour_vertices.emplace_back(m_vertices[edge(1)].v.z()); + m_paint_contour.contour_vertices.emplace_back(m_vertices[edge(1)].v.x()); + m_paint_contour.contour_vertices.emplace_back(m_vertices[edge(1)].v.y()); + m_paint_contour.contour_vertices.emplace_back(m_vertices[edge(1)].v.z()); } - m_gizmo_scene.contour_indices.assign(m_gizmo_scene.contour_vertices.size() / 3, 0); - std::iota(m_gizmo_scene.contour_indices.begin(), m_gizmo_scene.contour_indices.end(), 0); - m_gizmo_scene.contour_indices_size = m_gizmo_scene.contour_indices.size(); + m_paint_contour.contour_indices.assign(m_paint_contour.contour_vertices.size() / 3, 0); + std::iota(m_paint_contour.contour_indices.begin(), m_paint_contour.contour_indices.end(), 0); + m_paint_contour.contour_indices_size = m_paint_contour.contour_indices.size(); - m_gizmo_scene.finalize_contour(); + m_paint_contour.finalize_geometry(); } wxString GLGizmoMmuSegmentation::handle_snapshot_action_name(bool shift_down, GLGizmoPainterBase::Button button_down) const @@ -706,14 +702,6 @@ void GLMmSegmentationGizmo3DScene::release_geometry() { glsafe(::glDeleteBuffers(1, &triangle_indices_VBO_id)); triangle_indices_VBO_id = 0; } - if (this->contour_vertices_VBO_id) { - glsafe(::glDeleteBuffers(1, &this->contour_vertices_VBO_id)); - this->contour_vertices_VBO_id = 0; - } - if (this->contour_indices_VBO_id) { - glsafe(::glDeleteBuffers(1, &this->contour_indices_VBO_id)); - this->contour_indices_VBO_id = 0; - } this->clear(); } @@ -741,29 +729,6 @@ void GLMmSegmentationGizmo3DScene::render(size_t triangle_indices_idx) const glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); } -void GLMmSegmentationGizmo3DScene::render_contour() const -{ - assert(this->contour_vertices_VBO_id != 0); - assert(this->contour_indices_VBO_id != 0); - - glsafe(::glLineWidth(4.0f)); - - glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->contour_vertices_VBO_id)); - glsafe(::glVertexPointer(3, GL_FLOAT, 3 * sizeof(float), nullptr)); - - glsafe(::glEnableClientState(GL_VERTEX_ARRAY)); - - if (this->contour_indices_size > 0) { - glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->contour_indices_VBO_id)); - glsafe(::glDrawElements(GL_LINES, GLsizei(this->contour_indices_size), GL_UNSIGNED_INT, nullptr)); - glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); - } - - glsafe(::glDisableClientState(GL_VERTEX_ARRAY)); - - glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); -} - void GLMmSegmentationGizmo3DScene::finalize_vertices() { assert(this->vertices_VBO_id == 0); @@ -791,26 +756,4 @@ void GLMmSegmentationGizmo3DScene::finalize_triangle_indices() } } -void GLMmSegmentationGizmo3DScene::finalize_contour() -{ - assert(this->contour_vertices_VBO_id == 0); - assert(this->contour_indices_VBO_id == 0); - - if (!this->contour_vertices.empty()) { - glsafe(::glGenBuffers(1, &this->contour_vertices_VBO_id)); - glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->contour_vertices_VBO_id)); - glsafe(::glBufferData(GL_ARRAY_BUFFER, this->contour_vertices.size() * sizeof(float), this->contour_vertices.data(), GL_STATIC_DRAW)); - glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); - this->contour_vertices.clear(); - } - - if (!this->contour_indices.empty()) { - glsafe(::glGenBuffers(1, &this->contour_indices_VBO_id)); - glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->contour_indices_VBO_id)); - glsafe(::glBufferData(GL_ARRAY_BUFFER, this->contour_indices.size() * sizeof(unsigned int), this->contour_indices.data(), GL_STATIC_DRAW)); - glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); - this->contour_indices.clear(); - } -} - } // namespace Slic3r diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp index 851a5ac4f..604edf64d 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp @@ -25,8 +25,6 @@ public: return this->triangle_indices_VBO_ids[triangle_indices_idx] != 0; } - [[nodiscard]] inline bool has_contour_VBO() const { return this->contour_indices_VBO_id != 0; } - // Release the geometry data, release OpenGL VBOs. void release_geometry(); // Finalize the initialization of the geometry, upload the geometry to OpenGL VBO objects @@ -35,9 +33,6 @@ public: // Finalize the initialization of the indices, upload the indices to OpenGL VBO objects // and possibly releasing it if it has been loaded into the VBOs. void finalize_triangle_indices(); - // Finalize the initialization of the contour geometry and the indices, upload both to OpenGL VBO objects - // and possibly releasing it if it has been loaded into the VBOs. - void finalize_contour(); void clear() { @@ -47,34 +42,21 @@ public: for (size_t &triangle_indices_size : this->triangle_indices_sizes) triangle_indices_size = 0; - - this->contour_vertices.clear(); - this->contour_indices.clear(); - this->contour_indices_size = 0; } void render(size_t triangle_indices_idx) const; - void render_contour() const; - std::vector vertices; std::vector> triangle_indices; - std::vector contour_vertices; - std::vector contour_indices; - // When the triangle indices are loaded into the graphics card as Vertex Buffer Objects, // the above mentioned std::vectors are cleared and the following variables keep their original length. std::vector triangle_indices_sizes; - size_t contour_indices_size{0}; // IDs of the Vertex Array Objects, into which the geometry has been loaded. // Zero if the VBOs are not sent to GPU yet. unsigned int vertices_VBO_id{0}; std::vector triangle_indices_VBO_ids; - - unsigned int contour_vertices_VBO_id{0}; - unsigned int contour_indices_VBO_id{0}; }; class TriangleSelectorMmGui : public TriangleSelectorGUI { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp index 42bdd0843..56073b5b7 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp @@ -541,7 +541,10 @@ void GLGizmoPainterBase::on_load(cereal::BinaryInputArchive&) m_schedule_update = true; } - +std::array TriangleSelectorGUI::get_seed_fill_color(const std::array &base_color) +{ + return {base_color[0] * 0.75f, base_color[1] * 0.75f, base_color[2] * 0.75f, 1.f}; +} void TriangleSelectorGUI::render(ImGuiWrapper* imgui) { @@ -575,8 +578,6 @@ void TriangleSelectorGUI::render(ImGuiWrapper* imgui) #endif } - - void TriangleSelectorGUI::update_render_data() { int enf_cnt = 0; @@ -608,7 +609,63 @@ void TriangleSelectorGUI::update_render_data() iva->finalize_geometry(true); } +void GLPaintContour::render() const +{ + assert(this->m_contour_VBO_id != 0); + assert(this->m_contour_EBO_id != 0); + glsafe(::glLineWidth(4.0f)); + + glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->m_contour_VBO_id)); + glsafe(::glVertexPointer(3, GL_FLOAT, 3 * sizeof(float), nullptr)); + + glsafe(::glEnableClientState(GL_VERTEX_ARRAY)); + + if (this->contour_indices_size > 0) { + glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->m_contour_EBO_id)); + glsafe(::glDrawElements(GL_LINES, GLsizei(this->contour_indices_size), GL_UNSIGNED_INT, nullptr)); + glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); + } + + glsafe(::glDisableClientState(GL_VERTEX_ARRAY)); + + glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); +} + +void GLPaintContour::finalize_geometry() +{ + assert(this->m_contour_VBO_id == 0); + assert(this->m_contour_EBO_id == 0); + + if (!this->contour_vertices.empty()) { + glsafe(::glGenBuffers(1, &this->m_contour_VBO_id)); + glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->m_contour_VBO_id)); + glsafe(::glBufferData(GL_ARRAY_BUFFER, this->contour_vertices.size() * sizeof(float), this->contour_vertices.data(), GL_STATIC_DRAW)); + glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); + this->contour_vertices.clear(); + } + + if (!this->contour_indices.empty()) { + glsafe(::glGenBuffers(1, &this->m_contour_EBO_id)); + glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->m_contour_EBO_id)); + glsafe(::glBufferData(GL_ARRAY_BUFFER, this->contour_indices.size() * sizeof(unsigned int), this->contour_indices.data(), GL_STATIC_DRAW)); + glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); + this->contour_indices.clear(); + } +} + +void GLPaintContour::release_geometry() +{ + if (this->m_contour_VBO_id) { + glsafe(::glDeleteBuffers(1, &this->m_contour_VBO_id)); + this->m_contour_VBO_id = 0; + } + if (this->m_contour_EBO_id) { + glsafe(::glDeleteBuffers(1, &this->m_contour_EBO_id)); + this->m_contour_EBO_id = 0; + } + this->clear(); +} #ifdef PRUSASLICER_TRIANGLE_SELECTOR_DEBUG void TriangleSelectorGUI::render_debug(ImGuiWrapper* imgui) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp index 8d37f2404..172e876d3 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp @@ -10,6 +10,7 @@ #include "libslic3r/Model.hpp" #include +#include @@ -26,6 +27,41 @@ enum class PainterGizmoType { MMU_SEGMENTATION }; +class GLPaintContour +{ +public: + GLPaintContour() = default; + + void render() const; + + inline bool has_VBO() const { return this->m_contour_EBO_id != 0; } + + // Release the geometry data, release OpenGL VBOs. + void release_geometry(); + + // Finalize the initialization of the contour geometry and the indices, upload both to OpenGL VBO objects + // and possibly releasing it if it has been loaded into the VBOs. + void finalize_geometry(); + + void clear() + { + this->contour_vertices.clear(); + this->contour_indices.clear(); + this->contour_indices_size = 0; + } + + std::vector contour_vertices; + std::vector contour_indices; + + // When the triangle indices are loaded into the graphics card as Vertex Buffer Objects, + // the above mentioned std::vectors are cleared and the following variables keep their original length. + size_t contour_indices_size{0}; + + // IDs of the Vertex Array Objects, into which the geometry has been loaded. + // Zero if the VBOs are not sent to GPU yet. + GLuint m_contour_VBO_id{0}; + GLuint m_contour_EBO_id{0}; +}; class TriangleSelectorGUI : public TriangleSelector { public: @@ -49,12 +85,17 @@ public: protected: bool m_update_render_data = false; + static std::array get_seed_fill_color(const std::array &base_color); + private: void update_render_data(); GLIndexedVertexArray m_iva_enforcers; GLIndexedVertexArray m_iva_blockers; std::array m_varrays; + +protected: + GLPaintContour m_paint_contour; }; class GLGizmoTransparentRender From 542ba1bb9ad4bf66b27800afe6964de9797446ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Thu, 7 Oct 2021 13:04:22 +0200 Subject: [PATCH 033/102] Added rendering of smart fill and contour around selected areas for the FDM supports painting gizmo. --- src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp | 66 ++++++++++++++++++-- src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp | 1 + src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 2 +- 3 files changed, 62 insertions(+), 7 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp index 56073b5b7..fdb05ae22 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp @@ -569,6 +569,29 @@ void TriangleSelectorGUI::render(ImGuiWrapper* imgui) } } + for (auto &iva : m_iva_seed_fills) + if (iva.has_VBOs()) { + size_t color_idx = &iva - &m_iva_seed_fills.front(); + const std::array &color = TriangleSelectorGUI::get_seed_fill_color(color_idx == 1 ? enforcers_color : + color_idx == 2 ? blockers_color : + GLVolume::NEUTRAL_COLOR); + shader->set_uniform("uniform_color", color); + iva.render(); + } + + if (m_paint_contour.has_VBO()) { + ScopeGuard guard_gouraud([shader]() { shader->start_using(); }); + shader->stop_using(); + + auto *contour_shader = wxGetApp().get_shader("mm_contour"); + contour_shader->start_using(); + + glsafe(::glDepthFunc(GL_GEQUAL)); + m_paint_contour.render(); + glsafe(::glDepthFunc(GL_LESS)); + + contour_shader->stop_using(); + } #ifdef PRUSASLICER_TRIANGLE_SELECTOR_DEBUG if (imgui) @@ -580,22 +603,31 @@ void TriangleSelectorGUI::render(ImGuiWrapper* imgui) void TriangleSelectorGUI::update_render_data() { - int enf_cnt = 0; - int blc_cnt = 0; + int enf_cnt = 0; + int blc_cnt = 0; + std::vector seed_fill_cnt(m_iva_seed_fills.size(), 0); for (auto *iva : {&m_iva_enforcers, &m_iva_blockers}) iva->release_geometry(); + for (auto &iva : m_iva_seed_fills) + iva.release_geometry(); + for (const Triangle &tr : m_triangles) { - if (!tr.valid() || tr.is_split() || tr.get_state() == EnforcerBlockerType::NONE) + if (!tr.valid() || tr.is_split() || (tr.get_state() == EnforcerBlockerType::NONE && !tr.is_selected_by_seed_fill())) continue; - GLIndexedVertexArray &iva = tr.get_state() == EnforcerBlockerType::ENFORCER ? m_iva_enforcers : m_iva_blockers; - int & cnt = tr.get_state() == EnforcerBlockerType::ENFORCER ? enf_cnt : blc_cnt; + int tr_state = int(tr.get_state()); + GLIndexedVertexArray &iva = tr.is_selected_by_seed_fill() ? m_iva_seed_fills[tr_state] : + tr.get_state() == EnforcerBlockerType::ENFORCER ? m_iva_enforcers : + m_iva_blockers; + int &cnt = tr.is_selected_by_seed_fill() ? seed_fill_cnt[tr_state] : + tr.get_state() == EnforcerBlockerType::ENFORCER ? enf_cnt : + blc_cnt; const Vec3f &v0 = m_vertices[tr.verts_idxs[0]].v; const Vec3f &v1 = m_vertices[tr.verts_idxs[1]].v; const Vec3f &v2 = m_vertices[tr.verts_idxs[2]].v; - //FIXME the normal may likely be pulled from m_triangle_selectors, but it may not be worth the effort + //FIXME the normal may likely be pulled from m_triangle_selectors, but it may not be worth the effort // or the current implementation may be more cache friendly. const Vec3f n = (v1 - v0).cross(v2 - v1).normalized(); iva.push_geometry(v0, n); @@ -607,6 +639,28 @@ void TriangleSelectorGUI::update_render_data() for (auto *iva : {&m_iva_enforcers, &m_iva_blockers}) iva->finalize_geometry(true); + + for (auto &iva : m_iva_seed_fills) + iva.finalize_geometry(true); + + m_paint_contour.release_geometry(); + std::vector contour_edges = this->get_seed_fill_contour(); + m_paint_contour.contour_vertices.reserve(contour_edges.size() * 6); + for (const Vec2i &edge : contour_edges) { + m_paint_contour.contour_vertices.emplace_back(m_vertices[edge(0)].v.x()); + m_paint_contour.contour_vertices.emplace_back(m_vertices[edge(0)].v.y()); + m_paint_contour.contour_vertices.emplace_back(m_vertices[edge(0)].v.z()); + + m_paint_contour.contour_vertices.emplace_back(m_vertices[edge(1)].v.x()); + m_paint_contour.contour_vertices.emplace_back(m_vertices[edge(1)].v.y()); + m_paint_contour.contour_vertices.emplace_back(m_vertices[edge(1)].v.z()); + } + + m_paint_contour.contour_indices.assign(m_paint_contour.contour_vertices.size() / 3, 0); + std::iota(m_paint_contour.contour_indices.begin(), m_paint_contour.contour_indices.end(), 0); + m_paint_contour.contour_indices_size = m_paint_contour.contour_indices.size(); + + m_paint_contour.finalize_geometry(); } void GLPaintContour::render() const diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp index 172e876d3..cc15af41f 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp @@ -92,6 +92,7 @@ private: GLIndexedVertexArray m_iva_enforcers; GLIndexedVertexArray m_iva_blockers; + std::array m_iva_seed_fills; std::array m_varrays; protected: diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index 764c42c73..08a94a97d 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -548,7 +548,7 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt) // mouse anywhere if (evt.Moving()) { m_tooltip = update_hover_state(mouse_pos); - if (m_current == MmuSegmentation) + if (m_current == MmuSegmentation || m_current == FdmSupports) gizmo_event(SLAGizmoEventType::Moving, mouse_pos, evt.ShiftDown(), evt.AltDown()); } else if (evt.LeftUp()) { if (m_mouse_capture.left) { From ebdc69bdc92edc28ef14376f811a95ee57f550bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Thu, 7 Oct 2021 13:06:58 +0200 Subject: [PATCH 034/102] Fixed the positioning of the painting gizmos. --- src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp index 307f0d028..286e60213 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp @@ -89,7 +89,7 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l if (! m_c->selection_info()->model_object()) return; - const float approx_height = m_imgui->scaled(17.0f); + const float approx_height = m_imgui->scaled(20.5f); y = std::min(y, bottom_limit - approx_height); m_imgui->set_next_window_pos(x, y, ImGuiCond_Always); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp index 3153b880b..11a5b21bb 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp @@ -234,7 +234,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott if (!m_c->selection_info()->model_object()) return; - const float approx_height = m_imgui->scaled(25.0f); + const float approx_height = m_imgui->scaled(22.0f); y = std::min(y, bottom_limit - approx_height); m_imgui->set_next_window_pos(x, y, ImGuiCond_Always); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp index 672381835..2f9d16f90 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp @@ -77,7 +77,7 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit) if (! m_c->selection_info()->model_object()) return; - const float approx_height = m_imgui->scaled(14.0f); + const float approx_height = m_imgui->scaled(12.5f); y = std::min(y, bottom_limit - approx_height); m_imgui->set_next_window_pos(x, y, ImGuiCond_Always); m_imgui->begin(get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse); From d6d575f607742fdb22d94af36ecf56f7489f5ff2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Thu, 7 Oct 2021 13:10:48 +0200 Subject: [PATCH 035/102] Renamed the brush "Pointer" to "Triangles" in the multi-material painting gizmo, and in the FDM supports painting gizmo. --- src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp index 286e60213..12b827e64 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp @@ -51,7 +51,7 @@ bool GLGizmoFdmSupports::on_init() m_desc["remove_all"] = _L("Remove all selection"); m_desc["circle"] = _L("Circle"); m_desc["sphere"] = _L("Sphere"); - m_desc["pointer"] = _L("Pointer"); + m_desc["pointer"] = _L("Triangles"); m_desc["highlight_by_angle"] = _L("Highlight by angle"); m_desc["enforce_button"] = _L("Enforce"); m_desc["cancel"] = _L("Cancel"); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp index 11a5b21bb..b472fbc1b 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp @@ -121,7 +121,7 @@ bool GLGizmoMmuSegmentation::on_init() m_desc["remove_all"] = _L("Remove all painted areas"); m_desc["circle"] = _L("Circle"); m_desc["sphere"] = _L("Sphere"); - m_desc["pointer"] = _L("Pointer"); + m_desc["pointer"] = _L("Triangles"); m_desc["tool_type"] = _L("Tool type"); m_desc["tool_brush"] = _L("Brush"); From 82bf9c158a3c286ed043e27360421c5bccfa18b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Mon, 4 Oct 2021 12:52:52 +0200 Subject: [PATCH 036/102] Optimized multi-material segmentation to construct Voronoi diagrams only for layers that have more than one color. If the whole layer is painted using the same color, it is not needed to construct a Voronoi diagram. --- src/libslic3r/MultiMaterialSegmentation.cpp | 59 ++++++++++++++------- 1 file changed, 41 insertions(+), 18 deletions(-) diff --git a/src/libslic3r/MultiMaterialSegmentation.cpp b/src/libslic3r/MultiMaterialSegmentation.cpp index 9456f5077..9cbfaae4a 100644 --- a/src/libslic3r/MultiMaterialSegmentation.cpp +++ b/src/libslic3r/MultiMaterialSegmentation.cpp @@ -1214,7 +1214,7 @@ static void cut_segmented_layers(const std::vector const std::function &throw_on_cancel_callback) { BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - cutting segmented layers in parallel - begin"; - tbb::parallel_for(tbb::blocked_range(0, segmented_regions.size()),[&](const tbb::blocked_range& range) { + tbb::parallel_for(tbb::blocked_range(0, segmented_regions.size()),[&segmented_regions, &input_expolygons, &cut_width, &throw_on_cancel_callback](const tbb::blocked_range& range) { for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++layer_idx) { throw_on_cancel_callback(); std::vector> segmented_regions_cuts; @@ -1366,7 +1366,8 @@ static inline std::vector> mmu_segmentation_top_and_bott return out; }; - tbb::parallel_for(tbb::blocked_range(0, num_layers, granularity), [&](const tbb::blocked_range &range) { + tbb::parallel_for(tbb::blocked_range(0, num_layers, granularity), [&granularity, &num_layers, &num_extruders, &layer_color_stat, &top_raw, &triangles_by_color_top, + &throw_on_cancel_callback, &input_expolygons, &bottom_raw, &triangles_by_color_bottom](const tbb::blocked_range &range) { size_t group_idx = range.begin() / granularity; size_t layer_idx_offset = (group_idx & 1) * num_layers; for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx) { @@ -1417,7 +1418,7 @@ static inline std::vector> mmu_segmentation_top_and_bott std::vector> triangles_by_color_merged(num_extruders); triangles_by_color_merged.assign(num_extruders, std::vector(num_layers)); - tbb::parallel_for(tbb::blocked_range(0, num_layers), [&](const tbb::blocked_range &range) { + tbb::parallel_for(tbb::blocked_range(0, num_layers), [&triangles_by_color_merged, &triangles_by_color_bottom, &triangles_by_color_top, &num_layers, &throw_on_cancel_callback](const tbb::blocked_range &range) { for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx) { throw_on_cancel_callback(); for (size_t color_idx = 0; color_idx < triangles_by_color_merged.size(); ++color_idx) { @@ -1446,7 +1447,7 @@ static std::vector>> merge_segmented_la std::vector>> segmented_regions_merged(segmented_regions.size()); BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - merging segmented layers in parallel - begin"; - tbb::parallel_for(tbb::blocked_range(0, segmented_regions.size()), [&](const tbb::blocked_range &range) { + tbb::parallel_for(tbb::blocked_range(0, segmented_regions.size()), [&segmented_regions, &top_and_bottom_layers, &segmented_regions_merged, &throw_on_cancel_callback](const tbb::blocked_range &range) { for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++layer_idx) { for (const std::pair &colored_expoly : segmented_regions[layer_idx]) { throw_on_cancel_callback(); @@ -1526,6 +1527,20 @@ void export_processed_input_expolygons_to_svg(const std::string &path, const Lay } #endif // MMU_SEGMENTATION_DEBUG_INPUT +// Check if all ColoredLine representing a single layer uses the same color. +static bool has_layer_only_one_color(const std::vector> &colored_polygons) +{ + assert(!colored_polygons.empty()); + assert(!colored_polygons.front().empty()); + int first_line_color = colored_polygons.front().front().color; + for (const std::vector &colored_polygon : colored_polygons) + for (const ColoredLine &colored_line : colored_polygon) + if (first_line_color != colored_line.color) + return false; + + return true; +} + std::vector>> multi_material_segmentation_by_painting(const PrintObject &print_object, const std::function &throw_on_cancel_callback) { std::vector>> segmented_regions(print_object.layers().size()); @@ -1539,7 +1554,7 @@ std::vector>> multi_material_segmentati // Merge all regions and remove small holes BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - slices preparation in parallel - begin"; - tbb::parallel_for(tbb::blocked_range(0, layers.size()), [&](const tbb::blocked_range &range) { + tbb::parallel_for(tbb::blocked_range(0, layers.size()), [&layers, &input_expolygons, &throw_on_cancel_callback](const tbb::blocked_range &range) { for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++layer_idx) { throw_on_cancel_callback(); ExPolygons ex_polygons; @@ -1649,16 +1664,16 @@ std::vector>> multi_material_segmentati edge_grids[layer_idx].visit_cells_intersecting_line(line_start, line_end, visitor); } } - }); + }); // end of parallel_for } - }); + }); // end of parallel_for } BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - projection of painted triangles - end"; BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - painted layers count: " << std::count_if(painted_lines.begin(), painted_lines.end(), [](const std::vector &pl) { return !pl.empty(); }); BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - layers segmentation in parallel - begin"; - tbb::parallel_for(tbb::blocked_range(0, print_object.layers().size()), [&](const tbb::blocked_range &range) { + tbb::parallel_for(tbb::blocked_range(0, print_object.layers().size()), [&print_object, &edge_grids, &input_expolygons, &painted_lines, &segmented_regions, &throw_on_cancel_callback](const tbb::blocked_range &range) { for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++layer_idx) { throw_on_cancel_callback(); auto comp = [&edge_grids, layer_idx](const PaintedLine &first, const PaintedLine &second) { @@ -1677,20 +1692,28 @@ std::vector>> multi_material_segmentati if (!painted_lines_single.empty()) { std::vector> color_poly = colorize_polygons(edge_grids[layer_idx].contours(), painted_lines_single); - MMU_Graph graph = build_graph(layer_idx, color_poly); - remove_multiple_edges_in_vertices(graph, color_poly); - graph.remove_nodes_with_one_arc(); + assert(!color_poly.empty()); + assert(!color_poly.front().empty()); + if (has_layer_only_one_color(color_poly)) { + // If the whole layer is painted using the same color, it is not needed to construct a Voronoi diagram for the segmentation of this layer. + for (const ExPolygon &ex_polygon : input_expolygons[layer_idx]) + segmented_regions[layer_idx].emplace_back(ex_polygon, size_t(color_poly.front().front().color)); + } else { + MMU_Graph graph = build_graph(layer_idx, color_poly); + remove_multiple_edges_in_vertices(graph, color_poly); + graph.remove_nodes_with_one_arc(); #ifdef MMU_SEGMENTATION_DEBUG_GRAPH - { - static int iRun = 0; - export_graph_to_svg(debug_out_path("mm-graph-final-%d-%d.svg", layer_idx, iRun++), graph, input_expolygons[layer_idx]); - } + { + static int iRun = 0; + export_graph_to_svg(debug_out_path("mm-graph-final-%d-%d.svg", layer_idx, iRun++), graph, input_expolygons[layer_idx]); + } #endif // MMU_SEGMENTATION_DEBUG_GRAPH - std::vector> segmentation = extract_colored_segments(graph); - for (std::pair ®ion : segmentation) - segmented_regions[layer_idx].emplace_back(std::move(region)); + std::vector> segmentation = extract_colored_segments(graph); + for (std::pair ®ion : segmentation) + segmented_regions[layer_idx].emplace_back(std::move(region)); + } #ifdef MMU_SEGMENTATION_DEBUG_REGIONS { From b99be85187745f98c83d8457cb3076053ff675c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Thu, 7 Oct 2021 13:36:06 +0200 Subject: [PATCH 037/102] Fixed a warning. --- src/libslic3r/MultiMaterialSegmentation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libslic3r/MultiMaterialSegmentation.cpp b/src/libslic3r/MultiMaterialSegmentation.cpp index 9cbfaae4a..b48c71828 100644 --- a/src/libslic3r/MultiMaterialSegmentation.cpp +++ b/src/libslic3r/MultiMaterialSegmentation.cpp @@ -1673,7 +1673,7 @@ std::vector>> multi_material_segmentati << std::count_if(painted_lines.begin(), painted_lines.end(), [](const std::vector &pl) { return !pl.empty(); }); BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - layers segmentation in parallel - begin"; - tbb::parallel_for(tbb::blocked_range(0, print_object.layers().size()), [&print_object, &edge_grids, &input_expolygons, &painted_lines, &segmented_regions, &throw_on_cancel_callback](const tbb::blocked_range &range) { + tbb::parallel_for(tbb::blocked_range(0, print_object.layers().size()), [&edge_grids, &input_expolygons, &painted_lines, &segmented_regions, &throw_on_cancel_callback](const tbb::blocked_range &range) { for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++layer_idx) { throw_on_cancel_callback(); auto comp = [&edge_grids, layer_idx](const PaintedLine &first, const PaintedLine &second) { From c0f3077ce928ccd02ee1e4df927a56141c1ee0a8 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Thu, 7 Oct 2021 14:03:50 +0200 Subject: [PATCH 038/102] Follow-up fb3ed367ad71b589b328f02b5532b76ef399080f : Fixed flickering of the wxProgressDialog during the model fixing --- src/slic3r/Utils/FixModelByWin10.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/Utils/FixModelByWin10.cpp b/src/slic3r/Utils/FixModelByWin10.cpp index 30c81f6f7..6f6b21f68 100644 --- a/src/slic3r/Utils/FixModelByWin10.cpp +++ b/src/slic3r/Utils/FixModelByWin10.cpp @@ -421,7 +421,7 @@ bool fix_model_by_win10_sdk_gui(ModelObject &model_object, int volume_idx, wxPro } }); while (! finished) { - condition.wait_for(lock, std::chrono::milliseconds(500), [&progress]{ return progress.updated; }); + condition.wait_for(lock, std::chrono::milliseconds(250), [&progress]{ return progress.updated; }); // decrease progress.percent value to avoid closing of the progress dialog if (!progress_dialog.Update(progress.percent-1, msg_header + _(progress.message))) canceled = true; From 5de143f04fdb586490b28a4ac60654a1bb964a37 Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Thu, 7 Oct 2021 15:39:32 +0200 Subject: [PATCH 039/102] Follow-up to 96b88f5b29f14d23f022d627b62e7c64883dcef8 Fixed crash with zero support base spacing. The bug fix was not correct and it disabled the new "zig-zag" sparse infill generator, leading to GH issue #7014 Somehow improved missing interface layers for snug supports by propagating full overhangs when generating interface layers. Fixed generation of soluble interfaces for support enforcers, where base support was used for steeper overhangs. Disabled filtering out thin regions from the lower layer, that will not be covered by perimeters, thus they are not supporting the current layer. However this may lead to a situation where regions at the current layer that are narrow thus not extrudable will generate unnecessary supports. For example, see GH issue #3094 --- src/libslic3r/SupportMaterial.cpp | 206 +++++++++++++++++------------- 1 file changed, 119 insertions(+), 87 deletions(-) diff --git a/src/libslic3r/SupportMaterial.cpp b/src/libslic3r/SupportMaterial.cpp index 2099cbf73..9a5638c01 100644 --- a/src/libslic3r/SupportMaterial.cpp +++ b/src/libslic3r/SupportMaterial.cpp @@ -411,6 +411,7 @@ void PrintObjectSupportMaterial::generate(PrintObject &object) BOOST_LOG_TRIVIAL(info) << "Support generator - Creating top contacts"; + // Per object layer projection of the object below the layer into print bed. std::vector buildplate_covered = this->buildplate_covered(object); // Determine the top contact surfaces of the support, defined as: @@ -1241,7 +1242,7 @@ namespace SupportMaterialInternal { const PrintConfig &print_config, const Layer &lower_layer, const Polygons &lower_layer_polygons, - LayerRegion *layerm, + const LayerRegion &layerm, float fw, Polygons &contact_polygons) { @@ -1251,19 +1252,19 @@ namespace SupportMaterialInternal { // Surface supporting this layer, expanded by 0.5 * nozzle_diameter, as we consider this kind of overhang to be sufficiently supported. Polygons lower_grown_slices = offset(lower_layer_polygons, //FIXME to mimic the decision in the perimeter generator, we should use half the external perimeter width. - 0.5f * float(scale_(print_config.nozzle_diameter.get_at(layerm->region().config().perimeter_extruder-1))), + 0.5f * float(scale_(print_config.nozzle_diameter.get_at(layerm.region().config().perimeter_extruder-1))), SUPPORT_SURFACES_OFFSET_PARAMETERS); // Collect perimeters of this layer. //FIXME split_at_first_point() could split a bridge mid-way #if 0 - Polylines overhang_perimeters = layerm->perimeters.as_polylines(); + Polylines overhang_perimeters = layerm.perimeters.as_polylines(); // workaround for Clipper bug, see Slic3r::Polygon::clip_as_polyline() for (Polyline &polyline : overhang_perimeters) polyline.points[0].x += 1; // Trim the perimeters of this layer by the lower layer to get the unsupported pieces of perimeters. overhang_perimeters = diff_pl(overhang_perimeters, lower_grown_slices); #else - Polylines overhang_perimeters = diff_pl(layerm->perimeters.as_polylines(), lower_grown_slices); + Polylines overhang_perimeters = diff_pl(layerm.perimeters.as_polylines(), lower_grown_slices); #endif // only consider straight overhangs @@ -1272,7 +1273,7 @@ namespace SupportMaterialInternal { // since we're dealing with bridges, we can't assume width is larger than spacing, // so we take the largest value and also apply safety offset to be ensure no gaps // are left in between - Flow perimeter_bridge_flow = layerm->bridging_flow(frPerimeter); + Flow perimeter_bridge_flow = layerm.bridging_flow(frPerimeter); float w = float(std::max(perimeter_bridge_flow.scaled_width(), perimeter_bridge_flow.scaled_spacing())); for (Polyline &polyline : overhang_perimeters) if (polyline.is_straight()) { @@ -1293,8 +1294,8 @@ namespace SupportMaterialInternal { bridges = union_(bridges); } // remove the entire bridges and only support the unsupported edges - //FIXME the brided regions are already collected as layerm->bridged. Use it? - for (const Surface &surface : layerm->fill_surfaces.surfaces) + //FIXME the brided regions are already collected as layerm.bridged. Use it? + for (const Surface &surface : layerm.fill_surfaces.surfaces) if (surface.surface_type == stBottomBridge && surface.bridge_angle != -1) polygons_append(bridges, surface.expolygon); //FIXME add the gap filled areas. Extrude the gaps with a bridge flow? @@ -1302,14 +1303,14 @@ namespace SupportMaterialInternal { //FIXME add supports at regular intervals to support long bridges! bridges = diff(bridges, // Offset unsupported edges into polygons. - offset(layerm->unsupported_bridge_edges, scale_(SUPPORT_MATERIAL_MARGIN), SUPPORT_SURFACES_OFFSET_PARAMETERS)); + offset(layerm.unsupported_bridge_edges, scale_(SUPPORT_MATERIAL_MARGIN), SUPPORT_SURFACES_OFFSET_PARAMETERS)); // Remove bridged areas from the supported areas. contact_polygons = diff(contact_polygons, bridges, ApplySafetyOffset::Yes); #ifdef SLIC3R_DEBUG static int iRun = 0; SVG::export_expolygons(debug_out_path("support-top-contacts-remove-bridges-run%d.svg", iRun ++), - { { { union_ex(offset(layerm->unsupported_bridge_edges, scale_(SUPPORT_MATERIAL_MARGIN), SUPPORT_SURFACES_OFFSET_PARAMETERS)) }, { "unsupported_bridge_edges", "orange", 0.5f } }, + { { { union_ex(offset(layerm.unsupported_bridge_edges, scale_(SUPPORT_MATERIAL_MARGIN), SUPPORT_SURFACES_OFFSET_PARAMETERS)) }, { "unsupported_bridge_edges", "orange", 0.5f } }, { { union_ex(contact_polygons) }, { "contact_polygons", "blue", 0.5f } }, { { union_ex(bridges) }, { "bridges", "red", "black", "", scaled(0.1f), 0.5f } } }); #endif /* SLIC3R_DEBUG */ @@ -1325,6 +1326,7 @@ std::vector PrintObjectSupportMaterial::buildplate_covered(const Print if (buildplate_only) { BOOST_LOG_TRIVIAL(debug) << "PrintObjectSupportMaterial::buildplate_covered() - start"; buildplate_covered.assign(object.layers().size(), Polygons()); + //FIXME prefix sum algorithm, parallelize it! Parallelization will also likely be more numerically stable. for (size_t layer_id = 1; layer_id < object.layers().size(); ++ layer_id) { const Layer &lower_layer = *object.layers()[layer_id-1]; // Merge the new slices with the preceding slices. @@ -1368,6 +1370,8 @@ struct SlicesMarginCache Polygons all_polygons; }; +// Tuple: overhang_polygons, contact_polygons, enforcer_polygons, no_interface_offset +// no_interface_offset: minimum of external perimeter widths static inline std::tuple detect_overhangs( const Layer &layer, const size_t layer_id, @@ -1412,7 +1416,7 @@ static inline std::tuple detect_overhangs( // Expand for better stability. contact_polygons = offset(overhang_polygons, scaled(object_config.raft_expansion.value)); } - else + else if (! layer.regions().empty()) { // Generate overhang / contact_polygons for non-raft layers. const Layer &lower_layer = *layer.lower_layer; @@ -1426,6 +1430,7 @@ static inline std::tuple detect_overhangs( slices_margin.offset = slices_margin_offset; slices_margin.polygons = (slices_margin_offset == 0.f) ? lower_layer_polygons : + // What is the purpose of no_interface_offset? Likely to not trim the contact layer by lower layer regions that are too thin to extrude? offset2(lower_layer.lslices, -no_interface_offset * 0.5f, slices_margin_offset + no_interface_offset * 0.5f, SUPPORT_SURFACES_OFFSET_PARAMETERS); if (buildplate_only && !annotations.buildplate_covered[layer_id].empty()) { if (has_enforcer) @@ -1437,14 +1442,14 @@ static inline std::tuple detect_overhangs( } }; - float fw = 0; + no_interface_offset = std::accumulate(layer.regions().begin(), layer.regions().end(), FLT_MAX, + [](float acc, const LayerRegion *layerm) { return std::min(acc, float(layerm->flow(frExternalPerimeter).scaled_width())); }); + float lower_layer_offset = 0; - float no_interface_offset = 0; for (LayerRegion *layerm : layer.regions()) { // Extrusion width accounts for the roundings of the extrudates. // It is the maximum widh of the extrudate. - fw = float(layerm->flow(frExternalPerimeter).scaled_width()); - no_interface_offset = (no_interface_offset == 0.f) ? fw : std::min(no_interface_offset, fw); + float fw = float(layerm->flow(frExternalPerimeter).scaled_width()); lower_layer_offset = (layer_id < (size_t)object_config.support_material_enforce_layers.value) ? // Enforce a full possible support, ignore the overhang angle. @@ -1465,37 +1470,40 @@ static inline std::tuple detect_overhangs( // This step is done before the contact surface is calculated by growing the overhang region. diff_polygons = diff(diff_polygons, annotations.buildplate_covered[layer_id]); } - } else { - if (support_auto) { - // Get the regions needing a suport, collapse very tiny spots. - //FIXME cache the lower layer offset if this layer has multiple regions. -#if 1 - //FIXME this solution will trigger stupid supports for sharp corners, see GH #4874 - diff_polygons = offset2( - diff(layerm_polygons, - offset2(lower_layer_polygons, - 0.5f * fw, lower_layer_offset + 0.5f * fw, SUPPORT_SURFACES_OFFSET_PARAMETERS)), - //FIXME This offset2 is targeted to reduce very thin regions to support, but it may lead to - // no support at all for not so steep overhangs. - - 0.1f * fw, 0.1f * fw); + } else if (support_auto) { + // Get the regions needing a suport, collapse very tiny spots. + //FIXME cache the lower layer offset if this layer has multiple regions. +#if 0 + //FIXME this solution will trigger stupid supports for sharp corners, see GH #4874 + diff_polygons = offset2( + diff(layerm_polygons, + // Likely filtering out thin regions from the lower layer, that will not be covered by perimeters, thus they + // are not supporting this layer. + // However this may lead to a situation where regions at the current layer that are narrow thus not extrudable will generate unnecessary supports. + // For example, see GH issue #3094 + offset2(lower_layer_polygons, - 0.5f * fw, lower_layer_offset + 0.5f * fw, SUPPORT_SURFACES_OFFSET_PARAMETERS)), + //FIXME This offset2 is targeted to reduce very thin regions to support, but it may lead to + // no support at all for not so steep overhangs. + - 0.1f * fw, 0.1f * fw); #else - diff_polygons = - diff(layerm_polygons, - offset(lower_layer_polygons, lower_layer_offset, SUPPORT_SURFACES_OFFSET_PARAMETERS)); + diff_polygons = + diff(layerm_polygons, + offset(lower_layer_polygons, lower_layer_offset, SUPPORT_SURFACES_OFFSET_PARAMETERS)); #endif - if (buildplate_only && ! annotations.buildplate_covered[layer_id].empty()) { - // Don't support overhangs above the top surfaces. - // This step is done before the contact surface is calculated by growing the overhang region. - diff_polygons = diff(diff_polygons, annotations.buildplate_covered[layer_id]); - } - if (! diff_polygons.empty()) { - // Offset the support regions back to a full overhang, restrict them to the full overhang. - // This is done to increase size of the supporting columns below, as they are calculated by - // propagating these contact surfaces downwards. - diff_polygons = diff( - intersection(offset(diff_polygons, lower_layer_offset, SUPPORT_SURFACES_OFFSET_PARAMETERS), layerm_polygons), - lower_layer_polygons); - } + if (buildplate_only && ! annotations.buildplate_covered[layer_id].empty()) { + // Don't support overhangs above the top surfaces. + // This step is done before the contact surface is calculated by growing the overhang region. + diff_polygons = diff(diff_polygons, annotations.buildplate_covered[layer_id]); } + if (! diff_polygons.empty()) { + // Offset the support regions back to a full overhang, restrict them to the full overhang. + // This is done to increase size of the supporting columns below, as they are calculated by + // propagating these contact surfaces downwards. + diff_polygons = diff( + intersection(offset(diff_polygons, lower_layer_offset, SUPPORT_SURFACES_OFFSET_PARAMETERS), layerm_polygons), + lower_layer_polygons); + } + //FIXME add user defined filtering here based on minimal area or minimum radius or whatever. } if (diff_polygons.empty()) @@ -1523,8 +1531,9 @@ static inline std::tuple detect_overhangs( #endif /* SLIC3R_DEBUG */ if (object_config.dont_support_bridges) + //FIXME Expensive, potentially not precise enough. Misses gap fill extrusions, which bridge. SupportMaterialInternal::remove_bridges_from_contacts( - print_config, lower_layer, lower_layer_polygons, layerm, fw, diff_polygons); + print_config, lower_layer, lower_layer_polygons, *layerm, fw, diff_polygons); if (diff_polygons.empty()) continue; @@ -1579,7 +1588,7 @@ static inline std::tuple detect_overhangs( #endif // SLIC3R_DEBUG enforcer_polygons = diff(intersection(layer.lslices, annotations.enforcers_layers[layer_id]), // Inflate just a tiny bit to avoid intersection of the overhang areas with the object. - offset(lower_layer_polygons, 0.05f * fw, SUPPORT_SURFACES_OFFSET_PARAMETERS)); + offset(lower_layer_polygons, 0.05f * no_interface_offset, SUPPORT_SURFACES_OFFSET_PARAMETERS)); #ifdef SLIC3R_DEBUG SVG::export_expolygons(debug_out_path("support-top-contacts-enforcers-run%d-layer%d-z%f.svg", iRun, layer_id, layer.print_z), { { layer.lslices, { "layer.lslices", "gray", 0.2f } }, @@ -1596,6 +1605,8 @@ static inline std::tuple detect_overhangs( return std::make_tuple(std::move(overhang_polygons), std::move(contact_polygons), std::move(enforcer_polygons), no_interface_offset); } +// Allocate one, possibly two support contact layers. +// For "thick" overhangs, one support layer will be generated to support normal extrusions, the other to support the "thick" extrusions. static inline std::pair new_contact_layer( const PrintConfig &print_config, const PrintObjectConfig &object_config, @@ -1708,6 +1719,7 @@ static inline void fill_contact_layer( auto lower_layer_polygons_for_dense_interface = [&lower_layer_polygons_for_dense_interface_cache, &lower_layer_polygons, no_interface_offset]() -> const Polygons& { if (lower_layer_polygons_for_dense_interface_cache.empty()) lower_layer_polygons_for_dense_interface_cache = + //FIXME no_interface_offset * 0.6f offset is not quite correct, one shall derive it based on an angle thus depending on layer height. offset2(lower_layer_polygons, - no_interface_offset * 0.5f, no_interface_offset * (0.6f + 0.5f), SUPPORT_SURFACES_OFFSET_PARAMETERS); return lower_layer_polygons_for_dense_interface_cache; }; @@ -1721,14 +1733,8 @@ static inline void fill_contact_layer( #endif // SLIC3R_DEBUG )); // 2) infill polygons, expand them by half the extrusion width + a tiny bit of extra. - if (layer_id == 0 || slicing_params.soluble_interface) { - // if (no_interface_offset == 0.f) { - new_layer.polygons = support_grid_pattern.extract_support(grid_params.expansion_to_slice, true -#ifdef SLIC3R_DEBUG - , "top_contact_polygons2", iRun, layer_id, layer.print_z -#endif // SLIC3R_DEBUG - ); - } else { + bool reduce_interfaces = layer_id > 0 && ! slicing_params.soluble_interface; + if (reduce_interfaces) { // Reduce the amount of dense interfaces: Do not generate dense interfaces below overhangs with 60% overhang of the extrusions. Polygons dense_interface_polygons = diff(overhang_polygons, lower_layer_polygons_for_dense_interface()); if (! dense_interface_polygons.empty()) { @@ -1746,7 +1752,7 @@ static inline void fill_contact_layer( SupportGridPattern support_grid_pattern(&dense_interface_polygons_trimmed, &slices_margin.polygons, grid_params); new_layer.polygons = support_grid_pattern.extract_support(grid_params.expansion_to_slice, false #ifdef SLIC3R_DEBUG - , "top_contact_polygons3", iRun, layer_id, layer.print_z + , "top_contact_polygons2", iRun, layer_id, layer.print_z #endif // SLIC3R_DEBUG ); #ifdef SLIC3R_DEBUG @@ -1765,45 +1771,59 @@ static inline void fill_contact_layer( { { union_safety_offset_ex(new_layer.polygons) }, { "new_layer.polygons", "red", "black", "", scaled(0.1f), 0.5f } } }); #endif /* SLIC3R_DEBUG */ } + } else { + new_layer.polygons = support_grid_pattern.extract_support(grid_params.expansion_to_slice, true +#ifdef SLIC3R_DEBUG + , "top_contact_polygons3", iRun, layer_id, layer.print_z +#endif // SLIC3R_DEBUG + ); } if (! enforcer_polygons.empty() && ! slices_margin.all_polygons.empty() && layer_id > 0) { // Support enforcers used together with support enforcers. The support enforcers need to be handled separately from the rest of the support. - { - SupportGridPattern support_grid_pattern(&enforcer_polygons, &slices_margin.all_polygons, grid_params); - // 1) Contact polygons will be projected down. To keep the interface and base layers from growing, return a contour a tiny bit smaller than the grid cells. - new_layer.enforcer_polygons = std::make_unique(support_grid_pattern.extract_support(grid_params.expansion_to_propagate, true - #ifdef SLIC3R_DEBUG - , "top_contact_polygons4", iRun, layer_id, layer.print_z - #endif // SLIC3R_DEBUG - )); - } - // 2) infill polygons, expand them by half the extrusion width + a tiny bit of extra. - // Reduce the amount of dense interfaces: Do not generate dense interfaces below overhangs with 60% overhang of the extrusions. - Polygons dense_interface_polygons = diff(enforcer_polygons, lower_layer_polygons_for_dense_interface()); - if (! dense_interface_polygons.empty()) { - dense_interface_polygons = - diff( - // Regularize the contour. - offset(dense_interface_polygons, no_interface_offset * 0.1f), - slices_margin.all_polygons); - // Support islands, to be stretched into a grid. - //FIXME The regularization of dense_interface_polygons above may stretch dense_interface_polygons outside of the contact polygons, - // thus some dense interface areas may not get supported. Trim the excess with contact_polygons at the following line. - // See for example GH #4874. - Polygons dense_interface_polygons_trimmed = intersection(dense_interface_polygons, *new_layer.enforcer_polygons); - SupportGridPattern support_grid_pattern(&dense_interface_polygons_trimmed, &slices_margin.all_polygons, grid_params); - // Extend the polygons to extrude with the contact polygons of support enforcers. - bool needs_union = ! new_layer.polygons.empty(); - append(new_layer.polygons, support_grid_pattern.extract_support(grid_params.expansion_to_slice, false + SupportGridPattern support_grid_pattern(&enforcer_polygons, &slices_margin.all_polygons, grid_params); + // 1) Contact polygons will be projected down. To keep the interface and base layers from growing, return a contour a tiny bit smaller than the grid cells. + new_layer.enforcer_polygons = std::make_unique(support_grid_pattern.extract_support(grid_params.expansion_to_propagate, true #ifdef SLIC3R_DEBUG - , "top_contact_polygons5", iRun, layer_id, layer.print_z + , "top_contact_polygons4", iRun, layer_id, layer.print_z #endif // SLIC3R_DEBUG - )); - if (needs_union) - new_layer.polygons = union_(new_layer.polygons); + )); + Polygons new_polygons; + bool needs_union = ! new_layer.polygons.empty(); + if (reduce_interfaces) { + // 2) infill polygons, expand them by half the extrusion width + a tiny bit of extra. + // Reduce the amount of dense interfaces: Do not generate dense interfaces below overhangs with 60% overhang of the extrusions. + Polygons dense_interface_polygons = diff(enforcer_polygons, lower_layer_polygons_for_dense_interface()); + if (! dense_interface_polygons.empty()) { + dense_interface_polygons = + diff( + // Regularize the contour. + offset(dense_interface_polygons, no_interface_offset * 0.1f), + slices_margin.all_polygons); + // Support islands, to be stretched into a grid. + //FIXME The regularization of dense_interface_polygons above may stretch dense_interface_polygons outside of the contact polygons, + // thus some dense interface areas may not get supported. Trim the excess with contact_polygons at the following line. + // See for example GH #4874. + Polygons dense_interface_polygons_trimmed = intersection(dense_interface_polygons, *new_layer.enforcer_polygons); + SupportGridPattern support_grid_pattern(&dense_interface_polygons_trimmed, &slices_margin.all_polygons, grid_params); + // Extend the polygons to extrude with the contact polygons of support enforcers. + new_polygons = support_grid_pattern.extract_support(grid_params.expansion_to_slice, false + #ifdef SLIC3R_DEBUG + , "top_contact_polygons5", iRun, layer_id, layer.print_z + #endif // SLIC3R_DEBUG + ); + } + } else { + new_polygons = support_grid_pattern.extract_support(grid_params.expansion_to_slice, true + #ifdef SLIC3R_DEBUG + , "top_contact_polygons6", iRun, layer_id, layer.print_z + #endif // SLIC3R_DEBUG + ); } + append(new_layer.polygons, std::move(new_polygons)); + if (needs_union) + new_layer.polygons = union_(new_layer.polygons); } #ifdef SLIC3R_DEBUG @@ -1918,8 +1938,10 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_ // Now apply the contact areas to the layer where they need to be made. if (! contact_polygons.empty()) { + // Allocate the two empty layers. auto [new_layer, bridging_layer] = new_contact_layer(*m_print_config, *m_object_config, m_slicing_params, m_support_params.support_layer_height_min, layer, layer_storage, layer_storage_mutex); if (new_layer) { + // Fill the non-bridging layer with polygons. fill_contact_layer(*new_layer, layer_id, m_slicing_params, *m_object_config, slices_margin, overhang_polygons, contact_polygons, enforcer_polygons, lower_layer_polygons, m_support_params.support_material_flow, no_interface_offset @@ -1927,6 +1949,9 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_ , iRun, layer #endif // SLIC3R_DEBUG ); + // Insert new layer even if there is no interface generated: Likely the support angle is not steep enough to require dense interface, + // however generating a sparse support will be useful for the object stability. + // if (! new_layer->polygons.empty()) contact_out[layer_id * 2] = new_layer; if (bridging_layer != nullptr) { bridging_layer->polygons = new_layer->polygons; @@ -1944,6 +1969,8 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_ // Compress contact_out, remove the nullptr items. remove_nulls(contact_out); + // Merge close contact layers conservatively: If two layers are closer than the minimum allowed print layer height (the min_layer_height parameter), + // the top contact layer is merged into the bottom contact layer. merge_contact_layers(m_slicing_params, m_support_params.support_layer_height_min, contact_out); BOOST_LOG_TRIVIAL(debug) << "PrintObjectSupportMaterial::top_contact_layers() in parallel - end"; @@ -2709,6 +2736,7 @@ void PrintObjectSupportMaterial::generate_base_layers( ApplySafetyOffset::Yes); // safety offset to merge the touching source polygons layer_intermediate.layer_type = sltBase; + // For snug supports, expand the interfaces into the intermediate layer to make it printable. #if 0 // coordf_t fillet_radius_scaled = scale_(m_object_config->support_material_spacing); // Fillet the base polygons and trim them again with the top, interface and contact layers. @@ -2981,6 +3009,7 @@ std::pairsupport_material_interface_extruder.value > 0 && m_print_config->filament_soluble.get_at(m_object_config->support_material_interface_extruder.value - 1) && // Base extruder: Either "print with active extruder" not soluble. (m_object_config->support_material_extruder.value == 0 || ! m_print_config->filament_soluble.get_at(m_object_config->support_material_extruder.value - 1)); + bool snug_supports = m_object_config->support_material_style.value == smsSnug; int num_interface_layers_top = m_object_config->support_material_interface_layers; int num_interface_layers_bottom = m_object_config->support_material_bottom_interface_layers; if (num_interface_layers_bottom < 0) @@ -3023,7 +3052,7 @@ std::pair(0, int(intermediate_layers.size())), [&bottom_contacts, &top_contacts, &intermediate_layers, &insert_layer, num_interface_layers_top, num_interface_layers_bottom, num_base_interface_layers_top, num_base_interface_layers_bottom, num_interface_layers_only_top, num_interface_layers_only_bottom, - &interface_layers, &base_interface_layers](const tbb::blocked_range& range) { + snug_supports, &interface_layers, &base_interface_layers](const tbb::blocked_range& range) { // Gather the top / bottom contact layers intersecting with num_interface_layers resp. num_interface_layers_only intermediate layers above / below // this intermediate layer. // Index of the first top contact layer intersecting the current intermediate layer. @@ -3055,7 +3084,10 @@ std::pair top_z) break; - polygons_append(top_contact_layer.bottom_z - EPSILON > top_inteface_z ? polygons_top_contact_projected_base : polygons_top_contact_projected_interface, top_contact_layer.polygons); + polygons_append(top_contact_layer.bottom_z - EPSILON > top_inteface_z ? polygons_top_contact_projected_base : polygons_top_contact_projected_interface, + // For snug supports, project the overhang polygons covering the whole overhang, so that they will merge without a gap with support polygons of the other layers. + // For grid supports, merging of support regions will be performed by the projection into grid. + snug_supports ? *top_contact_layer.overhang_polygons : top_contact_layer.polygons); } } if (num_interface_layers_bottom > 0) { @@ -3799,7 +3831,7 @@ void PrintObjectSupportMaterial::generate_toolpaths( // Prepare fillers. SupportMaterialPattern support_pattern = m_object_config->support_material_pattern; bool with_sheath = m_object_config->support_material_with_sheath; - InfillPattern infill_pattern = support_pattern == smpHoneycomb ? ipHoneycomb : (support_density < 1.05 ? ipRectilinear : ipSupportBase); + InfillPattern infill_pattern = support_pattern == smpHoneycomb ? ipHoneycomb : (support_density > 0.95 ? ipRectilinear : ipSupportBase); std::vector angles; angles.push_back(base_angle); From 7b0d90f489bc951c61b22227dddaf33531da9f60 Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Thu, 7 Oct 2021 15:40:28 +0200 Subject: [PATCH 040/102] Reworded "Shape Gallery" menu and dialog title --- src/slic3r/GUI/GalleryDialog.cpp | 2 +- src/slic3r/GUI/MainFrame.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/GalleryDialog.cpp b/src/slic3r/GUI/GalleryDialog.cpp index 5429e2658..6230f1c02 100644 --- a/src/slic3r/GUI/GalleryDialog.cpp +++ b/src/slic3r/GUI/GalleryDialog.cpp @@ -66,7 +66,7 @@ bool GalleryDropTarget::OnDropFiles(wxCoord x, wxCoord y, const wxArrayString& f GalleryDialog::GalleryDialog(wxWindow* parent, bool modify_gallery/* = false*/) : - DPIDialog(parent, wxID_ANY, _L("Shapes Gallery"), wxDefaultPosition, wxSize(45 * wxGetApp().em_unit(), -1), wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) + DPIDialog(parent, wxID_ANY, _L("Shape Gallery"), wxDefaultPosition, wxSize(45 * wxGetApp().em_unit(), -1), wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) { #ifndef _WIN32 SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index 66e22c694..799c4e793 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -1400,7 +1400,7 @@ void MainFrame::init_menubar_as_editor() } windowMenu->AppendSeparator(); - append_menu_item(windowMenu, wxID_ANY, _L("Modify Shapes Gallery"), _L("Open the dialog to modify shapes gallery"), + append_menu_item(windowMenu, wxID_ANY, _L("Shape Gallery"), _L("Open the dialog to modify shape gallery"), [this](wxCommandEvent&) { GalleryDialog dlg(this, true); if (dlg.ShowModal() == wxID_OK) { From ce397a0c5cf722646b089f86e87a96b9801b5d37 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Fri, 8 Oct 2021 09:04:42 +0200 Subject: [PATCH 041/102] ShapeGallery: Added more system shapes --- resources/shapes/M3_hex_nut.png | Bin 0 -> 6946 bytes resources/shapes/M3_hex_nut.stl | Bin 0 -> 31084 bytes resources/shapes/M3x10_screw.png | Bin 0 -> 13644 bytes resources/shapes/M3x10_screw.stl | Bin 0 -> 776684 bytes resources/shapes/cone.png | Bin 0 -> 8964 bytes resources/shapes/cone.stl | Bin 0 -> 25584 bytes resources/shapes/helper_disk.png | Bin 0 -> 4380 bytes resources/shapes/helper_disk.stl | Bin 0 -> 37284 bytes resources/shapes/torus.png | Bin 0 -> 18433 bytes resources/shapes/torus.stl | Bin 0 -> 153684 bytes 10 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 resources/shapes/M3_hex_nut.png create mode 100644 resources/shapes/M3_hex_nut.stl create mode 100644 resources/shapes/M3x10_screw.png create mode 100644 resources/shapes/M3x10_screw.stl create mode 100644 resources/shapes/cone.png create mode 100644 resources/shapes/cone.stl create mode 100644 resources/shapes/helper_disk.png create mode 100644 resources/shapes/helper_disk.stl create mode 100644 resources/shapes/torus.png create mode 100644 resources/shapes/torus.stl diff --git a/resources/shapes/M3_hex_nut.png b/resources/shapes/M3_hex_nut.png new file mode 100644 index 0000000000000000000000000000000000000000..26dbb634ce93dacc0f7bc7e0bb0bccd131b20597 GIT binary patch literal 6946 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 T+${rtdI1J{_jJp3>|XvKT2hRW literal 0 HcmV?d00001 diff --git a/resources/shapes/M3_hex_nut.stl b/resources/shapes/M3_hex_nut.stl new file mode 100644 index 0000000000000000000000000000000000000000..2be83170533055388969b6992a4d2355e9215447 GIT binary patch literal 31084 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 literal 0 HcmV?d00001 diff --git a/resources/shapes/M3x10_screw.png b/resources/shapes/M3x10_screw.png new file mode 100644 index 0000000000000000000000000000000000000000..623efd4604aa9422b864e6e4466430bab05b8bf1 GIT binary patch literal 13644 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 TEEw>56m2}x^TiXyEwL_-us zW{~rQDrzSst))mwTU9MZX_4P`&zx}0=j+d3UoWrke7@KHp6e{nxzBUo=Q$Ib?f>t8 zn_Adx6WTS^i?+89UDl%n3xVk>sezlRewTTbGQOQFpWZG<7 zERVtqU(o|rZ7`+`3s$T!u{E+t=H<&NmPe(N<#oj6!^Z95O?(KBidE0P z8?0DiqUe8FI(g{tmPhLbx6G*c;;QYdO?(KB!aithahUg<_lUb--U@g@)&473vBJdT znp^ep@IpA>a?TsRdBiMRrGom|uZa)g8?{B_$Xgy6CB8QQ@T;V@-w(!iK2?|qyF62m z>E&m6OwV3zeo+23brl{=a1_Rr#t5=JI@e7!!=A6H>R>-uVd8}&t+jidzvU59dx&|c zVLjCb$BGG#!nL7sC0HKAKd5I0T&Sm};e4>dM3Isg%pQ*`Sspu9`I+NeHBoZTncyg7 z2ou+*)!BO>ZKCXc?XL+2T zf2hUmNlnybTpz43(QC|fqxB~NmdDm(M(Ffg&D29&gG_LgWV)yO(fIm<(Cu{^sr|Ul zSz+Rpb`{l?trabgo6q|h%@P}{Uy)0g;3&yePtV8FGrf%RqwA_Lqf3HF2qz*NyzQ2FwwvN3YAu`xaCp2<0@lFVl^e1 znhD>iEs|%f^D*e1?~JHT{;DGg$zu5m6OwtJUbSz%a@bgq^^*D=Tg3_!YoGr{bxMAK zZjS2ASX}*$46WW}mGmimS-BzZeHGN?2jyUJYB=`DVK;k1NZ|t47NXd+r8IaFiUs zr+0%1ohqm;-Ap4Eqn#BduADCsmauD)weh$2Zt�I7&u{oL%pJoc*D? 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�cNyQ1aj`nfI;zzHDLQhbuA4 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ς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 literal 0 HcmV?d00001 diff --git a/resources/shapes/helper_disk.png b/resources/shapes/helper_disk.png new file mode 100644 index 0000000000000000000000000000000000000000..602f33cbf66724583dec4f5ae426380a91f1ca53 GIT binary patch literal 4380 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 F^naZ=Lk$1` literal 0 HcmV?d00001 diff --git a/resources/shapes/helper_disk.stl b/resources/shapes/helper_disk.stl new file mode 100644 index 0000000000000000000000000000000000000000..94ab0739c9a0d012e26a472790c8fdc9f3f0b07d GIT binary patch literal 37284 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 literal 0 HcmV?d00001 diff --git a/resources/shapes/torus.png b/resources/shapes/torus.png new file mode 100644 index 0000000000000000000000000000000000000000..16e8bac5a0750eb1bfe891d976ceac5648bdce09 GIT binary patch literal 18433 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 literal 0 HcmV?d00001 diff --git a/resources/shapes/torus.stl b/resources/shapes/torus.stl new file mode 100644 index 0000000000000000000000000000000000000000..997fd44b531a0a1371acb409e4d6c42b1612e0e3 GIT binary patch literal 153684 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 Date: Fri, 8 Oct 2021 10:48:46 +0200 Subject: [PATCH 042/102] #7076 - Modifiers and similar objects always rendered as transparent --- src/libslic3r/Technologies.hpp | 9 +++++++++ src/slic3r/GUI/3DScene.cpp | 14 ++++++++++++++ src/slic3r/GUI/GLCanvas3D.cpp | 2 ++ src/slic3r/GUI/Selection.cpp | 14 ++++++++++++++ 4 files changed, 39 insertions(+) diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index 350f6aedc..acbb4731d 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -73,4 +73,13 @@ #define ENABLE_FIX_SUPERSLICER_GCODE_IMPORT (1 && ENABLE_2_4_0_ALPHA3) +//==================== +// 2.4.0.alpha4 techs +//==================== +#define ENABLE_2_4_0_ALPHA4 1 + +// Enable rendering modifiers and similar objects always as transparent +#define ENABLE_MODIFIERS_ALWAYS_TRANSPARENT (1 && ENABLE_2_4_0_ALPHA4) + + #endif // _prusaslicer_technologies_h_ diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index dfc10658d..27eb69363 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -464,9 +464,15 @@ std::array color_from_model_volume(const ModelVolume& model_volume) color[2] = 0.2f; } else if (model_volume.is_modifier()) { +#if ENABLE_MODIFIERS_ALWAYS_TRANSPARENT + color[0] = 1.0f; + color[1] = 1.0f; + color[2] = 0.2f; +#else color[0] = 0.2f; color[1] = 1.0f; color[2] = 0.2f; +#endif // ENABLE_MODIFIERS_ALWAYS_TRANSPARENT } else if (model_volume.is_support_blocker()) { color[0] = 1.0f; @@ -836,7 +842,15 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type, bool disab glsafe(::glDisable(GL_CULL_FACE)); for (GLVolumeWithIdAndZ& volume : to_render) { +#if ENABLE_MODIFIERS_ALWAYS_TRANSPARENT + if (type == ERenderType::Transparent) + volume.first->force_transparent = true; +#endif // ENABLE_MODIFIERS_ALWAYS_TRANSPARENT volume.first->set_render_color(); +#if ENABLE_MODIFIERS_ALWAYS_TRANSPARENT + if (type == ERenderType::Transparent) + volume.first->force_transparent = false; +#endif // ENABLE_MODIFIERS_ALWAYS_TRANSPARENT // render sinking contours of non-hovered volumes if (m_show_sinking_contours) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index d42bc26dc..37fb7995b 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1286,12 +1286,14 @@ bool GLCanvas3D::is_reload_delayed() const void GLCanvas3D::enable_layers_editing(bool enable) { m_layers_editing.set_enabled(enable); +#if !ENABLE_MODIFIERS_ALWAYS_TRANSPARENT const Selection::IndicesList& idxs = m_selection.get_volume_idxs(); for (unsigned int idx : idxs) { GLVolume* v = m_volumes.volumes[idx]; if (v->is_modifier) v->force_transparent = enable; } +#endif // !ENABLE_MODIFIERS_ALWAYS_TRANSPARENT set_as_dirty(); } diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index 3ab9b7bdc..6a82ca8d3 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -444,11 +444,25 @@ void Selection::clear() if (m_list.empty()) return; +#if ENABLE_MODIFIERS_ALWAYS_TRANSPARENT + // ensure that the volumes get the proper color before next call to render (expecially needed for transparent volumes) + for (unsigned int i : m_list) { + GLVolume& volume = *(*m_volumes)[i]; + volume.selected = false; + bool transparent = volume.color[3] < 1.0f; + if (transparent) + volume.force_transparent = true; + volume.set_render_color(); + if (transparent) + volume.force_transparent = false; + } +#else for (unsigned int i : m_list) { (*m_volumes)[i]->selected = false; // ensure the volume gets the proper color before next call to render (expecially needed for transparent volumes) (*m_volumes)[i]->set_render_color(); } +#endif // ENABLE_MODIFIERS_ALWAYS_TRANSPARENT m_list.clear(); From c921d6f9368af922cb3c4b209e3dadf94116f41c Mon Sep 17 00:00:00 2001 From: YuSanka Date: Fri, 8 Oct 2021 12:14:49 +0200 Subject: [PATCH 043/102] ObjectList: Fixed positioning of the object's part/modifiers when it's added Use load_modifier() for everything without a respect to the type --- src/slic3r/GUI/GUI_ObjectList.cpp | 15 +++++++++------ src/slic3r/GUI/GUI_ObjectList.hpp | 3 ++- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index e6e7336f7..83f9d1ec1 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -1405,9 +1405,11 @@ void ObjectList::load_subobject(ModelVolumeType type, bool from_galery/* = false item = m_objects_model->GetItemById(obj_idx); std::vector volumes; + // ! ysFIXME - delete commented code after testing and rename "load_modifier" to something common + /* if (type == ModelVolumeType::MODEL_PART) load_part(*(*m_objects)[obj_idx], volumes, type, from_galery); - else + else*/ load_modifier(*(*m_objects)[obj_idx], volumes, type, from_galery); if (volumes.empty()) @@ -1430,8 +1432,8 @@ void ObjectList::load_subobject(ModelVolumeType type, bool from_galery/* = false selection_changed(); } - -void ObjectList::load_part(ModelObject& model_object, std::vector& added_volumes, ModelVolumeType type, bool from_galery/* = false*/) +/* +void ObjectList::load_part(ModelObject& model_object, std::vector& added_volumes, ModelVolumeType type, bool from_galery/* = false* /) { if (type != ModelVolumeType::MODEL_PART) return; @@ -1489,11 +1491,12 @@ void ObjectList::load_part(ModelObject& model_object, std::vector& } } } - +*/ void ObjectList::load_modifier(ModelObject& model_object, std::vector& added_volumes, ModelVolumeType type, bool from_galery) { - if (type == ModelVolumeType::MODEL_PART) - return; + // ! ysFIXME - delete commented code after testing and rename "load_modifier" to something common + //if (type == ModelVolumeType::MODEL_PART) + // return; wxWindow* parent = wxGetApp().tab_panel()->GetPage(0); diff --git a/src/slic3r/GUI/GUI_ObjectList.hpp b/src/slic3r/GUI/GUI_ObjectList.hpp index cc619fc45..535bfa7a7 100644 --- a/src/slic3r/GUI/GUI_ObjectList.hpp +++ b/src/slic3r/GUI/GUI_ObjectList.hpp @@ -249,7 +249,8 @@ public: bool is_instance_or_object_selected(); void load_subobject(ModelVolumeType type, bool from_galery = false); - void load_part(ModelObject& model_object, std::vector& added_volumes, ModelVolumeType type, bool from_galery = false); + // ! ysFIXME - delete commented code after testing and rename "load_modifier" to something common + //void load_part(ModelObject& model_object, std::vector& added_volumes, ModelVolumeType type, bool from_galery = false); void load_modifier(ModelObject& model_object, std::vector& added_volumes, ModelVolumeType type, bool from_galery = false); void load_generic_subobject(const std::string& type_name, const ModelVolumeType type); void load_shape_object(const std::string &type_name); From e1104d5f7df3a33936b78235007252bef4b33e46 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Mon, 11 Oct 2021 09:54:38 +0200 Subject: [PATCH 044/102] Win11 specific: Added workaround for implicit set of the dark mode --- src/slic3r/GUI/GUI_App.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index e2a9df25d..4b5235ec9 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -865,8 +865,11 @@ bool GUI_App::on_init_inner() wxInitAllImageHandlers(); #ifdef _MSW_DARK_MODE - if (app_config->get("dark_color_mode") == "1") + if (bool dark_mode = app_config->get("dark_color_mode") == "1") { NppDarkMode::InitDarkMode(); + if (dark_mode != NppDarkMode::IsDarkMode()) + NppDarkMode::SetDarkMode(dark_mode); + } #endif SplashScreen* scrn = nullptr; if (app_config->get("show_splash_screen") == "1") { From c4f78fcdc9b5fc586e32536bd046037c2494e9cf Mon Sep 17 00:00:00 2001 From: David Kocik Date: Mon, 11 Oct 2021 09:44:22 +0200 Subject: [PATCH 045/102] Check version string for alpha and beta release versions. Preferences setting to show / not show alpha beta releases. --- src/libslic3r/AppConfig.cpp | 3 ++ src/slic3r/GUI/GUI_App.cpp | 19 ++++++++ src/slic3r/GUI/NotificationManager.cpp | 4 ++ src/slic3r/GUI/NotificationManager.hpp | 3 ++ src/slic3r/GUI/Preferences.cpp | 7 +++ src/slic3r/Utils/PresetUpdater.cpp | 62 +++++++++++++++++++++----- src/slic3r/Utils/PresetUpdater.hpp | 4 +- 7 files changed, 88 insertions(+), 14 deletions(-) diff --git a/src/libslic3r/AppConfig.cpp b/src/libslic3r/AppConfig.cpp index fd2c4f865..bf5ecc7f5 100644 --- a/src/libslic3r/AppConfig.cpp +++ b/src/libslic3r/AppConfig.cpp @@ -122,6 +122,9 @@ void AppConfig::set_defaults() if (get("auto_toolbar_size").empty()) set("auto_toolbar_size", "100"); + + if (get("notify_testing_release").empty()) + set("notify_testing_release", "1"); #if ENABLE_ENVIRONMENT_MAP if (get("use_environment_map").empty()) set("use_environment_map", "0"); diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 4b5235ec9..a21054201 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -918,6 +918,25 @@ bool GUI_App::on_init_inner() } } }); + Bind(EVT_SLIC3R_ALPHA_VERSION_ONLINE, [this](const wxCommandEvent& evt) { + //app_config->set("version_alpha_online", into_u8(evt.GetString())); + app_config->save(); + if (this->plater_ != nullptr && app_config->get("notify_testing_release") == "1") { + if (*Semver::parse(SLIC3R_VERSION) < *Semver::parse(into_u8(evt.GetString()))) { + this->plater_->get_notification_manager()->push_notification(NotificationType::NewAlphaAvailable); + } + } + }); + Bind(EVT_SLIC3R_BETA_VERSION_ONLINE, [this](const wxCommandEvent& evt) { + //app_config->set("version_beta_online", into_u8(evt.GetString())); + app_config->save(); + if (this->plater_ != nullptr && app_config->get("notify_testing_release") == "1") { + if (*Semver::parse(SLIC3R_VERSION) < *Semver::parse(into_u8(evt.GetString()))) { + this->plater_->get_notification_manager()->close_notification_of_type(NotificationType::NewAlphaAvailable); + this->plater_->get_notification_manager()->push_notification(NotificationType::NewBetaAvailable); + } + } + }); } else { #ifdef __WXMSW__ diff --git a/src/slic3r/GUI/NotificationManager.cpp b/src/slic3r/GUI/NotificationManager.cpp index ed6f11ddb..b12256cf0 100644 --- a/src/slic3r/GUI/NotificationManager.cpp +++ b/src/slic3r/GUI/NotificationManager.cpp @@ -43,6 +43,10 @@ const NotificationManager::NotificationData NotificationManager::basic_notificat }, {NotificationType::NewAppAvailable, NotificationLevel::ImportantNotificationLevel, 20, _u8L("New version is available."), _u8L("See Releases page."), [](wxEvtHandler* evnthndlr) { wxGetApp().open_browser_with_warning_dialog("https://github.com/prusa3d/PrusaSlicer/releases"); return true; }}, + {NotificationType::NewAlphaAvailable, NotificationLevel::ImportantNotificationLevel, 20, _u8L("New alpha release is available."), _u8L("See Releases page."), [](wxEvtHandler* evnthndlr) { + wxGetApp().open_browser_with_warning_dialog("https://github.com/prusa3d/PrusaSlicer/releases"); return true; }}, + {NotificationType::NewBetaAvailable, NotificationLevel::ImportantNotificationLevel, 20, _u8L("New beta release is available."), _u8L("See Releases page."), [](wxEvtHandler* evnthndlr) { + wxGetApp().open_browser_with_warning_dialog("https://github.com/prusa3d/PrusaSlicer/releases"); return true; }}, {NotificationType::EmptyColorChangeCode, NotificationLevel::PrintInfoNotificationLevel, 10, _u8L("You have just added a G-code for color change, but its value is empty.\n" "To export the G-code correctly, check the \"Color Change G-code\" in \"Printer Settings > Custom G-code\"") }, diff --git a/src/slic3r/GUI/NotificationManager.hpp b/src/slic3r/GUI/NotificationManager.hpp index ad2e315b7..00065f795 100644 --- a/src/slic3r/GUI/NotificationManager.hpp +++ b/src/slic3r/GUI/NotificationManager.hpp @@ -52,6 +52,9 @@ enum class NotificationType // Notification on the start of PrusaSlicer, when a new PrusaSlicer version is published. // Contains a hyperlink to open a web browser pointing to the PrusaSlicer download location. NewAppAvailable, + // Like NewAppAvailable but with text and link for alpha / bet release + NewAlphaAvailable, + NewBetaAvailable, // Notification on the start of PrusaSlicer, when updates of system profiles are detected. // Contains a hyperlink to execute installation of the new system profiles. PresetUpdateAvailable, diff --git a/src/slic3r/GUI/Preferences.cpp b/src/slic3r/GUI/Preferences.cpp index 9d1236922..e7ecb0547 100644 --- a/src/slic3r/GUI/Preferences.cpp +++ b/src/slic3r/GUI/Preferences.cpp @@ -375,6 +375,13 @@ void PreferencesDialog::build(size_t selected_tab) def.set_default_value(new ConfigOptionBool{ app_config->get("use_custom_toolbar_size") == "1" }); option = Option(def, "use_custom_toolbar_size"); m_optgroup_gui->append_single_option_line(option); + + def.label = L("Notify about testing releases"); + def.type = coBool; + def.tooltip = L("If enabled, you will be notified about alpha / beta releases available for download."); + def.set_default_value(new ConfigOptionBool{ app_config->get("notify_testing_release") == "1" }); + option = Option(def, "notify_testing_release"); + m_optgroup_gui->append_single_option_line(option); } activate_options_tab(m_optgroup_gui); diff --git a/src/slic3r/Utils/PresetUpdater.cpp b/src/slic3r/Utils/PresetUpdater.cpp index 97c6cb2a5..f20ddb147 100644 --- a/src/slic3r/Utils/PresetUpdater.cpp +++ b/src/slic3r/Utils/PresetUpdater.cpp @@ -141,7 +141,8 @@ struct Updates wxDEFINE_EVENT(EVT_SLIC3R_VERSION_ONLINE, wxCommandEvent); - +wxDEFINE_EVENT(EVT_SLIC3R_ALPHA_VERSION_ONLINE, wxCommandEvent); +wxDEFINE_EVENT(EVT_SLIC3R_BETA_VERSION_ONLINE, wxCommandEvent); struct PresetUpdater::priv { @@ -262,21 +263,58 @@ void PresetUpdater::priv::sync_version() const }) .on_complete([&](std::string body, unsigned /* http_status */) { boost::trim(body); - const auto nl_pos = body.find_first_of("\n\r"); - if (nl_pos != std::string::npos) { - body.resize(nl_pos); - } - - if (! Semver::parse(body)) { - BOOST_LOG_TRIVIAL(warning) << format("Received invalid contents from `%1%`: Not a correct semver: `%2%`", SLIC3R_APP_NAME, body); + // release version + std::string version; + const auto first_nl_pos = body.find_first_of("\n\r"); + if (first_nl_pos != std::string::npos) + version = body.substr(0,first_nl_pos); + else + version = body; + if (! Semver::parse(version)) { + BOOST_LOG_TRIVIAL(warning) << format("Received invalid contents from `%1%`: Not a correct semver: `%2%`", SLIC3R_APP_NAME, version); return; } - - BOOST_LOG_TRIVIAL(info) << format("Got %1% online version: `%2%`. Sending to GUI thread...", SLIC3R_APP_NAME, body); - + BOOST_LOG_TRIVIAL(info) << format("Got %1% online version: `%2%`. Sending to GUI thread...", SLIC3R_APP_NAME, version); wxCommandEvent* evt = new wxCommandEvent(EVT_SLIC3R_VERSION_ONLINE); - evt->SetString(GUI::from_u8(body)); + evt->SetString(GUI::from_u8(version)); GUI::wxGetApp().QueueEvent(evt); + + // alpha / beta version + size_t nexn_nl_pos = first_nl_pos; + while (nexn_nl_pos != std::string::npos && body.size() > nexn_nl_pos + 1) { + const auto last_nl_pos = nexn_nl_pos; + nexn_nl_pos = body.find_first_of("\n\r", last_nl_pos + 1); + std::string line; + if (nexn_nl_pos == std::string::npos) + line = body.substr(last_nl_pos + 1); + else + line = body.substr(last_nl_pos + 1, nexn_nl_pos - last_nl_pos - 1); + + // alpha + if (line.substr(0, 6) == "alpha=") { + version = line.substr(6); + if (!Semver::parse(version)) { + BOOST_LOG_TRIVIAL(warning) << format("Received invalid contents for alpha release from `%1%`: Not a correct semver: `%2%`", SLIC3R_APP_NAME, version); + return; + } + BOOST_LOG_TRIVIAL(info) << format("Got %1% online version of alpha release: `%2%`. Sending to GUI thread...", SLIC3R_APP_NAME, version); + wxCommandEvent* evt = new wxCommandEvent(EVT_SLIC3R_ALPHA_VERSION_ONLINE); + evt->SetString(GUI::from_u8(version)); + GUI::wxGetApp().QueueEvent(evt); + + // beta + } else if (line.substr(0, 5) == "beta=") { + version = line.substr(5); + if (!Semver::parse(version)) { + BOOST_LOG_TRIVIAL(warning) << format("Received invalid contents for beta release from `%1%`: Not a correct semver: `%2%`", SLIC3R_APP_NAME, version); + return; + } + BOOST_LOG_TRIVIAL(info) << format("Got %1% online version of beta release: `%2%`. Sending to GUI thread...", SLIC3R_APP_NAME, version); + wxCommandEvent* evt = new wxCommandEvent(EVT_SLIC3R_BETA_VERSION_ONLINE); + evt->SetString(GUI::from_u8(version)); + GUI::wxGetApp().QueueEvent(evt); + } + } }) .perform_sync(); } diff --git a/src/slic3r/Utils/PresetUpdater.hpp b/src/slic3r/Utils/PresetUpdater.hpp index d7eeb5604..b7937c574 100644 --- a/src/slic3r/Utils/PresetUpdater.hpp +++ b/src/slic3r/Utils/PresetUpdater.hpp @@ -61,7 +61,7 @@ private: }; wxDECLARE_EVENT(EVT_SLIC3R_VERSION_ONLINE, wxCommandEvent); - - +wxDECLARE_EVENT(EVT_SLIC3R_ALPHA_VERSION_ONLINE, wxCommandEvent); +wxDECLARE_EVENT(EVT_SLIC3R_BETA_VERSION_ONLINE, wxCommandEvent); } #endif From b39eb7f222e567eb49b95e4e6230827adb9fc469 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Mon, 11 Oct 2021 11:21:05 +0200 Subject: [PATCH 046/102] Gallery: Fixed a naming of the added item with already existing name. + Fixed layout after add/delete item to/from Gallery --- src/slic3r/GUI/GalleryDialog.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/slic3r/GUI/GalleryDialog.cpp b/src/slic3r/GUI/GalleryDialog.cpp index 6230f1c02..fef131b88 100644 --- a/src/slic3r/GUI/GalleryDialog.cpp +++ b/src/slic3r/GUI/GalleryDialog.cpp @@ -66,7 +66,7 @@ bool GalleryDropTarget::OnDropFiles(wxCoord x, wxCoord y, const wxArrayString& f GalleryDialog::GalleryDialog(wxWindow* parent, bool modify_gallery/* = false*/) : - DPIDialog(parent, wxID_ANY, _L("Shape Gallery"), wxDefaultPosition, wxSize(45 * wxGetApp().em_unit(), -1), wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) + DPIDialog(parent, wxID_ANY, _L("Shape Gallery"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) { #ifndef _WIN32 SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); @@ -75,7 +75,7 @@ GalleryDialog::GalleryDialog(wxWindow* parent, bool modify_gallery/* = false*/) wxStaticText* label_top = new wxStaticText(this, wxID_ANY, _L("Select shape from the gallery") + ":"); - m_list_ctrl = new wxListCtrl(this, wxID_ANY, wxDefaultPosition, wxSize(55 * wxGetApp().em_unit(), 35 * wxGetApp().em_unit()), + m_list_ctrl = new wxListCtrl(this, wxID_ANY, wxDefaultPosition, wxSize(50 * wxGetApp().em_unit(), 35 * wxGetApp().em_unit()), wxLC_ICON | wxSIMPLE_BORDER); m_list_ctrl->Bind(wxEVT_LIST_ITEM_SELECTED, &GalleryDialog::select, this); m_list_ctrl->Bind(wxEVT_LIST_ITEM_DESELECTED, &GalleryDialog::deselect, this); @@ -152,7 +152,7 @@ void GalleryDialog::on_dpi_changed(const wxRect& suggested_rect) msw_buttons_rescale(this, em, { ID_BTN_ADD_CUSTOM_SHAPE, ID_BTN_DEL_CUSTOM_SHAPE, ID_BTN_REPLACE_CUSTOM_PNG, wxID_OK, wxID_CLOSE }); - wxSize size = wxSize(55 * em, 35 * em); + wxSize size = wxSize(50 * em, 35 * em); m_list_ctrl->SetMinSize(size); m_list_ctrl->SetSize(size); @@ -461,8 +461,11 @@ void GalleryDialog::replace_custom_png(wxEvent& event) } try { + fs::path png_path = fs::path(get_dir(false) / m_selected_items[0].name); + png_path.replace_extension("png"); + fs::path current = fs::path(into_u8(input_files.Item(0))); - fs::copy_file(current, get_dir(false) / (m_selected_items[0].name + ".png"), fs::copy_option::overwrite_if_exists); + fs::copy_file(current, png_path, fs::copy_option::overwrite_if_exists); } catch (fs::filesystem_error const& e) { std::cerr << e.what() << '\n'; @@ -535,12 +538,12 @@ bool GalleryDialog::load_files(const wxArrayString& input_files) if (!fs::exists(dest_dir / current.filename())) fs::copy_file(current, dest_dir / current.filename()); else { - std::string filename = current.filename().string(); + std::string filename = current.stem().string(); int file_idx = 0; for (auto& dir_entry : fs::directory_iterator(dest_dir)) if (is_gallery_file(dir_entry, ".stl") || is_gallery_file(dir_entry, ".obj")) { - std::string name = dir_entry.path().filename().string(); + std::string name = dir_entry.path().stem().string(); if (filename == name) { if (file_idx == 0) file_idx++; From e28ebf9386c5e9482b1c5859adbf6860aedb6f85 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 12 Oct 2021 09:53:23 +0200 Subject: [PATCH 047/102] Removed threshold to detect seams to be shown in preview --- src/libslic3r/GCode/GCodeProcessor.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libslic3r/GCode/GCodeProcessor.cpp b/src/libslic3r/GCode/GCodeProcessor.cpp index 9c90535c4..c5471911a 100644 --- a/src/libslic3r/GCode/GCodeProcessor.cpp +++ b/src/libslic3r/GCode/GCodeProcessor.cpp @@ -2671,12 +2671,12 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line) const Vec3f curr_pos(m_end_position[X], m_end_position[Y], m_end_position[Z]); const Vec3f new_pos = m_result.moves.back().position - m_extruder_offsets[m_extruder_id]; const std::optional first_vertex = m_seams_detector.get_first_vertex(); - // the threshold value = 0.0625f == 0.25 * 0.25 is arbitrary, we may find some smarter condition later - if ((new_pos - *first_vertex).squaredNorm() < 0.0625f) { +// // the threshold value = 0.0625f == 0.25 * 0.25 is arbitrary, we may find some smarter condition later +// if ((new_pos - *first_vertex).squaredNorm() < 0.0625f) { set_end_position(0.5f * (new_pos + *first_vertex)); store_move_vertex(EMoveType::Seam); set_end_position(curr_pos); - } +// } m_seams_detector.activate(false); } From 94843bb6bf1a99af6fafcc21a81912dd3dff71e7 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Tue, 12 Oct 2021 09:58:45 +0200 Subject: [PATCH 048/102] Removing search for upstream miniz as its no longer compatible. Due to 729298c40854e97dbaf051316f789dbd2f873a31 fixes #7080 --- src/miniz/CMakeLists.txt | 34 ++++++++++------------------------ 1 file changed, 10 insertions(+), 24 deletions(-) diff --git a/src/miniz/CMakeLists.txt b/src/miniz/CMakeLists.txt index a664f7460..04d562b76 100644 --- a/src/miniz/CMakeLists.txt +++ b/src/miniz/CMakeLists.txt @@ -3,29 +3,15 @@ project(miniz) add_library(miniz INTERFACE) -if(NOT SLIC3R_STATIC OR CMAKE_SYSTEM_NAME STREQUAL "Linux") - find_package(miniz 2.1 QUIET) -endif() - -if(miniz_FOUND) - - message(STATUS "Using system miniz...") - target_link_libraries(miniz INTERFACE miniz::miniz) - -else() - - add_library(miniz_static STATIC - miniz.c - miniz.h - ) - - if(${CMAKE_C_COMPILER_ID} STREQUAL "GNU") - target_compile_definitions(miniz_static PRIVATE _GNU_SOURCE) - endif() - - target_link_libraries(miniz INTERFACE miniz_static) - target_include_directories(miniz INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) - - message(STATUS "Miniz NOT found in system, using bundled version...") +add_library(miniz_static STATIC + miniz.c + miniz.h +) +if(${CMAKE_C_COMPILER_ID} STREQUAL "GNU") + target_compile_definitions(miniz_static PRIVATE _GNU_SOURCE) endif() + +target_link_libraries(miniz INTERFACE miniz_static) +target_include_directories(miniz INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) + From cedfc5e3fb2090e6c7a3897346abe3eb694ebd90 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Tue, 12 Oct 2021 10:46:09 +0200 Subject: [PATCH 049/102] DoubleSlider: Code refactoring for auto color change --- src/slic3r/GUI/DoubleSlider.cpp | 29 +++++++++++++++++++++-------- src/slic3r/GUI/DoubleSlider.hpp | 7 +++++++ src/slic3r/GUI/GUI_Preview.cpp | 7 +++---- 3 files changed, 31 insertions(+), 12 deletions(-) diff --git a/src/slic3r/GUI/DoubleSlider.cpp b/src/slic3r/GUI/DoubleSlider.cpp index 77679a1ad..d52d8be1c 100644 --- a/src/slic3r/GUI/DoubleSlider.cpp +++ b/src/slic3r/GUI/DoubleSlider.cpp @@ -38,6 +38,25 @@ using GUI::format_wxstr; namespace DoubleSlider { +bool possible_threshold(const double& bottom_area, const double& top_area) +{ + // Check percent of the area decrease. + // This value have to be more than 25 mm2 + return (bottom_area - top_area > min_delta_area()) && + // and more 10% + (top_area / bottom_area < 0.9); +} + +bool equivalent_areas(const double& bottom_area, const double& top_area) +{ + return fabs(bottom_area - top_area <= min_threshold()); +} + +bool overhang(const double& bottom_area, const double& top_area) +{ + return top_area > bottom_area && !equivalent_areas(bottom_area, top_area); +} + wxDEFINE_EVENT(wxCUSTOMEVT_TICKSCHANGED, wxEvent); static std::string gcode(Type type) @@ -2049,8 +2068,6 @@ void Control::auto_color_change() int extruder = 2; const Print& print = GUI::wxGetApp().plater()->fff_print(); - double delta_area = scale_(scale_(25)); // equal to 25 mm2 - for (auto object : print.objects()) { if (object->layer_count() == 0) continue; @@ -2060,14 +2077,10 @@ void Control::auto_color_change() Layer* layer = object->get_layer(i); double cur_area = area(layer->lslices); - if (cur_area > prev_area && prev_area - cur_area > scale_(scale_(1))) + if (overhang(prev_area, cur_area)) break; - if (prev_area - cur_area > delta_area) { - // Check percent of the area decrease. - // Ignore it, if this value is less than 10% - if (cur_area / prev_area > 0.9) - continue; + if (possible_threshold(prev_area, cur_area)) { int tick = get_tick_from_value(layer->print_z); if (tick >= 0 && !m_ticks.has_tick(tick)) { if (m_mode == SingleExtruder) { diff --git a/src/slic3r/GUI/DoubleSlider.hpp b/src/slic3r/GUI/DoubleSlider.hpp index 0f663f663..13b7f483d 100644 --- a/src/slic3r/GUI/DoubleSlider.hpp +++ b/src/slic3r/GUI/DoubleSlider.hpp @@ -25,6 +25,13 @@ namespace DoubleSlider { */ constexpr double epsilon() { return 0.0011; } +constexpr double min_delta_area() { return scale_(scale_(25)); } // equal to 25 mm2 +constexpr double min_threshold() { return scale_(scale_(1)); } // equal to 1 mm2 + +bool possible_threshold(const double& bottom_area, const double& top_area); +bool equivalent_areas(const double& bottom_area, const double& top_area); +bool overhang(const double& bottom_area, const double& top_area); + // custom message the slider sends to its parent to notify a tick-change: wxDECLARE_EVENT(wxCUSTOMEVT_TICKSCHANGED, wxEvent); diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp index 57840dda2..558435019 100644 --- a/src/slic3r/GUI/GUI_Preview.cpp +++ b/src/slic3r/GUI/GUI_Preview.cpp @@ -687,7 +687,6 @@ void Preview::update_layers_slider(const std::vector& layers_z, bool kee if (m_layers_slider->IsNewPrint()) { const Print& print = wxGetApp().plater()->fff_print(); - double delta_area = scale_(scale_(25)); // equal to 25 mm2 //bool is_possible_auto_color_change = false; for (auto object : print.objects()) { @@ -708,7 +707,7 @@ void Preview::update_layers_slider(const std::vector& layers_z, bool kee int i, min_solid_height = int(0.25 * num_layers); for (i = 1; i <= min_solid_height; ++ i) { double cur_area = area(object->get_layer(i)->lslices); - if (cur_area != bottom_area && fabs(cur_area - bottom_area) > scale_(scale_(1))) { + if (!DoubleSlider::equivalent_areas(bottom_area, cur_area)) { // but due to the elephant foot compensation, the first layer may be slightly smaller than the others if (i == 1 && fabs(cur_area - bottom_area) / bottom_area < 0.1) { // So, let process this case and use second layer as a bottom @@ -725,7 +724,7 @@ void Preview::update_layers_slider(const std::vector& layers_z, bool kee double prev_area = area(object->get_layer(i)->lslices); for ( i++; i < num_layers; i++) { double cur_area = area(object->get_layer(i)->lslices); - if (cur_area > prev_area && prev_area - cur_area > scale_(scale_(1))) + if (DoubleSlider::overhang(prev_area, cur_area)) break; prev_area = cur_area; } @@ -733,7 +732,7 @@ void Preview::update_layers_slider(const std::vector& layers_z, bool kee continue; double top_area = area(object->get_layer(int(object->layers().size()) - 1)->lslices); - if( bottom_area - top_area > delta_area) { + if (DoubleSlider::possible_threshold(bottom_area, top_area)) { NotificationManager *notif_mngr = wxGetApp().plater()->get_notification_manager(); notif_mngr->push_notification( NotificationType::SignDetected, NotificationManager::NotificationLevel::PrintInfoNotificationLevel, From ac414e226f94fe92fc9f4fed8ca12e03448a797e Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Tue, 12 Oct 2021 10:55:18 +0200 Subject: [PATCH 050/102] Minor beautification --- src/libslic3r/MTUtils.hpp | 4 ++-- src/libslic3r/SLAPrint.cpp | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libslic3r/MTUtils.hpp b/src/libslic3r/MTUtils.hpp index e60918fab..ab99ea5f6 100644 --- a/src/libslic3r/MTUtils.hpp +++ b/src/libslic3r/MTUtils.hpp @@ -47,7 +47,7 @@ private: public: // Forwarded constructor template - inline CachedObject(Setter fn, Args &&... args) + inline CachedObject(Setter &&fn, Args &&... args) : m_obj(std::forward(args)...), m_valid(false), m_setter(fn) {} @@ -55,7 +55,7 @@ public: // the next retrieval (Setter will be called). The data that is used in // the setter function should be guarded as well during modification so // the modification has to take place in fn. - inline void invalidate(std::function fn) + template void invalidate(Fn &&fn) { std::lock_guard lck(m_lck); fn(); diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index 004f7d555..1bc548914 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -138,14 +138,14 @@ Transform3d SLAPrint::sla_trafo(const ModelObject &model_object) const offset(1) = 0.; rotation(2) = 0.; - offset(Z) *= corr(Z); + offset.z() *= corr.z(); auto trafo = Transform3d::Identity(); trafo.translate(offset); trafo.scale(corr); - trafo.rotate(Eigen::AngleAxisd(rotation(2), Vec3d::UnitZ())); - trafo.rotate(Eigen::AngleAxisd(rotation(1), Vec3d::UnitY())); - trafo.rotate(Eigen::AngleAxisd(rotation(0), Vec3d::UnitX())); + trafo.rotate(Eigen::AngleAxisd(rotation.z(), Vec3d::UnitZ())); + trafo.rotate(Eigen::AngleAxisd(rotation.y(), Vec3d::UnitY())); + trafo.rotate(Eigen::AngleAxisd(rotation.x(), Vec3d::UnitX())); trafo.scale(model_instance.get_scaling_factor()); trafo.scale(model_instance.get_mirror()); From 19572068a50bd188005bc49004a31fe243cf4e90 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 12 Oct 2021 11:49:51 +0200 Subject: [PATCH 051/102] Revert of e28ebf9386c5e9482b1c5859adbf6860aedb6f85 --- src/libslic3r/GCode/GCodeProcessor.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libslic3r/GCode/GCodeProcessor.cpp b/src/libslic3r/GCode/GCodeProcessor.cpp index c5471911a..9c90535c4 100644 --- a/src/libslic3r/GCode/GCodeProcessor.cpp +++ b/src/libslic3r/GCode/GCodeProcessor.cpp @@ -2671,12 +2671,12 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line) const Vec3f curr_pos(m_end_position[X], m_end_position[Y], m_end_position[Z]); const Vec3f new_pos = m_result.moves.back().position - m_extruder_offsets[m_extruder_id]; const std::optional first_vertex = m_seams_detector.get_first_vertex(); -// // the threshold value = 0.0625f == 0.25 * 0.25 is arbitrary, we may find some smarter condition later -// if ((new_pos - *first_vertex).squaredNorm() < 0.0625f) { + // the threshold value = 0.0625f == 0.25 * 0.25 is arbitrary, we may find some smarter condition later + if ((new_pos - *first_vertex).squaredNorm() < 0.0625f) { set_end_position(0.5f * (new_pos + *first_vertex)); store_move_vertex(EMoveType::Seam); set_end_position(curr_pos); -// } + } m_seams_detector.activate(false); } From 8befc43739baac43d177e74546af2f028c17ca85 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 12 Oct 2021 12:03:34 +0200 Subject: [PATCH 052/102] Seams detection now takes in account for overhang perimeters --- src/libslic3r/GCode/GCodeProcessor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libslic3r/GCode/GCodeProcessor.cpp b/src/libslic3r/GCode/GCodeProcessor.cpp index 9c90535c4..5077069d0 100644 --- a/src/libslic3r/GCode/GCodeProcessor.cpp +++ b/src/libslic3r/GCode/GCodeProcessor.cpp @@ -2663,7 +2663,7 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line) if (type == EMoveType::Extrude && m_extrusion_role == erExternalPerimeter && !m_seams_detector.has_first_vertex()) m_seams_detector.set_first_vertex(m_result.moves.back().position - m_extruder_offsets[m_extruder_id]); // check for seam ending vertex and store the resulting move - else if ((type != EMoveType::Extrude || m_extrusion_role != erExternalPerimeter) && m_seams_detector.has_first_vertex()) { + else if ((type != EMoveType::Extrude || (m_extrusion_role != erExternalPerimeter && m_extrusion_role != erOverhangPerimeter)) && m_seams_detector.has_first_vertex()) { auto set_end_position = [this](const Vec3f& pos) { m_end_position[X] = pos.x(); m_end_position[Y] = pos.y(); m_end_position[Z] = pos.z(); }; From 5990f05418a7b9463af01e46bb1eb7bb754dc04e Mon Sep 17 00:00:00 2001 From: YuSanka Date: Tue, 12 Oct 2021 14:18:04 +0200 Subject: [PATCH 053/102] Follow-up https://github.com/prusa3d/PrusaSlicer/commit/cedfc5e3fb2090e6c7a3897346abe3eb694ebd90 - Next code refactoring to avoid inconsistency between AutoColorChangeDetection in Preview and DoubleSlider --- src/slic3r/GUI/DoubleSlider.cpp | 87 ++++++++++++++++++--------------- src/slic3r/GUI/DoubleSlider.hpp | 14 ++++-- src/slic3r/GUI/GUI_Preview.cpp | 26 +++------- 3 files changed, 65 insertions(+), 62 deletions(-) diff --git a/src/slic3r/GUI/DoubleSlider.cpp b/src/slic3r/GUI/DoubleSlider.cpp index d52d8be1c..d8ad08037 100644 --- a/src/slic3r/GUI/DoubleSlider.cpp +++ b/src/slic3r/GUI/DoubleSlider.cpp @@ -38,23 +38,12 @@ using GUI::format_wxstr; namespace DoubleSlider { -bool possible_threshold(const double& bottom_area, const double& top_area) -{ - // Check percent of the area decrease. - // This value have to be more than 25 mm2 - return (bottom_area - top_area > min_delta_area()) && - // and more 10% - (top_area / bottom_area < 0.9); -} +constexpr double min_delta_area = scale_(scale_(25)); // equal to 25 mm2 +constexpr double miscalculation = scale_(scale_(1)); // equal to 1 mm2 bool equivalent_areas(const double& bottom_area, const double& top_area) { - return fabs(bottom_area - top_area <= min_threshold()); -} - -bool overhang(const double& bottom_area, const double& top_area) -{ - return top_area > bottom_area && !equivalent_areas(bottom_area, top_area); + return fabs(bottom_area - top_area <= miscalculation); } wxDEFINE_EVENT(wxCUSTOMEVT_TICKSCHANGED, wxEvent); @@ -2053,6 +2042,32 @@ void Control::show_cog_icon_context_menu() GUI::wxGetApp().plater()->PopupMenu(&menu); } +bool check_color_change(PrintObject* object, size_t frst_layer_id, size_t layers_cnt, std::function break_condition) +{ + double prev_area = area(object->get_layer(frst_layer_id)->lslices); + + bool detected = false; + for (size_t i = frst_layer_id+1; i < layers_cnt; i++) { + Layer* layer = object->get_layer(i); + double cur_area = area(layer->lslices); + + // check for overhangs + if (cur_area > prev_area && !equivalent_areas(prev_area, cur_area)) + break; + + // Check percent of the area decrease. + // This value have to be more than min_delta_area and more then 10% + if ((prev_area - cur_area > min_delta_area) && (cur_area / prev_area < 0.9)) { + detected = true; + if (break_condition(layer)) + break; + } + + prev_area = cur_area; + } + return detected; +} + void Control::auto_color_change() { if (!m_ticks.empty()) { @@ -2071,36 +2086,30 @@ void Control::auto_color_change() for (auto object : print.objects()) { if (object->layer_count() == 0) continue; - double prev_area = area(object->get_layer(0)->lslices); - for (size_t i = 1; i < object->layers().size(); i++) { - Layer* layer = object->get_layer(i); - double cur_area = area(layer->lslices); - - if (overhang(prev_area, cur_area)) - break; - - if (possible_threshold(prev_area, cur_area)) { - int tick = get_tick_from_value(layer->print_z); - if (tick >= 0 && !m_ticks.has_tick(tick)) { - if (m_mode == SingleExtruder) { - m_ticks.set_default_colors(true); - m_ticks.add_tick(tick, ColorChange, 1, layer->print_z); - } - else { - m_ticks.add_tick(tick, ToolChange, extruder, layer->print_z); - if (++extruder > extruders_cnt) + check_color_change(object, 1, object->layers().size(), [this, extruders_cnt](Layer* layer) + { + int tick = get_tick_from_value(layer->print_z); + if (tick >= 0 && !m_ticks.has_tick(tick)) { + if (m_mode == SingleExtruder) { + m_ticks.set_default_colors(true); + m_ticks.add_tick(tick, ColorChange, 1, layer->print_z); + } + else { + int extruder = 2; + if (!m_ticks.empty()) { + auto it = m_ticks.ticks.end(); + it--; + extruder = it->extruder + 1; + if (extruder > extruders_cnt) extruder = 1; } + m_ticks.add_tick(tick, ToolChange, extruder, layer->print_z); } - - // allow max 3 auto color changes - if (m_ticks.ticks.size() == 3) - break; } - - prev_area = cur_area; - } + // allow max 3 auto color changes + return m_ticks.ticks.size() > 2; + }); } if (m_ticks.empty()) diff --git a/src/slic3r/GUI/DoubleSlider.hpp b/src/slic3r/GUI/DoubleSlider.hpp index 13b7f483d..5c95d8052 100644 --- a/src/slic3r/GUI/DoubleSlider.hpp +++ b/src/slic3r/GUI/DoubleSlider.hpp @@ -17,6 +17,8 @@ class wxMenu; namespace Slic3r { using namespace CustomGCode; +class PrintObject; +class Layer; namespace DoubleSlider { @@ -25,12 +27,14 @@ namespace DoubleSlider { */ constexpr double epsilon() { return 0.0011; } -constexpr double min_delta_area() { return scale_(scale_(25)); } // equal to 25 mm2 -constexpr double min_threshold() { return scale_(scale_(1)); } // equal to 1 mm2 - -bool possible_threshold(const double& bottom_area, const double& top_area); +// return true when areas are mostly equivalent bool equivalent_areas(const double& bottom_area, const double& top_area); -bool overhang(const double& bottom_area, const double& top_area); + +// return true if color change was detected +bool check_color_change(PrintObject* object, size_t frst_layer_id, size_t layers_cnt, + // what to do with detected color change + // and return true when detection have to be desturbed + std::function break_condition); // custom message the slider sends to its parent to notify a tick-change: wxDECLARE_EVENT(wxCUSTOMEVT_TICKSCHANGED, wxEvent); diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp index 558435019..8654bed89 100644 --- a/src/slic3r/GUI/GUI_Preview.cpp +++ b/src/slic3r/GUI/GUI_Preview.cpp @@ -720,33 +720,23 @@ void Preview::update_layers_slider(const std::vector& layers_z, bool kee if (i < min_solid_height) continue; - // bottom layer have to be a biggest, so control relation between bottom layer and object size - double prev_area = area(object->get_layer(i)->lslices); - for ( i++; i < num_layers; i++) { - double cur_area = area(object->get_layer(i)->lslices); - if (DoubleSlider::overhang(prev_area, cur_area)) - break; - prev_area = cur_area; - } - if (i < num_layers) - continue; - - double top_area = area(object->get_layer(int(object->layers().size()) - 1)->lslices); - if (DoubleSlider::possible_threshold(bottom_area, top_area)) { - NotificationManager *notif_mngr = wxGetApp().plater()->get_notification_manager(); + if (DoubleSlider::check_color_change(object, i, num_layers, [this, object](Layer*) { + NotificationManager* notif_mngr = wxGetApp().plater()->get_notification_manager(); notif_mngr->push_notification( NotificationType::SignDetected, NotificationManager::NotificationLevel::PrintInfoNotificationLevel, - _u8L("NOTE:") + "\n" + _u8L("Sliced object looks like the sign") + "\n", - _u8L("Apply auto color change to print"), + _u8L("NOTE:") + "\n" + + format(_u8L("Sliced object \"%1%\" looks like a logo or a sign"), object->model_object()->name) + "\n", + _u8L("Apply automatic color change"), [this](wxEvtHandler*) { m_layers_slider->auto_color_change(); return true; }); notif_mngr->apply_in_preview(); - + return true; + }) ) + // first object with color chnages is found break; - } } } From a4ad4ff4a9367bc411b01104f58d339c35d15527 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Tue, 12 Oct 2021 15:23:50 +0200 Subject: [PATCH 054/102] Auto color change: check overhangs lust from Preview when detecting auto color changes + fixed typo in equivalent_areas() + Added missed include --- src/slic3r/GUI/DoubleSlider.cpp | 8 ++++---- src/slic3r/GUI/DoubleSlider.hpp | 2 +- src/slic3r/GUI/GUI_Preview.cpp | 3 ++- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/slic3r/GUI/DoubleSlider.cpp b/src/slic3r/GUI/DoubleSlider.cpp index d8ad08037..d0b29165c 100644 --- a/src/slic3r/GUI/DoubleSlider.cpp +++ b/src/slic3r/GUI/DoubleSlider.cpp @@ -43,7 +43,7 @@ constexpr double miscalculation = scale_(scale_(1)); // equal to 1 mm2 bool equivalent_areas(const double& bottom_area, const double& top_area) { - return fabs(bottom_area - top_area <= miscalculation); + return fabs(bottom_area - top_area) <= miscalculation; } wxDEFINE_EVENT(wxCUSTOMEVT_TICKSCHANGED, wxEvent); @@ -2042,7 +2042,7 @@ void Control::show_cog_icon_context_menu() GUI::wxGetApp().plater()->PopupMenu(&menu); } -bool check_color_change(PrintObject* object, size_t frst_layer_id, size_t layers_cnt, std::function break_condition) +bool check_color_change(PrintObject* object, size_t frst_layer_id, size_t layers_cnt, bool check_overhangs, std::function break_condition) { double prev_area = area(object->get_layer(frst_layer_id)->lslices); @@ -2052,7 +2052,7 @@ bool check_color_change(PrintObject* object, size_t frst_layer_id, size_t layers double cur_area = area(layer->lslices); // check for overhangs - if (cur_area > prev_area && !equivalent_areas(prev_area, cur_area)) + if (check_overhangs && cur_area > prev_area && !equivalent_areas(prev_area, cur_area)) break; // Check percent of the area decrease. @@ -2087,7 +2087,7 @@ void Control::auto_color_change() if (object->layer_count() == 0) continue; - check_color_change(object, 1, object->layers().size(), [this, extruders_cnt](Layer* layer) + check_color_change(object, 1, object->layers().size(), false, [this, extruders_cnt](Layer* layer) { int tick = get_tick_from_value(layer->print_z); if (tick >= 0 && !m_ticks.has_tick(tick)) { diff --git a/src/slic3r/GUI/DoubleSlider.hpp b/src/slic3r/GUI/DoubleSlider.hpp index 5c95d8052..8f88de472 100644 --- a/src/slic3r/GUI/DoubleSlider.hpp +++ b/src/slic3r/GUI/DoubleSlider.hpp @@ -31,7 +31,7 @@ constexpr double epsilon() { return 0.0011; } bool equivalent_areas(const double& bottom_area, const double& top_area); // return true if color change was detected -bool check_color_change(PrintObject* object, size_t frst_layer_id, size_t layers_cnt, +bool check_color_change(PrintObject* object, size_t frst_layer_id, size_t layers_cnt, bool check_overhangs, // what to do with detected color change // and return true when detection have to be desturbed std::function break_condition); diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp index 8654bed89..8ca2a39c5 100644 --- a/src/slic3r/GUI/GUI_Preview.cpp +++ b/src/slic3r/GUI/GUI_Preview.cpp @@ -13,6 +13,7 @@ #include "DoubleSlider.hpp" #include "Plater.hpp" #include "MainFrame.hpp" +#include "format.hpp" #include #include @@ -720,7 +721,7 @@ void Preview::update_layers_slider(const std::vector& layers_z, bool kee if (i < min_solid_height) continue; - if (DoubleSlider::check_color_change(object, i, num_layers, [this, object](Layer*) { + if (DoubleSlider::check_color_change(object, i, num_layers, true, [this, object](Layer*) { NotificationManager* notif_mngr = wxGetApp().plater()->get_notification_manager(); notif_mngr->push_notification( NotificationType::SignDetected, NotificationManager::NotificationLevel::PrintInfoNotificationLevel, From 405a7e84d6be30961f9509b397870a4f2b828c60 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 13 Oct 2021 11:13:31 +0200 Subject: [PATCH 055/102] Fix in seams detection (restore detection after wiping) --- src/libslic3r/GCode/GCodeProcessor.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/libslic3r/GCode/GCodeProcessor.cpp b/src/libslic3r/GCode/GCodeProcessor.cpp index 5077069d0..c3489a621 100644 --- a/src/libslic3r/GCode/GCodeProcessor.cpp +++ b/src/libslic3r/GCode/GCodeProcessor.cpp @@ -2672,6 +2672,7 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line) const Vec3f new_pos = m_result.moves.back().position - m_extruder_offsets[m_extruder_id]; const std::optional first_vertex = m_seams_detector.get_first_vertex(); // the threshold value = 0.0625f == 0.25 * 0.25 is arbitrary, we may find some smarter condition later + if ((new_pos - *first_vertex).squaredNorm() < 0.0625f) { set_end_position(0.5f * (new_pos + *first_vertex)); store_move_vertex(EMoveType::Seam); @@ -2681,6 +2682,10 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line) m_seams_detector.activate(false); } } + else if (type == EMoveType::Extrude && m_extrusion_role == erExternalPerimeter) { + m_seams_detector.activate(true); + m_seams_detector.set_first_vertex(m_result.moves.back().position - m_extruder_offsets[m_extruder_id]); + } // store move store_move_vertex(type); From ac6259e387210a4874b60d44dc7f50870f95047c Mon Sep 17 00:00:00 2001 From: David Kocik Date: Wed, 13 Oct 2021 15:36:07 +0200 Subject: [PATCH 056/102] Preferences: notify_relese option with Choice type Field. OptionsGroup:: Added possibility of the right alignment of the controls + Added separator line to Preferences --- src/libslic3r/AppConfig.cpp | 6 +- src/slic3r/GUI/GUI_App.cpp | 2 - src/slic3r/GUI/OG_CustomCtrl.cpp | 77 ++++++++++++++++++++- src/slic3r/GUI/OG_CustomCtrl.hpp | 9 +++ src/slic3r/GUI/OptionsGroup.cpp | 20 +++++- src/slic3r/GUI/OptionsGroup.hpp | 11 ++- src/slic3r/GUI/Preferences.cpp | 103 +++++++++++++++++++++++++--- src/slic3r/GUI/Preferences.hpp | 8 +++ src/slic3r/Utils/PresetUpdater.cpp | 105 ++++++++++++++++------------- 9 files changed, 275 insertions(+), 66 deletions(-) diff --git a/src/libslic3r/AppConfig.cpp b/src/libslic3r/AppConfig.cpp index bf5ecc7f5..d5444edc6 100644 --- a/src/libslic3r/AppConfig.cpp +++ b/src/libslic3r/AppConfig.cpp @@ -121,10 +121,10 @@ void AppConfig::set_defaults() if (get("auto_toolbar_size").empty()) set("auto_toolbar_size", "100"); + + if (get("notify_release").empty()) + set("notify_release", "all"); // or "none" or "release" - - if (get("notify_testing_release").empty()) - set("notify_testing_release", "1"); #if ENABLE_ENVIRONMENT_MAP if (get("use_environment_map").empty()) set("use_environment_map", "0"); diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index a21054201..a19858eea 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -919,7 +919,6 @@ bool GUI_App::on_init_inner() } }); Bind(EVT_SLIC3R_ALPHA_VERSION_ONLINE, [this](const wxCommandEvent& evt) { - //app_config->set("version_alpha_online", into_u8(evt.GetString())); app_config->save(); if (this->plater_ != nullptr && app_config->get("notify_testing_release") == "1") { if (*Semver::parse(SLIC3R_VERSION) < *Semver::parse(into_u8(evt.GetString()))) { @@ -928,7 +927,6 @@ bool GUI_App::on_init_inner() } }); Bind(EVT_SLIC3R_BETA_VERSION_ONLINE, [this](const wxCommandEvent& evt) { - //app_config->set("version_beta_online", into_u8(evt.GetString())); app_config->save(); if (this->plater_ != nullptr && app_config->get("notify_testing_release") == "1") { if (*Semver::parse(SLIC3R_VERSION) < *Semver::parse(into_u8(evt.GetString()))) { diff --git a/src/slic3r/GUI/OG_CustomCtrl.cpp b/src/slic3r/GUI/OG_CustomCtrl.cpp index f01a1e962..9c31f679b 100644 --- a/src/slic3r/GUI/OG_CustomCtrl.cpp +++ b/src/slic3r/GUI/OG_CustomCtrl.cpp @@ -72,6 +72,11 @@ void OG_CustomCtrl::init_ctrl_lines() const std::vector& og_lines = opt_group->get_lines(); for (const Line& line : og_lines) { + if (line.is_separator()) { + ctrl_lines.emplace_back(CtrlLine(0, this, line)); + continue; + } + if (line.full_width && ( // description line line.widget != nullptr || @@ -124,6 +129,15 @@ wxPoint OG_CustomCtrl::get_pos(const Line& line, Field* field_in/* = nullptr*/) line_height = win_height; }; + auto correct_horiz_pos = [this](int& h_pos, Field* field) { + if (m_max_win_width > 0 && field->getWindow()) { + int win_width = field->getWindow()->GetSize().GetWidth(); + if (dynamic_cast(field)) + win_width *= 0.5; + h_pos += m_max_win_width - win_width; + } + }; + for (CtrlLine& ctrl_line : ctrl_lines) { if (&ctrl_line.og_line == &line) { @@ -160,6 +174,7 @@ wxPoint OG_CustomCtrl::get_pos(const Line& line, Field* field_in/* = nullptr*/) h_pos += 3 * blinking_button_width; Field* field = opt_group->get_field(option_set.front().opt_id); correct_line_height(ctrl_line.height, field->getWindow()); + correct_horiz_pos(h_pos, field); break; } @@ -189,8 +204,10 @@ wxPoint OG_CustomCtrl::get_pos(const Line& line, Field* field_in/* = nullptr*/) } h_pos += (opt.opt.gui_type == ConfigOptionDef::GUIType::legend ? 1 : 3) * blinking_button_width; - if (field == field_in) + if (field == field_in) { + correct_horiz_pos(h_pos, field); break; + } if (opt.opt.gui_type == ConfigOptionDef::GUIType::legend) h_pos += 2 * blinking_button_width; @@ -361,6 +378,28 @@ void OG_CustomCtrl::correct_widgets_position(wxSizer* widget, const Line& line, } }; +void OG_CustomCtrl::init_max_win_width() +{ + if (opt_group->ctrl_horiz_alignment == wxALIGN_RIGHT && m_max_win_width == 0) + for (CtrlLine& line : ctrl_lines) { + if (int max_win_width = line.get_max_win_width(); + m_max_win_width < max_win_width) + m_max_win_width = max_win_width; + } +} + +void OG_CustomCtrl::set_max_win_width(int max_win_width) +{ + if (m_max_win_width == max_win_width) + return; + m_max_win_width = max_win_width; + for (CtrlLine& line : ctrl_lines) + line.correct_items_positions(); + + GetParent()->Layout(); +} + + void OG_CustomCtrl::msw_rescale() { #ifdef __WXOSX__ @@ -374,6 +413,8 @@ void OG_CustomCtrl::msw_rescale() m_bmp_mode_sz = create_scaled_bitmap("mode_simple", this, wxOSX ? 10 : 12).GetSize(); m_bmp_blinking_sz = create_scaled_bitmap("search_blink", this).GetSize(); + m_max_win_width = 0; + wxCoord v_pos = 0; for (CtrlLine& line : ctrl_lines) { line.msw_rescale(); @@ -407,6 +448,21 @@ OG_CustomCtrl::CtrlLine::CtrlLine( wxCoord height, } } +int OG_CustomCtrl::CtrlLine::get_max_win_width() +{ + int max_win_width = 0; + if (!draw_just_act_buttons) { + const std::vector