From 0bc2448e22a21a160f9c1f00caaa501af96194f7 Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Sat, 23 Oct 2021 15:29:00 +0200 Subject: [PATCH] Documented the new print bed collision detection algorithm requirements: Only convex print bed is supported. Optimization of collision detection by precomputing the print bed shape type. --- src/libslic3r/Model.cpp | 3 +++ src/libslic3r/Model.hpp | 3 +++ src/slic3r/GUI/3DScene.cpp | 24 +++++++++++++++--------- src/slic3r/GUI/Plater.cpp | 4 ++-- 4 files changed, 23 insertions(+), 11 deletions(-) diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 613e2b262..2dcf34211 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -27,6 +27,7 @@ namespace Slic3r { #if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS +// Using rotating callipers to check for collision of two convex polygons. Thus both printbed_shape and obj_hull_2d are convex polygons. 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) { if (!Geometry::convex_polygons_intersect(printbed_shape, obj_hull_2d)) @@ -362,6 +363,7 @@ BoundingBoxf3 Model::bounding_box() const } #if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS +// printbed_shape is convex polygon unsigned int Model::update_print_volume_state(const Polygon& printbed_shape, double print_volume_height) { unsigned int num_printable = 0; @@ -1571,6 +1573,7 @@ double ModelObject::get_instance_max_z(size_t instance_idx) const } #if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS +// printbed_shape is convex polygon unsigned int ModelObject::check_instances_print_volume_state(const Polygon& printbed_shape, double print_volume_height) { unsigned int num_printable = 0; diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 2a0c83c0d..e47ebda39 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -911,9 +911,11 @@ enum ModelInstanceEPrintVolumeState : unsigned char #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) +// Using rotating callipers to check for collision of two convex polygons. 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) +// Commented out, using rotating callipers is quite expensive for a bounding box test. //ModelInstanceEPrintVolumeState printbed_collision_state(const Polygon& printbed_shape, double print_volume_height, const BoundingBoxf3& box); #endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS @@ -1122,6 +1124,7 @@ public: // Set the print_volume_state of PrintObject::instances, // return total number of printable objects. #if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS + // printbed_shape is convex polygon 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); diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 3dd0c0e1f..673a9a924 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -992,6 +992,7 @@ bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, M 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(); + //FIXME 2D convex hull is O(n log n), while testing the 2D points against 2D circle is O(n). 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); @@ -1013,6 +1014,7 @@ bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, M 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(); + // Using rotating callipers to check for collision of two convex polygons. 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); @@ -1041,6 +1043,14 @@ bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, M ModelInstanceEPrintVolumeState overall_state = ModelInstancePVS_Inside; bool contained_min_one = false; + enum class BedShape { Rectangle, Circle, Convex, NonConvex }; + Vec2d center; + double radius; + BedShape bed_shape = + GUI::Bed3D::is_rectangle(opt->values) ? BedShape::Rectangle : + GUI::Bed3D::is_circle(opt->values, ¢er, &radius) ? BedShape::Circle : + GUI::Bed3D::is_convex(opt->values) ? BedShape::Convex : BedShape::NonConvex; + for (GLVolume* volume : this->volumes) { #if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS if (as_toolpaths && !volume->is_extrusion_path) @@ -1048,15 +1058,11 @@ bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, M 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); + switch (bed_shape) { + case BedShape::Rectangle: check_against_rectangular_bed(*volume, overall_state); break; + case BedShape::Circle: check_against_circular_bed(*volume, overall_state, center, radius); break; + case BedShape::Convex: check_against_convex_bed(*volume, overall_state); break; + default: break; } contained_min_one |= !volume->is_outside; diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index c6de7df22..afbfc7d3c 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -3011,9 +3011,9 @@ 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 Polygon bed_poly_convex = offset(Geometry::convex_hull(Polygon::new_scale(opt->values).points), 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); + this->q->model().update_print_volume_state(bed_poly_convex, 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"))));