diff --git a/xs/src/libslic3r/BoundingBox.hpp b/xs/src/libslic3r/BoundingBox.hpp index 92a2bd451c..a96fd1a301 100644 --- a/xs/src/libslic3r/BoundingBox.hpp +++ b/xs/src/libslic3r/BoundingBox.hpp @@ -147,6 +147,31 @@ public: BoundingBoxf3() : BoundingBox3Base() {}; BoundingBoxf3(const Pointf3 &pmin, const Pointf3 &pmax) : BoundingBox3Base(pmin, pmax) {}; BoundingBoxf3(const std::vector &points) : BoundingBox3Base(points) {}; + + // check if the given point is contained inside this bounding box + // all quantities are compared after being quantized to try to reduce instability due to float imprecision + bool contains_quantized(const Pointf3& point) const { + struct Helper + { + static coordf_t quantize(coordf_t value) + { + static const coordf_t INV_EPSILON = 1.0 / EPSILON; + return round(value * INV_EPSILON + 0.5) * EPSILON; + } + }; + + coordf_t x = Helper::quantize(point.x); + coordf_t y = Helper::quantize(point.y); + coordf_t z = Helper::quantize(point.z); + + return (Helper::quantize(min.x) <= x) && (x <= Helper::quantize(max.x)) + && (Helper::quantize(min.y) <= y) && (y <= Helper::quantize(max.y)) + && (Helper::quantize(min.z) <= z) && (z <= Helper::quantize(max.z)); + } + + bool contains_quantized(const BoundingBoxf3& other) const { + return contains_quantized(other.min) && contains_quantized(other.max); + } }; template diff --git a/xs/src/libslic3r/Model.cpp b/xs/src/libslic3r/Model.cpp index aaea863e83..25e2073047 100644 --- a/xs/src/libslic3r/Model.cpp +++ b/xs/src/libslic3r/Model.cpp @@ -463,7 +463,7 @@ bool Model::fits_print_volume(const DynamicPrintConfig* config) const BoundingBoxf3 print_volume(Pointf3(unscale(bed_box_2D.min.x), unscale(bed_box_2D.min.y), 0.0), Pointf3(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; - return print_volume.contains(transformed_bounding_box()); + return print_volume.contains_quantized(transformed_bounding_box()); } bool Model::fits_print_volume(const FullPrintConfig &config) const @@ -474,7 +474,7 @@ bool Model::fits_print_volume(const FullPrintConfig &config) const BoundingBoxf3 print_volume(Pointf3(unscale(bed_box_2D.min.x), unscale(bed_box_2D.min.y), 0.0), Pointf3(unscale(bed_box_2D.max.x), unscale(bed_box_2D.max.y), config.max_print_height)); // Allow the objects to protrude below the print bed print_volume.min.z = -1e10; - return print_volume.contains(transformed_bounding_box()); + return print_volume.contains_quantized(transformed_bounding_box()); } unsigned int Model::get_auto_extruder_id() diff --git a/xs/src/libslic3r/Print.cpp b/xs/src/libslic3r/Print.cpp index e692b1e9ee..9de5c03794 100644 --- a/xs/src/libslic3r/Print.cpp +++ b/xs/src/libslic3r/Print.cpp @@ -522,7 +522,7 @@ std::string Print::validate() const // Allow the objects to protrude below the print bed, only the part of the object above the print bed will be sliced. print_volume.min.z = -1e10; for (PrintObject *po : this->objects) { - if (! print_volume.contains(po->model_object()->tight_bounding_box(false))) + if (!print_volume.contains_quantized(po->model_object()->tight_bounding_box(false))) return "Some objects are outside of the print volume."; } diff --git a/xs/src/slic3r/GUI/3DScene.cpp b/xs/src/slic3r/GUI/3DScene.cpp index 7f5e632bba..7d4e4d68c5 100644 --- a/xs/src/slic3r/GUI/3DScene.cpp +++ b/xs/src/slic3r/GUI/3DScene.cpp @@ -665,7 +665,7 @@ void GLVolumeCollection::update_outside_state(const DynamicPrintConfig* config, continue; } - volume->is_outside = !print_volume.contains(volume->transformed_bounding_box()); + volume->is_outside = !print_volume.contains_quantized(volume->transformed_bounding_box()); } }