(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.
This commit is contained in:
Vojtech Bubnik 2021-11-19 10:32:40 +01:00
parent 8a0c492583
commit f5c23871e8
4 changed files with 44 additions and 21 deletions

View file

@ -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. // 2) Calculate intersections of triangle edges with the build surface.
inside = num_inside > 0; inside = num_inside > 0;
outside = num_inside < num_above; outside = num_inside < num_above;
@ -303,7 +308,9 @@ BuildVolume::ObjectState BuildVolume::volume_state_bbox(const BoundingBoxf3 &vol
BoundingBox3Base<Vec3d> build_volume = this->bounding_volume().inflated(SceneEpsilon); BoundingBox3Base<Vec3d> build_volume = this->bounding_volume().inflated(SceneEpsilon);
if (m_max_print_height == 0) if (m_max_print_height == 0)
build_volume.max.z() = std::numeric_limits<double>::max(); build_volume.max.z() = std::numeric_limits<double>::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 bool BuildVolume::all_paths_inside(const GCodeProcessorResult &paths, const BoundingBoxf3 &paths_bbox) const

View file

@ -68,7 +68,10 @@ public:
// Colliding with the build volume boundary, thus not printable and error is shown. // Colliding with the build volume boundary, thus not printable and error is shown.
Colliding, Colliding,
// Outside of the build volume means the object is ignored: Not printed and no error is shown. // 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. // 1) Tests called on the plater.

View file

@ -1546,15 +1546,21 @@ unsigned int ModelObject::update_instances_print_volume_state(const BuildVolume
const Transform3d matrix = model_instance->get_matrix() * vol->get_matrix(); const Transform3d matrix = model_instance->get_matrix() * vol->get_matrix();
BuildVolume::ObjectState state = build_volume.object_state(vol->mesh().its, matrix.cast<float>(), true /* may be below print bed */); BuildVolume::ObjectState state = build_volume.object_state(vol->mesh().its, matrix.cast<float>(), true /* may be below print bed */);
if (state == BuildVolume::ObjectState::Inside) if (state == BuildVolume::ObjectState::Inside)
// Volume is completely inside.
inside_outside |= INSIDE; inside_outside |= INSIDE;
else if (state == BuildVolume::ObjectState::Outside) else if (state == BuildVolume::ObjectState::Outside)
// Volume is completely outside.
inside_outside |= 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; inside_outside |= INSIDE | OUTSIDE;
} }
model_instance->print_volume_state = model_instance->print_volume_state =
(inside_outside == (INSIDE | OUTSIDE)) ? ModelInstancePVS_Partly_Outside : inside_outside == (INSIDE | OUTSIDE) ? ModelInstancePVS_Partly_Outside :
(inside_outside == INSIDE) ? ModelInstancePVS_Inside : ModelInstancePVS_Fully_Outside; inside_outside == INSIDE ? ModelInstancePVS_Inside : ModelInstancePVS_Fully_Outside;
if (inside_outside == INSIDE) if (inside_outside == INSIDE)
++num_printable; ++num_printable;
} }

View file

@ -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 bool GLVolumeCollection::check_outside_state(const BuildVolume &build_volume, ModelInstanceEPrintVolumeState *out_state) const
{ {
const Model& model = GUI::wxGetApp().plater()->model(); 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. // Volume is partially below the print bed, thus a pre-calculated convex hull cannot be used.
auto volume_sinking = [](GLVolume& volume) -> bool 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. // Cached bounding box of a volume above the print bed.
auto volume_bbox = [volume_sinking](GLVolume& volume) -> BoundingBoxf3 auto volume_bbox = [volume_sinking](GLVolume& volume) -> BoundingBoxf3
{ return volume_sinking(volume) ? volume.transformed_non_sinking_bounding_box() : volume.transformed_convex_hull_bounding_box(); }; { return volume_sinking(volume) ? volume.transformed_non_sinking_bounding_box() : volume.transformed_convex_hull_bounding_box(); };
@ -948,6 +950,9 @@ bool GLVolumeCollection::check_outside_state(const BuildVolume &build_volume, Mo
for (GLVolume* volume : this->volumes) 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))) { if (! volume->is_modifier && (volume->shader_outside_printer_detection_enabled || (! volume->is_wipe_tower && volume->composite_id.volume_id >= 0))) {
BuildVolume::ObjectState state; BuildVolume::ObjectState state;
if (volume_below(*volume))
state = BuildVolume::ObjectState::Below;
else {
switch (build_volume.type()) { switch (build_volume.type()) {
case BuildVolume::Type::Rectangle: case BuildVolume::Type::Rectangle:
//FIXME this test does not evaluate collision of a build volume bounding box with non-convex objects. //FIXME this test does not evaluate collision of a build volume bounding box with non-convex objects.
@ -964,6 +969,8 @@ bool GLVolumeCollection::check_outside_state(const BuildVolume &build_volume, Mo
state = BuildVolume::ObjectState::Inside; state = BuildVolume::ObjectState::Inside;
break; break;
} }
assert(state != BuildVolume::ObjectState::Below);
}
volume->is_outside = state != BuildVolume::ObjectState::Inside; volume->is_outside = state != BuildVolume::ObjectState::Inside;
if (volume->printable) { if (volume->printable) {
if (overall_state == ModelInstancePVS_Inside && volume->is_outside) if (overall_state == ModelInstancePVS_Inside && volume->is_outside)