From f5c23871e80711b4e144a465992d01e04b33ccb8 Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Fri, 19 Nov 2021 10:32:40 +0100 Subject: [PATCH] Follow-up to 77548df00ff24ef9aae0b5808876b7ac0ec7db17 (Fixed missing sinking property in objects list for multipart objects with a part completely below the printbed): It was not possible to slice an object with some part completely below the print bed. The BuildVolume collision check newly supports a "completely below print bed" return status, Model evaluates this "completely below print bed status" allowing objects with some volumes completely below the print bed to print. --- src/libslic3r/BuildVolume.cpp | 9 +++++++- src/libslic3r/BuildVolume.hpp | 5 ++++- src/libslic3r/Model.cpp | 12 ++++++++--- src/slic3r/GUI/3DScene.cpp | 39 +++++++++++++++++++++-------------- 4 files changed, 44 insertions(+), 21 deletions(-) diff --git a/src/libslic3r/BuildVolume.cpp b/src/libslic3r/BuildVolume.cpp index 216b61698..f8fcef76f 100644 --- a/src/libslic3r/BuildVolume.cpp +++ b/src/libslic3r/BuildVolume.cpp @@ -216,6 +216,11 @@ BuildVolume::ObjectState object_state_templ(const indexed_triangle_set &its, con } } + if (num_above == 0) + // Special case, the object is completely below the print bed, thus it is outside, + // however we want to allow an object to be still printable if some of its parts are completely below the print bed. + return BuildVolume::ObjectState::Below; + // 2) Calculate intersections of triangle edges with the build surface. inside = num_inside > 0; outside = num_inside < num_above; @@ -303,7 +308,9 @@ BuildVolume::ObjectState BuildVolume::volume_state_bbox(const BoundingBoxf3 &vol BoundingBox3Base build_volume = this->bounding_volume().inflated(SceneEpsilon); if (m_max_print_height == 0) build_volume.max.z() = std::numeric_limits::max(); - return build_volume.contains(volume_bbox) ? ObjectState::Inside : build_volume.intersects(volume_bbox) ? ObjectState::Colliding : ObjectState::Outside; + return build_volume.max.z() <= - SceneEpsilon ? ObjectState::Below : + build_volume.contains(volume_bbox) ? ObjectState::Inside : + build_volume.intersects(volume_bbox) ? ObjectState::Colliding : ObjectState::Outside; } bool BuildVolume::all_paths_inside(const GCodeProcessorResult &paths, const BoundingBoxf3 &paths_bbox) const diff --git a/src/libslic3r/BuildVolume.hpp b/src/libslic3r/BuildVolume.hpp index ff3041eb7..e75710882 100644 --- a/src/libslic3r/BuildVolume.hpp +++ b/src/libslic3r/BuildVolume.hpp @@ -68,7 +68,10 @@ public: // Colliding with the build volume boundary, thus not printable and error is shown. Colliding, // Outside of the build volume means the object is ignored: Not printed and no error is shown. - Outside + Outside, + // Completely below the print bed. The same as Outside, but an object with one printable part below the print bed + // and at least one part above the print bed is still printable. + Below, }; // 1) Tests called on the plater. diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index b561b1a44..b900a6298 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -1546,15 +1546,21 @@ unsigned int ModelObject::update_instances_print_volume_state(const BuildVolume const Transform3d matrix = model_instance->get_matrix() * vol->get_matrix(); BuildVolume::ObjectState state = build_volume.object_state(vol->mesh().its, matrix.cast(), true /* may be below print bed */); if (state == BuildVolume::ObjectState::Inside) + // Volume is completely inside. inside_outside |= INSIDE; else if (state == BuildVolume::ObjectState::Outside) + // Volume is completely outside. inside_outside |= OUTSIDE; - else + else if (state == BuildVolume::ObjectState::Below) { + // Volume below the print bed, thus it is completely outside, however this does not prevent the object to be printable + // if some of its volumes are still inside the build volume. + } else + // Volume colliding with the build volume. inside_outside |= INSIDE | OUTSIDE; } model_instance->print_volume_state = - (inside_outside == (INSIDE | OUTSIDE)) ? ModelInstancePVS_Partly_Outside : - (inside_outside == INSIDE) ? ModelInstancePVS_Inside : ModelInstancePVS_Fully_Outside; + inside_outside == (INSIDE | OUTSIDE) ? ModelInstancePVS_Partly_Outside : + inside_outside == INSIDE ? ModelInstancePVS_Inside : ModelInstancePVS_Fully_Outside; if (inside_outside == INSIDE) ++num_printable; } diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index a96ea2d17..6aa12431c 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -932,9 +932,11 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type, bool disab bool GLVolumeCollection::check_outside_state(const BuildVolume &build_volume, ModelInstanceEPrintVolumeState *out_state) const { const Model& model = GUI::wxGetApp().plater()->model(); + auto volume_below = [](GLVolume& volume) -> bool + { return volume.object_idx() != -1 && volume.volume_idx() != -1 && volume.is_below_printbed(); }; // Volume is partially below the print bed, thus a pre-calculated convex hull cannot be used. auto volume_sinking = [](GLVolume& volume) -> bool - { return volume.is_sinking() && volume.object_idx() != -1 && volume.volume_idx() != -1; }; + { return volume.object_idx() != -1 && volume.volume_idx() != -1 && volume.is_sinking(); }; // Cached bounding box of a volume above the print bed. auto volume_bbox = [volume_sinking](GLVolume& volume) -> BoundingBoxf3 { return volume_sinking(volume) ? volume.transformed_non_sinking_bounding_box() : volume.transformed_convex_hull_bounding_box(); }; @@ -948,21 +950,26 @@ bool GLVolumeCollection::check_outside_state(const BuildVolume &build_volume, Mo for (GLVolume* volume : this->volumes) if (! volume->is_modifier && (volume->shader_outside_printer_detection_enabled || (! volume->is_wipe_tower && volume->composite_id.volume_id >= 0))) { BuildVolume::ObjectState state; - switch (build_volume.type()) { - case BuildVolume::Type::Rectangle: - //FIXME this test does not evaluate collision of a build volume bounding box with non-convex objects. - state = build_volume.volume_state_bbox(volume_bbox(*volume)); - break; - case BuildVolume::Type::Circle: - case BuildVolume::Type::Convex: - //FIXME doing test on convex hull until we learn to do test on non-convex polygons efficiently. - case BuildVolume::Type::Custom: - state = build_volume.object_state(volume_convex_mesh(*volume).its, volume->world_matrix().cast(), volume_sinking(*volume)); - break; - default: - // Ignore, don't produce any collision. - state = BuildVolume::ObjectState::Inside; - break; + if (volume_below(*volume)) + state = BuildVolume::ObjectState::Below; + else { + switch (build_volume.type()) { + case BuildVolume::Type::Rectangle: + //FIXME this test does not evaluate collision of a build volume bounding box with non-convex objects. + state = build_volume.volume_state_bbox(volume_bbox(*volume)); + break; + case BuildVolume::Type::Circle: + case BuildVolume::Type::Convex: + //FIXME doing test on convex hull until we learn to do test on non-convex polygons efficiently. + case BuildVolume::Type::Custom: + state = build_volume.object_state(volume_convex_mesh(*volume).its, volume->world_matrix().cast(), volume_sinking(*volume)); + break; + default: + // Ignore, don't produce any collision. + state = BuildVolume::ObjectState::Inside; + break; + } + assert(state != BuildVolume::ObjectState::Below); } volume->is_outside = state != BuildVolume::ObjectState::Inside; if (volume->printable) {