From d805c8ac3bcaa3310b2c3542da061657a192c3b3 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Wed, 18 Jul 2018 14:26:42 +0200 Subject: [PATCH] Disable slicing when one object crosses the print volume boundary --- xs/src/libslic3r/BoundingBox.hpp | 4 ++++ xs/src/libslic3r/Model.cpp | 11 ++++++++--- xs/src/libslic3r/Model.hpp | 26 +++++++++++++++++++------- xs/src/libslic3r/Print.cpp | 2 +- xs/src/libslic3r/PrintObject.cpp | 2 +- xs/src/slic3r/GUI/3DScene.cpp | 25 +++++++++++++++++++------ xs/src/slic3r/GUI/3DScene.hpp | 5 ++++- xs/src/slic3r/GUI/GLCanvas3D.cpp | 17 +++++++++++------ xs/xsp/GUI_3DScene.xsp | 4 ---- 9 files changed, 67 insertions(+), 29 deletions(-) diff --git a/xs/src/libslic3r/BoundingBox.hpp b/xs/src/libslic3r/BoundingBox.hpp index 1f71536ee..82a3edc18 100644 --- a/xs/src/libslic3r/BoundingBox.hpp +++ b/xs/src/libslic3r/BoundingBox.hpp @@ -103,6 +103,10 @@ public: bool contains(const BoundingBox3Base& other) const { return contains(other.min) && contains(other.max); } + + bool intersects(const BoundingBox3Base& other) const { + return (min.x < other.max.x) && (max.x > other.min.x) && (min.y < other.max.y) && (max.y > other.min.y) && (min.z < other.max.z) && (max.z > other.min.z); + } }; class BoundingBox : public BoundingBoxBase diff --git a/xs/src/libslic3r/Model.cpp b/xs/src/libslic3r/Model.cpp index bd95d9959..509fe6190 100644 --- a/xs/src/libslic3r/Model.cpp +++ b/xs/src/libslic3r/Model.cpp @@ -1235,7 +1235,7 @@ void ModelObject::split(ModelObjectPtrs* new_objects) return; } -void ModelObject::check_instances_printability(const BoundingBoxf3& print_volume) +void ModelObject::check_instances_print_volume_state(const BoundingBoxf3& print_volume) { for (ModelVolume* vol : this->volumes) { @@ -1274,10 +1274,15 @@ void ModelObject::check_instances_printability(const BoundingBoxf3& print_volume p.y += inst->offset.y; bb.merge(p); - - inst->is_printable = print_volume.contains(bb); } } + + if (print_volume.contains(bb)) + inst->print_volume_state = ModelInstance::PVS_Inside; + else if (print_volume.intersects(bb)) + inst->print_volume_state = ModelInstance::PVS_Partly_Outside; + else + inst->print_volume_state = ModelInstance::PVS_Fully_Outside; } } } diff --git a/xs/src/libslic3r/Model.hpp b/xs/src/libslic3r/Model.hpp index 08ba8487d..f5e97fb6a 100644 --- a/xs/src/libslic3r/Model.hpp +++ b/xs/src/libslic3r/Model.hpp @@ -131,7 +131,8 @@ public: bool needed_repair() const; void cut(coordf_t z, Model* model) const; void split(ModelObjectPtrs* new_objects); - void check_instances_printability(const BoundingBoxf3& print_volume); + + void check_instances_print_volume_state(const BoundingBoxf3& print_volume); // Print object statistics to console. void print_info() const; @@ -198,14 +199,23 @@ private: // Knows the affine transformation of an object. class ModelInstance { - friend class ModelObject; public: + enum EPrintVolumeState : unsigned char + { + PVS_Inside, + PVS_Partly_Outside, + PVS_Fully_Outside, + Num_BedStates + }; + + friend class ModelObject; + double rotation; // Rotation around the Z axis, in radians around mesh center point double scaling_factor; Pointf offset; // in unscaled coordinates - // whether or not this instance is contained in the print volume (set by Print::validate() using ModelObject::check_instances_printability()) - bool is_printable; + // flag showing the position of this instance with respect to the print volume (set by Print::validate() using ModelObject::check_instances_print_volume_state()) + EPrintVolumeState print_volume_state; ModelObject* get_object() const { return this->object; } @@ -217,14 +227,16 @@ public: BoundingBoxf3 transform_bounding_box(const BoundingBoxf3 &bbox, bool dont_translate = false) const; // To be called on an external polygon. It does not translate the polygon, only rotates and scales. void transform_polygon(Polygon* polygon) const; - + + bool is_printable() const { return print_volume_state == PVS_Inside; } + private: // Parent object, owning this instance. ModelObject* object; - ModelInstance(ModelObject *object) : rotation(0), scaling_factor(1), object(object), is_printable(false) {} + ModelInstance(ModelObject *object) : rotation(0), scaling_factor(1), object(object), print_volume_state(PVS_Inside) {} ModelInstance(ModelObject *object, const ModelInstance &other) : - rotation(other.rotation), scaling_factor(other.scaling_factor), offset(other.offset), object(object), is_printable(false) {} + rotation(other.rotation), scaling_factor(other.scaling_factor), offset(other.offset), object(object), print_volume_state(PVS_Inside) {} }; diff --git a/xs/src/libslic3r/Print.cpp b/xs/src/libslic3r/Print.cpp index 9c9f7f5bb..838cdfc9f 100644 --- a/xs/src/libslic3r/Print.cpp +++ b/xs/src/libslic3r/Print.cpp @@ -543,7 +543,7 @@ std::string Print::validate() const print_volume.min.z = -1e10; unsigned int printable_count = 0; for (PrintObject *po : this->objects) { - po->model_object()->check_instances_printability(print_volume); + po->model_object()->check_instances_print_volume_state(print_volume); po->reload_model_instances(); if (po->is_printable()) ++printable_count; diff --git a/xs/src/libslic3r/PrintObject.cpp b/xs/src/libslic3r/PrintObject.cpp index 1d0a81cd2..8888da76d 100644 --- a/xs/src/libslic3r/PrintObject.cpp +++ b/xs/src/libslic3r/PrintObject.cpp @@ -103,7 +103,7 @@ bool PrintObject::reload_model_instances() copies.reserve(this->_model_object->instances.size()); for (const ModelInstance *mi : this->_model_object->instances) { - if (mi->is_printable) + if (mi->is_printable()) copies.emplace_back(Point::new_scale(mi->offset.x, mi->offset.y)); } return this->set_copies(copies); diff --git a/xs/src/slic3r/GUI/3DScene.cpp b/xs/src/slic3r/GUI/3DScene.cpp index d8fe592e8..c927d6e1d 100644 --- a/xs/src/slic3r/GUI/3DScene.cpp +++ b/xs/src/slic3r/GUI/3DScene.cpp @@ -743,7 +743,7 @@ void GLVolumeCollection::render_legacy() const glDisable(GL_BLEND); } -bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config) +bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, ModelInstance::EPrintVolumeState* out_state) { if (config == nullptr) return false; @@ -757,18 +757,31 @@ bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config) // Allow the objects to protrude below the print bed print_volume.min.z = -1e10; - bool contained = true; + ModelInstance::EPrintVolumeState state = ModelInstance::PVS_Inside; + bool all_contained = true; + for (GLVolume* volume : this->volumes) { if ((volume != nullptr) && !volume->is_modifier) { - bool state = print_volume.contains(volume->transformed_bounding_box()); - contained &= state; - volume->is_outside = !state; + const BoundingBoxf3& bb = volume->transformed_bounding_box(); + bool contained = print_volume.contains(bb); + all_contained &= contained; + + volume->is_outside = !contained; + + if ((state == ModelInstance::PVS_Inside) && volume->is_outside) + state = ModelInstance::PVS_Fully_Outside; + + if ((state == ModelInstance::PVS_Fully_Outside) && volume->is_outside && print_volume.intersects(bb)) + state = ModelInstance::PVS_Partly_Outside; } } - return contained; + if (out_state != nullptr) + *out_state = state; + + return all_contained; } void GLVolumeCollection::reset_outside_state() diff --git a/xs/src/slic3r/GUI/3DScene.hpp b/xs/src/slic3r/GUI/3DScene.hpp index f7fc75db5..11a800c24 100644 --- a/xs/src/slic3r/GUI/3DScene.hpp +++ b/xs/src/slic3r/GUI/3DScene.hpp @@ -6,6 +6,7 @@ #include "../../libslic3r/Line.hpp" #include "../../libslic3r/TriangleMesh.hpp" #include "../../libslic3r/Utils.hpp" +#include "../../libslic3r/Model.hpp" #include "../../slic3r/GUI/GLCanvas3DManager.hpp" class wxBitmap; @@ -422,7 +423,9 @@ public: print_box_max[0] = max_x; print_box_max[1] = max_y; print_box_max[2] = max_z; } - bool check_outside_state(const DynamicPrintConfig* config); + // 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 + bool check_outside_state(const DynamicPrintConfig* config, ModelInstance::EPrintVolumeState* out_state); void reset_outside_state(); void update_colors_by_extruder(const DynamicPrintConfig* config); diff --git a/xs/src/slic3r/GUI/GLCanvas3D.cpp b/xs/src/slic3r/GUI/GLCanvas3D.cpp index 729c91cf3..8eae6359b 100644 --- a/xs/src/slic3r/GUI/GLCanvas3D.cpp +++ b/xs/src/slic3r/GUI/GLCanvas3D.cpp @@ -1381,7 +1381,8 @@ void GLCanvas3D::Gizmos::render(const GLCanvas3D& canvas, const BoundingBoxf3& b ::glDisable(GL_DEPTH_TEST); - _render_current_gizmo(box); + if (box.radius() > 0.0) + _render_current_gizmo(box); ::glPushMatrix(); ::glLoadIdentity(); @@ -1657,7 +1658,7 @@ void GLCanvas3D::update_volumes_selection(const std::vector& selections) bool GLCanvas3D::check_volumes_outside_state(const DynamicPrintConfig* config) const { - return m_volumes.check_outside_state(config); + return m_volumes.check_outside_state(config, nullptr); } bool GLCanvas3D::move_volume_up(unsigned int id) @@ -2082,19 +2083,22 @@ void GLCanvas3D::reload_scene(bool force) // checks for geometry outside the print volume to render it accordingly if (!m_volumes.empty()) { - bool contained = m_volumes.check_outside_state(m_config); + ModelInstance::EPrintVolumeState state; + bool contained = m_volumes.check_outside_state(m_config, &state); + if (!contained) { enable_warning_texture(true); _3DScene::generate_warning_texture(L("Detected object outside print volume")); + m_on_enable_action_buttons_callback.call(state == ModelInstance::PVS_Fully_Outside); } else { enable_warning_texture(false); m_volumes.reset_outside_state(); _3DScene::reset_warning_texture(); + m_on_enable_action_buttons_callback.call(!m_model->objects.empty()); } - m_on_enable_action_buttons_callback.call(!m_model->objects.empty()); } else { @@ -3130,6 +3134,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) m_mouse.set_start_position_3D_as_invalid(); m_mouse.set_start_position_2D_as_invalid(); m_mouse.dragging = false; + m_dirty = true; } else if (evt.Moving()) { @@ -3272,7 +3277,7 @@ BoundingBoxf3 GLCanvas3D::_selected_volumes_bounding_box() const BoundingBoxf3 bb; for (const GLVolume* volume : m_volumes.volumes) { - if ((volume != nullptr) && volume->selected) + if ((volume != nullptr) && !volume->is_wipe_tower && volume->selected) bb.merge(volume->transformed_bounding_box()); } return bb; @@ -3549,7 +3554,7 @@ void GLCanvas3D::_render_objects() const { const BoundingBoxf3& bed_bb = m_bed.get_bounding_box(); m_volumes.set_print_box((float)bed_bb.min.x, (float)bed_bb.min.y, 0.0f, (float)bed_bb.max.x, (float)bed_bb.max.y, (float)m_config->opt_float("max_print_height")); - m_volumes.check_outside_state(m_config); + m_volumes.check_outside_state(m_config, nullptr); } // do not cull backfaces to show broken geometry, if any ::glDisable(GL_CULL_FACE); diff --git a/xs/xsp/GUI_3DScene.xsp b/xs/xsp/GUI_3DScene.xsp index 65dfc8e8e..e85a3b64e 100644 --- a/xs/xsp/GUI_3DScene.xsp +++ b/xs/xsp/GUI_3DScene.xsp @@ -105,10 +105,6 @@ void release_geometry(); void set_print_box(float min_x, float min_y, float min_z, float max_x, float max_y, float max_z); - bool check_outside_state(DynamicPrintConfig* config) - %code%{ - RETVAL = THIS->check_outside_state(config); - %}; void reset_outside_state(); void update_colors_by_extruder(DynamicPrintConfig* config);