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
src/libslic3r

View file

@ -1,8 +1,9 @@
#include "libslic3r.h"
#include "BuildVolume.hpp"
#include "Exception.hpp"
#include "Model.hpp"
#include "ModelArrange.hpp"
#include "Geometry.hpp"
#include "Geometry/ConvexHull.hpp"
#include "MTUtils.hpp"
#include "TriangleMeshSlicer.hpp"
#include "TriangleSelector.hpp"
@ -26,39 +27,6 @@
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))
return ModelInstancePVS_Fully_Outside;
bool contained_xy = true;
for (const Point& p : obj_hull_2d) {
if (!printbed_shape.contains(p)) {
contained_xy = false;
break;
}
}
const bool contained_z = -1e10 < obj_min_z && obj_max_z <= print_volume_height;
return (contained_xy && contained_z) ? ModelInstancePVS_Inside : ModelInstancePVS_Partly_Outside;
}
/*
ModelInstanceEPrintVolumeState printbed_collision_state(const Polygon& printbed_shape, double print_volume_height, const BoundingBoxf3& box)
{
const Polygon box_hull_2d({
{ scale_(box.min.x()), scale_(box.min.y()) },
{ scale_(box.max.x()), scale_(box.min.y()) },
{ scale_(box.max.x()), scale_(box.max.y()) },
{ scale_(box.min.x()), scale_(box.max.y()) }
});
return printbed_collision_state(printbed_shape, print_volume_height, box_hull_2d, box.min.z(), box.max.z());
}
*/
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
Model& Model::assign_copy(const Model &rhs)
{
this->copy_id(rhs);
@ -363,24 +331,13 @@ BoundingBoxf3 Model::bounding_box() const
return bb;
}
#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 Model::update_print_volume_state(const BuildVolume &build_volume)
{
unsigned int num_printable = 0;
for (ModelObject* model_object : this->objects)
num_printable += model_object->check_instances_print_volume_state(printbed_shape, print_volume_height);
num_printable += model_object->update_instances_print_volume_state(build_volume);
return num_printable;
}
#else
unsigned int Model::update_print_volume_state(const BoundingBoxf3 &print_volume)
{
unsigned int num_printable = 0;
for (ModelObject *model_object : this->objects)
num_printable += model_object->check_instances_print_volume_state(print_volume);
return num_printable;
}
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
bool Model::center_instances_around_point(const Vec2d &point)
{
@ -1572,9 +1529,7 @@ double ModelObject::get_instance_max_z(size_t instance_idx) const
return max_z + inst->get_offset(Z);
}
#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 ModelObject::update_instances_print_volume_state(const BuildVolume &build_volume)
{
unsigned int num_printable = 0;
enum {
@ -1586,16 +1541,10 @@ unsigned int ModelObject::check_instances_print_volume_state(const Polygon& prin
for (const ModelVolume* vol : this->volumes)
if (vol->is_model_part()) {
const Transform3d matrix = model_instance->get_matrix() * vol->get_matrix();
const BoundingBoxf3 bb = vol->mesh().transformed_bounding_box(matrix, 0.0);
if (!bb.defined) {
// this may happen if the part is fully below the printbed, leading to a crash in the following call to its_convex_hull_2d_above()
continue;
}
const Polygon volume_hull_2d = its_convex_hull_2d_above(vol->mesh().its, matrix.cast<float>(), 0.0f);
ModelInstanceEPrintVolumeState state = printbed_collision_state(printbed_shape, print_volume_height, volume_hull_2d, bb.min.z(), bb.max.z());
if (state == ModelInstancePVS_Inside)
BuildVolume::ObjectState state = build_volume.object_state(vol->mesh().its, matrix.cast<float>(), true /* may be below print bed */);
if (state == BuildVolume::ObjectState::Inside)
inside_outside |= INSIDE;
else if (state == ModelInstancePVS_Fully_Outside)
else if (state == BuildVolume::ObjectState::Outside)
inside_outside |= OUTSIDE;
else
inside_outside |= INSIDE | OUTSIDE;
@ -1608,35 +1557,6 @@ unsigned int ModelObject::check_instances_print_volume_state(const Polygon& prin
}
return num_printable;
}
#else
unsigned int ModelObject::check_instances_print_volume_state(const BoundingBoxf3& print_volume)
{
unsigned int num_printable = 0;
enum {
INSIDE = 1,
OUTSIDE = 2
};
for (ModelInstance *model_instance : this->instances) {
unsigned int inside_outside = 0;
for (const ModelVolume *vol : this->volumes)
if (vol->is_model_part()) {
BoundingBoxf3 bb = vol->get_convex_hull().transformed_bounding_box(model_instance->get_matrix() * vol->get_matrix());
if (print_volume.contains(bb))
inside_outside |= INSIDE;
else if (print_volume.intersects(bb))
inside_outside |= INSIDE | OUTSIDE;
else
inside_outside |= OUTSIDE;
}
model_instance->print_volume_state =
(inside_outside == (INSIDE | OUTSIDE)) ? ModelInstancePVS_Partly_Outside :
(inside_outside == INSIDE) ? ModelInstancePVS_Inside : ModelInstancePVS_Fully_Outside;
if (inside_outside == INSIDE)
++ num_printable;
}
return num_printable;
}
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
void ModelObject::print_info() const
{