New BuildVolume class was created, which detects build volume type (rectangular,

circular, convex, concave) and performs efficient collision detection agains these build
volumes. As of now, collision detection is performed against a convex
hull of a concave build volume for efficency.

GCodeProcessor::Result renamed out of GCodeProcessor to GCodeProcessorResult,
so it could be forward declared.

Plater newly exports BuildVolume, not Bed3D. Bed3D is a rendering class,
while BuildVolume is a purely geometric class.

Reduced usage of global wxGetApp, the Bed3D is passed as a parameter
to View3D/Preview/GLCanvas.

Convex hull code was extracted from Geometry.cpp/hpp to Geometry/ConvexHulll.cpp,hpp.
New test inside_convex_polygon().
New efficent point inside polygon test: Decompose convex hull
to bottom / top parts and use the decomposition to detect point inside
a convex polygon in O(log n). decompose_convex_polygon_top_bottom(),
inside_convex_polygon().

New Circle constructing functions: circle_ransac() and circle_taubin_newton().

New polygon_is_convex() test with unit tests.
This commit is contained in:
Vojtech Bubnik 2021-11-16 10:15:51 +01:00
parent b431fd1f7e
commit cc44089440
51 changed files with 1544 additions and 1594 deletions

View file

@ -3,16 +3,18 @@
#include <igl/unproject.h>
#include "libslic3r/BuildVolume.hpp"
#include "libslic3r/ClipperUtils.hpp"
#include "libslic3r/PrintConfig.hpp"
#include "libslic3r/GCode/ThumbnailData.hpp"
#include "libslic3r/Geometry.hpp"
#include "libslic3r/Geometry/ConvexHull.hpp"
#include "libslic3r/ExtrusionEntity.hpp"
#include "libslic3r/Layer.hpp"
#include "libslic3r/Utils.hpp"
#include "libslic3r/Technologies.hpp"
#include "libslic3r/Tesselate.hpp"
#include "libslic3r/PresetBundle.hpp"
#include "slic3r/GUI/3DBed.hpp"
#include "slic3r/GUI/3DScene.hpp"
#include "slic3r/GUI/BackgroundSlicingProcess.hpp"
#include "slic3r/GUI/GLShader.hpp"
@ -20,7 +22,6 @@
#include "slic3r/GUI/Tab.hpp"
#include "slic3r/GUI/GUI_Preview.hpp"
#include "slic3r/GUI/OpenGLManager.hpp"
#include "slic3r/GUI/3DBed.hpp"
#include "slic3r/GUI/Plater.hpp"
#include "slic3r/GUI/MainFrame.hpp"
#include "slic3r/Utils/UndoRedo.hpp"
@ -957,9 +958,10 @@ PrinterTechnology GLCanvas3D::current_printer_technology() const
return m_process->current_printer_technology();
}
GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas)
GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D &bed)
: m_canvas(canvas)
, m_context(nullptr)
, m_bed(bed)
#if ENABLE_RETINA_GL
, m_retina_helper(nullptr)
#endif
@ -1115,18 +1117,10 @@ 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
m_volumes.check_outside_state(m_bed.build_volume(), &state);
return state;
}
@ -1250,13 +1244,11 @@ BoundingBoxf3 GLCanvas3D::volumes_bounding_box() const
BoundingBoxf3 GLCanvas3D::scene_bounding_box() const
{
BoundingBoxf3 bb = volumes_bounding_box();
bb.merge(wxGetApp().plater()->get_bed().get_bounding_box(true));
if (m_config != nullptr) {
double h = m_config->opt_float("max_print_height");
bb.min(2) = std::min(bb.min(2), -h);
bb.max(2) = std::max(bb.max(2), h);
}
bb.merge(m_bed.extended_bounding_box());
double h = m_bed.build_volume().max_print_height();
//FIXME why -h?
bb.min.z() = std::min(bb.min.z(), -h);
bb.max.z() = std::max(bb.max.z(), h);
return bb;
}
@ -1362,7 +1354,7 @@ void GLCanvas3D::allow_multisample(bool allow)
void GLCanvas3D::zoom_to_bed()
{
_zoom_to_box(wxGetApp().plater()->get_bed().get_bounding_box(false));
_zoom_to_box(m_bed.build_volume().bounding_volume());
}
void GLCanvas3D::zoom_to_volumes()
@ -1423,7 +1415,7 @@ void GLCanvas3D::render()
m_gcode_viewer.init();
#endif // ENABLE_SEAMS_USING_MODELS
if (wxGetApp().plater()->get_bed().get_shape().empty()) {
if (! m_bed.build_volume().valid()) {
// this happens at startup when no data is still saved under <>\AppData\Roaming\Slic3rPE
post_event(SimpleEvent(EVT_GLCANVAS_UPDATE_BED_SHAPE));
return;
@ -2057,7 +2049,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
// checks for geometry outside the print volume to render it accordingly
if (!m_volumes.empty()) {
ModelInstanceEPrintVolumeState state;
const bool contained_min_one = m_volumes.check_outside_state(m_config, &state);
const bool contained_min_one = m_volumes.check_outside_state(m_bed.build_volume(), &state);
const bool partlyOut = (state == ModelInstanceEPrintVolumeState::ModelInstancePVS_Partly_Outside);
const bool fullyOut = (state == ModelInstanceEPrintVolumeState::ModelInstancePVS_Fully_Outside);
@ -2109,7 +2101,7 @@ static void reserve_new_volume_finalize_old_volume(GLVolume& vol_new, GLVolume&
vol_old.finalize_geometry(gl_initialized);
}
void GLCanvas3D::load_gcode_preview(const GCodeProcessor::Result& gcode_result, const std::vector<std::string>& str_tool_colors)
void GLCanvas3D::load_gcode_preview(const GCodeProcessorResult& gcode_result, const std::vector<std::string>& str_tool_colors)
{
m_gcode_viewer.load(gcode_result, *this->fff_print(), m_initialized);
@ -2138,10 +2130,6 @@ void GLCanvas3D::load_sla_preview()
// Release OpenGL data before generating new data.
reset_volumes();
_load_sla_shells();
#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
_update_sla_shells_outside_state();
_set_warning_notification_if_needed(EWarning::SlaSupportsOutside);
}
@ -2158,20 +2146,12 @@ void GLCanvas3D::load_preview(const std::vector<std::string>& str_tool_colors, c
// Release OpenGL data before generating new data.
this->reset_volumes();
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
bool requires_convex_hulls = wxGetApp().plater()->get_bed().get_shape_type() != Bed3D::EShapeType::Rectangle;
_load_print_toolpaths(requires_convex_hulls);
_load_wipe_tower_toolpaths(str_tool_colors, requires_convex_hulls);
const BuildVolume &build_volume = m_bed.build_volume();
_load_print_toolpaths(build_volume);
_load_wipe_tower_toolpaths(build_volume, str_tool_colors);
for (const PrintObject* object : print->objects())
_load_print_object_toolpaths(*object, str_tool_colors, color_print_values, requires_convex_hulls);
#else
_load_print_toolpaths();
_load_wipe_tower_toolpaths(str_tool_colors);
for (const PrintObject* object : print->objects())
_load_print_object_toolpaths(*object, str_tool_colors, color_print_values);
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
_load_print_object_toolpaths(*object, build_volume, str_tool_colors, color_print_values);
_update_toolpath_volumes_outside_state();
_set_warning_notification_if_needed(EWarning::ToolpathOutside);
}
@ -3770,7 +3750,7 @@ Linef3 GLCanvas3D::mouse_ray(const Point& mouse_pos)
double GLCanvas3D::get_size_proportional_to_max_bed_size(double factor) const
{
return factor * wxGetApp().plater()->get_bed().get_bounding_box(false).max_size();
return factor * m_bed.build_volume().bounding_volume().max_size();
}
void GLCanvas3D::set_cursor(ECursorType type)
@ -4161,7 +4141,7 @@ void GLCanvas3D::_render_thumbnail_internal(ThumbnailData& thumbnail_data, const
}
else
// This happens for empty projects
volumes_box = wxGetApp().plater()->get_bed().get_bounding_box(true);
volumes_box = m_bed.extended_bounding_box();
#endif // ENABLE_SAVE_COMMANDS_ALWAYS_ENABLED
Camera camera;
@ -4178,7 +4158,7 @@ void GLCanvas3D::_render_thumbnail_internal(ThumbnailData& thumbnail_data, const
// extends the near and far z of the frustrum to avoid the bed being clipped
// box in eye space
BoundingBoxf3 t_bed_box = wxGetApp().plater()->get_bed().get_bounding_box(true).transformed(camera.get_view_matrix());
BoundingBoxf3 t_bed_box = m_bed.extended_bounding_box().transformed(camera.get_view_matrix());
near_z = -t_bed_box.max.z();
far_z = -t_bed_box.min.z();
}
@ -4861,7 +4841,7 @@ BoundingBoxf3 GLCanvas3D::_max_bounding_box(bool include_gizmos, bool include_be
bb.merge(BoundingBoxf3(sel_bb_center - extend_by, sel_bb_center + extend_by));
}
bb.merge(wxGetApp().plater()->get_bed().get_bounding_box(include_bed_model));
bb.merge(include_bed_model ? m_bed.extended_bounding_box() : m_bed.build_volume().bounding_volume());
if (!m_main_toolbar.is_enabled())
bb.merge(m_gcode_viewer.get_max_bounding_box());
@ -5035,25 +5015,6 @@ 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
const double tolerance_x = 0.05;
const double tolerance_y = 0.05;
BoundingBoxf3 ret;
const ConfigOptionPoints* opt = dynamic_cast<const ConfigOptionPoints*>(config.option("bed_shape"));
if (opt != nullptr) {
BoundingBox bed_box_2D = get_extents(Polygon::new_scale(opt->values));
ret = BoundingBoxf3(Vec3d(unscale<double>(bed_box_2D.min(0)) - tolerance_x, unscale<double>(bed_box_2D.min(1)) - tolerance_y, 0.0), Vec3d(unscale<double>(bed_box_2D.max(0)) + tolerance_x, unscale<double>(bed_box_2D.max(1)) + tolerance_y, config.opt_float("max_print_height")));
// Allow the objects to protrude below the print bed
ret.min(2) = -1e10;
}
return ret;
}
#endif // !ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
void GLCanvas3D::_render_background() const
{
bool use_error_color = false;
@ -5064,15 +5025,7 @@ void GLCanvas3D::_render_background() const
if (!m_volumes.empty())
use_error_color &= _is_any_volume_outside();
else
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
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
}
glsafe(::glPushMatrix());
@ -5123,7 +5076,7 @@ void GLCanvas3D::_render_bed(bool bottom, bool show_axes)
&& m_gizmos.get_current_type() != GLGizmosManager::Seam
&& m_gizmos.get_current_type() != GLGizmosManager::MmuSegmentation);
wxGetApp().plater()->get_bed().render(*this, bottom, scale_factor, show_axes, show_texture);
m_bed.render(*this, bottom, scale_factor, show_axes, show_texture);
}
void GLCanvas3D::_render_bed_for_picking(bool bottom)
@ -5133,7 +5086,7 @@ void GLCanvas3D::_render_bed_for_picking(bool bottom)
scale_factor = m_retina_helper->get_scale_factor();
#endif // ENABLE_RETINA_GL
wxGetApp().plater()->get_bed().render_for_picking(*this, bottom, scale_factor);
m_bed.render_for_picking(*this, bottom, scale_factor);
}
void GLCanvas3D::_render_objects(GLVolumeCollection::ERenderType type)
@ -5148,55 +5101,35 @@ 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
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(), &center, &radius)) {
m_volumes.set_print_volume({ static_cast<int>(type),
{ float(center.x()), float(center.y()), float(radius) + BedEpsilon, 0.0f },
{ 0.0f, float(m_config->opt_float("max_print_height")) } });
}
if (const BuildVolume &build_volume = m_bed.build_volume(); build_volume.valid()) {
switch (build_volume.type()) {
case BuildVolume::Type::Rectangle: {
const BoundingBox3Base<Vec3d> bed_bb = build_volume.bounding_volume().inflated(BuildVolume::SceneEpsilon);
m_volumes.set_print_volume({ 0, // circle
{ float(bed_bb.min.x()), float(bed_bb.min.y()), float(bed_bb.max.x()), float(bed_bb.max.y()) },
{ 0.0f, float(build_volume.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<int>(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")) } });
case BuildVolume::Type::Circle: {
m_volumes.set_print_volume({ 1, // rectangle
{ unscaled<float>(build_volume.circle().center.x()), unscaled<float>(build_volume.circle().center.y()), unscaled<float>(build_volume.circle().radius + BuildVolume::SceneEpsilon), 0.0f },
{ 0.0f, float(build_volume.max_print_height() + BuildVolume::SceneEpsilon) } });
break;
}
default:
case Bed3D::EShapeType::Custom: {
case BuildVolume::Type::Custom: {
m_volumes.set_print_volume({ static_cast<int>(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);
m_volumes.check_outside_state(build_volume, nullptr);
m_requires_check_outside_state = false;
}
#else
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]);
@ -5206,11 +5139,7 @@ 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();
@ -5832,11 +5761,7 @@ void GLCanvas3D::_stop_timer()
m_timer.Stop();
}
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
void GLCanvas3D::_load_print_toolpaths(bool generate_convex_hulls)
#else
void GLCanvas3D::_load_print_toolpaths()
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
void GLCanvas3D::_load_print_toolpaths(const BuildVolume &build_volume)
{
const Print *print = this->fff_print();
if (print == nullptr)
@ -5889,18 +5814,11 @@ void GLCanvas3D::_load_print_toolpaths()
reserve_new_volume_finalize_old_volume(*volume, vol, m_initialized);
}
}
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
if (generate_convex_hulls)
volume->calc_convex_hull_3d();
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
volume->is_outside = ! build_volume.all_paths_inside_vertices_and_normals_interleaved(volume->indexed_vertex_array.vertices_and_normals_interleaved, volume->indexed_vertex_array.bounding_box());
volume->indexed_vertex_array.finalize_geometry(m_initialized);
}
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, const std::vector<std::string>& str_tool_colors, const std::vector<CustomGCode::Item>& color_print_values, bool generate_convex_hulls)
#else
void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, const std::vector<std::string>& str_tool_colors, const std::vector<CustomGCode::Item>& color_print_values)
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, const BuildVolume& build_volume, const std::vector<std::string>& str_tool_colors, const std::vector<CustomGCode::Item>& color_print_values)
{
std::vector<std::array<float, 4>> tool_colors = _parse_colors(str_tool_colors);
@ -6187,26 +6105,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];
if (generate_convex_hulls)
v->calc_convex_hull_3d();
v->is_outside = ! build_volume.all_paths_inside_vertices_and_normals_interleaved(v->indexed_vertex_array.vertices_and_normals_interleaved, v->indexed_vertex_array.bounding_box());
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();
}
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
void GLCanvas3D::_load_wipe_tower_toolpaths(const std::vector<std::string>& str_tool_colors, bool generate_convex_hulls)
#else
void GLCanvas3D::_load_wipe_tower_toolpaths(const std::vector<std::string>& str_tool_colors)
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
void GLCanvas3D::_load_wipe_tower_toolpaths(const BuildVolume& build_volume, const std::vector<std::string>& str_tool_colors)
{
const Print *print = this->fff_print();
if (print == nullptr || print->wipe_tower_data().tool_changes.empty())
@ -6357,17 +6265,11 @@ void GLCanvas3D::_load_wipe_tower_toolpaths(const std::vector<std::string>& 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];
if (generate_convex_hulls)
v->calc_convex_hull_3d();
v->is_outside = ! build_volume.all_paths_inside_vertices_and_normals_interleaved(v->indexed_vertex_array.vertices_and_normals_interleaved, v->indexed_vertex_array.bounding_box());
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();
}
@ -6427,28 +6329,9 @@ void GLCanvas3D::_load_sla_shells()
update_volumes_colors_by_extruder();
}
void GLCanvas3D::_update_toolpath_volumes_outside_state()
{
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
check_volumes_outside_state(true);
#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
check_volumes_outside_state();
#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)