Tech ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS - Fixed detection of collision with circular printbed for pre-gcode preview and sla preview

This commit is contained in:
enricoturri1966 2021-10-01 12:15:14 +02:00
parent c4edff72d0
commit 6ff4d6c3f5
3 changed files with 170 additions and 38 deletions

View File

@ -37,6 +37,12 @@
#include <Eigen/Dense>
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
#include <libqhullcpp/Qhull.h>
#include <libqhullcpp/QhullFacetList.h>
#include <libqhullcpp/QhullVertexSet.h>
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
#ifdef HAS_GLSAFE
void glAssertRecentCallImpl(const char* file_name, unsigned int line, const char* function_name)
{
@ -614,6 +620,106 @@ void GLVolume::render_sinking_contours()
m_sinking_contours.render();
}
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
void GLVolume::calc_convex_hull_3d()
{
if (this->indexed_vertex_array.vertices_and_normals_interleaved.empty())
return;
TriangleMesh mesh;
for (size_t i = 0; i < this->indexed_vertex_array.vertices_and_normals_interleaved.size(); i += 6) {
const size_t v_id = 3 + i;
mesh.its.vertices.push_back({ this->indexed_vertex_array.vertices_and_normals_interleaved[v_id + 0],
this->indexed_vertex_array.vertices_and_normals_interleaved[v_id + 1],
this->indexed_vertex_array.vertices_and_normals_interleaved[v_id + 2]
});
}
const std::vector<Vec3f>& vertices = mesh.its.vertices;
// The qhull call:
orgQhull::Qhull qhull;
qhull.disableOutputStream(); // we want qhull to be quiet
std::vector<realT> src_vertices;
try
{
#if REALfloat
qhull.runQhull("", 3, (int)vertices.size(), (const realT*)(vertices.front().data()), "Qt");
#else
src_vertices.reserve(vertices.size() * 3);
// We will now fill the vector with input points for computation:
for (const stl_vertex& v : vertices)
for (int i = 0; i < 3; ++i)
src_vertices.emplace_back(v(i));
qhull.runQhull("", 3, (int)src_vertices.size() / 3, src_vertices.data(), "Qt");
#endif
}
catch (...)
{
std::cout << "GLVolume::calc_convex_hull_3d() - Unable to create convex hull" << std::endl;
return ;
}
// Let's collect results:
std::vector<Vec3f> dst_vertices;
std::vector<Vec3i> dst_facets;
// Map of QHull's vertex ID to our own vertex ID (pointing to dst_vertices).
std::vector<int> map_dst_vertices;
#ifndef NDEBUG
Vec3f centroid = Vec3f::Zero();
for (const auto& pt : vertices)
centroid += pt;
centroid /= float(vertices.size());
#endif // NDEBUG
for (const orgQhull::QhullFacet& facet : qhull.facetList()) {
// Collect face vertices first, allocate unique vertices in dst_vertices based on QHull's vertex ID.
Vec3i indices;
int cnt = 0;
for (const orgQhull::QhullVertex vertex : facet.vertices()) {
const int id = vertex.id();
assert(id >= 0);
if (id >= int(map_dst_vertices.size()))
map_dst_vertices.resize(next_highest_power_of_2(size_t(id + 1)), -1);
if (int i = map_dst_vertices[id]; i == -1) {
// Allocate a new vertex.
i = int(dst_vertices.size());
map_dst_vertices[id] = i;
orgQhull::QhullPoint pt(vertex.point());
dst_vertices.emplace_back(pt[0], pt[1], pt[2]);
indices[cnt] = i;
}
else
// Reuse existing vertex.
indices[cnt] = i;
if (cnt++ == 3)
break;
}
assert(cnt == 3);
if (cnt == 3) {
// QHull sorts vertices of a face lexicographically by their IDs, not by face normals.
// Calculate face normal based on the order of vertices.
const Vec3f n = (dst_vertices[indices(1)] - dst_vertices[indices(0)]).cross(dst_vertices[indices(2)] - dst_vertices[indices(1)]);
auto* n2 = facet.getBaseT()->normal;
const auto d = n.x() * n2[0] + n.y() * n2[1] + n.z() * n2[2];
#ifndef NDEBUG
const Vec3f n3 = (dst_vertices[indices(0)] - centroid);
const auto d3 = n.dot(n3);
assert((d < 0.f) == (d3 < 0.f));
#endif // NDEBUG
// Get the face normal from QHull.
if (d < 0.f)
// Fix face orientation.
std::swap(indices[1], indices[2]);
dst_facets.emplace_back(indices);
}
}
TriangleMesh out_mesh{ std::move(dst_vertices), std::move(dst_facets) };
this->set_convex_hull(out_mesh);
}
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
std::vector<int> GLVolumeCollection::load_object(
const ModelObject *model_object,
int obj_idx,
@ -771,7 +877,10 @@ int GLVolumeCollection::load_wipe_tower_preview(
volumes.emplace_back(new GLVolume(color));
GLVolume& v = *volumes.back();
v.indexed_vertex_array.load_mesh(mesh);
v.indexed_vertex_array.load_mesh(mesh);
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
v.calc_convex_hull_3d();
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
v.indexed_vertex_array.finalize_geometry(opengl_initialized);
v.set_volume_offset(Vec3d(pos_x, pos_y, 0.0));
v.set_volume_rotation(Vec3d(0., 0., (M_PI / 180.) * rotation_angle));
@ -964,12 +1073,16 @@ bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, M
#if ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION
bool contained = false;
bool intersects = false;
bool is_sla = GUI::wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA;
const BoundingBoxf3 bb = is_sla ? volume->transformed_convex_hull_bounding_box() : volume->transformed_non_sinking_bounding_box();
bool is_aux_volume = volume->is_sla_support() || volume->is_sla_pad() || volume->is_wipe_tower;
const BoundingBoxf3 bb = is_aux_volume ? volume->transformed_convex_hull_bounding_box() : volume->transformed_non_sinking_bounding_box();
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
ModelInstanceEPrintVolumeState volume_state;
if (is_sla)
volume_state = printbed_collision_state(bed_poly, bed_height, bb);
if (is_aux_volume) {
if (volume->is_sla_support() || volume->is_wipe_tower) {
const Polygon volume_hull_2d = its_convex_hull_2d_above(volume->convex_hull()->its, volume->world_matrix().cast<float>(), 0.0f);
volume_state = printbed_collision_state(bed_poly, bed_height, volume_hull_2d, bb.min.z(), bb.max.z());
}
}
else {
const indexed_triangle_set& its = GUI::wxGetApp().plater()->model().objects[volume->object_idx()]->volumes[volume->volume_idx()]->mesh().its;
const Polygon volume_hull_2d = its_convex_hull_2d_above(its, volume->world_matrix().cast<float>(), 0.0f);
@ -1061,35 +1174,28 @@ void GLVolumeCollection::update_colors_by_extruder(const DynamicPrintConfig* con
std::vector<Color> colors(colors_count);
unsigned char rgb[3];
for (unsigned int i = 0; i < colors_count; ++i)
{
for (unsigned int i = 0; i < colors_count; ++i) {
const std::string& txt_color = config->opt_string("extruder_colour", i);
if (Slic3r::GUI::BitmapCache::parse_color(txt_color, rgb))
{
colors[i].set(txt_color, rgb);
}
else
{
else {
const std::string& txt_color = config->opt_string("filament_colour", i);
if (Slic3r::GUI::BitmapCache::parse_color(txt_color, rgb))
colors[i].set(txt_color, rgb);
}
}
for (GLVolume* volume : volumes)
{
if ((volume == nullptr) || volume->is_modifier || volume->is_wipe_tower || (volume->volume_idx() < 0))
for (GLVolume* volume : volumes) {
if (volume == nullptr || volume->is_modifier || volume->is_wipe_tower || (volume->volume_idx() < 0))
continue;
int extruder_id = volume->extruder_id - 1;
if ((extruder_id < 0) || ((int)colors.size() <= extruder_id))
if (extruder_id < 0 || (int)colors.size() <= extruder_id)
extruder_id = 0;
const Color& color = colors[extruder_id];
if (!color.text.empty())
{
for (int i = 0; i < 3; ++i)
{
if (!color.text.empty()) {
for (int i = 0; i < 3; ++i) {
volume->color[i] = (float)color.rgb[i] * inv_255;
}
}

View File

@ -515,6 +515,12 @@ public:
// Return an estimate of the memory held by GPU vertex buffers.
size_t gpu_memory_used() const { return this->indexed_vertex_array.gpu_memory_used(); }
size_t total_memory_used() const { return this->cpu_memory_used() + this->gpu_memory_used(); }
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
// calculates the 3D convex hull from indexed_vertex_array.vertices_and_normals_interleaved
// must be called before calling indexed_vertex_array.finalize_geometry();
void calc_convex_hull_3d();
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
};
typedef std::vector<GLVolume*> GLVolumePtrs;

View File

@ -1826,8 +1826,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
assert(volume_idx_wipe_tower_old == -1);
volume_idx_wipe_tower_old = (int)volume_id;
}
if (!m_reload_delayed)
{
if (!m_reload_delayed) {
deleted_volumes.emplace_back(volume, volume_id);
delete volume;
}
@ -5016,8 +5015,7 @@ void GLCanvas3D::_render_background() const
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
ModelInstanceEPrintVolumeState state;
if (m_gcode_viewer.has_data()) {
const ConfigOptionPoints* opt = dynamic_cast<const ConfigOptionPoints*>(m_config->option("bed_shape"));
const Polygon bed_poly = offset(Polygon::new_scale(opt->values), static_cast<float>(scale_(BedEpsilon))).front();
const Polygon bed_poly = offset(Polygon::new_scale(wxGetApp().plater()->get_bed().get_shape()), static_cast<float>(scale_(BedEpsilon))).front();
const float bed_height = m_config->opt_float("max_print_height");
state = printbed_collision_state(bed_poly, bed_height, m_gcode_viewer.get_paths_bounding_box());
}
@ -5813,7 +5811,7 @@ void GLCanvas3D::_load_print_toolpaths()
total_layer_count = std::max(total_layer_count, print_object->total_layer_count());
}
size_t skirt_height = print->has_infinite_skirt() ? total_layer_count : std::min<size_t>(print->config().skirt_height.value, total_layer_count);
if ((skirt_height == 0) && print->has_brim())
if (skirt_height == 0 && print->has_brim())
skirt_height = 1;
// Get first skirt_height layers.
@ -5846,6 +5844,9 @@ void GLCanvas3D::_load_print_toolpaths()
reserve_new_volume_finalize_old_volume(*volume, vol, m_initialized);
}
}
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
volume->calc_convex_hull_3d();
#endif // ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
volume->indexed_vertex_array.finalize_geometry(m_initialized);
}
@ -6136,8 +6137,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];
v->calc_convex_hull_3d();
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();
}
@ -6145,7 +6154,7 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c
void GLCanvas3D::_load_wipe_tower_toolpaths(const std::vector<std::string>& str_tool_colors)
{
const Print *print = this->fff_print();
if ((print == nullptr) || print->wipe_tower_data().tool_changes.empty())
if (print == nullptr || print->wipe_tower_data().tool_changes.empty())
return;
if (!print->is_step_done(psWipeTower))
@ -6293,8 +6302,16 @@ 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];
v->calc_convex_hull_3d();
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();
}
@ -6357,12 +6374,13 @@ void GLCanvas3D::_load_sla_shells()
void GLCanvas3D::_update_toolpath_volumes_outside_state()
{
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
const ConfigOptionPoints* opt = dynamic_cast<const ConfigOptionPoints*>(m_config->option("bed_shape"));
const Polygon bed_poly = offset(Polygon::new_scale(opt->values), static_cast<float>(scale_(BedEpsilon))).front();
const Polygon bed_poly = offset(Polygon::new_scale(wxGetApp().plater()->get_bed().get_shape()), static_cast<float>(scale_(BedEpsilon))).front();
const float bed_height = m_config->opt_float("max_print_height");
for (GLVolume* volume : m_volumes.volumes) {
if (volume->is_extrusion_path) {
const ModelInstanceEPrintVolumeState state = printbed_collision_state(bed_poly, bed_height, volume->bounding_box());
const BoundingBoxf3& bb = volume->transformed_convex_hull_bounding_box();
const Polygon volume_hull_2d = its_convex_hull_2d_above(volume->convex_hull()->its, volume->world_matrix().cast<float>(), 0.0f);
const ModelInstanceEPrintVolumeState state = printbed_collision_state(bed_poly, bed_height, volume_hull_2d, bb.min.z(), bb.max.z());
volume->is_outside = (state != ModelInstancePVS_Inside);
}
else
@ -6379,12 +6397,13 @@ void GLCanvas3D::_update_toolpath_volumes_outside_state()
void GLCanvas3D::_update_sla_shells_outside_state()
{
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
const ConfigOptionPoints* opt = dynamic_cast<const ConfigOptionPoints*>(m_config->option("bed_shape"));
const Polygon bed_poly = offset(Polygon::new_scale(opt->values), static_cast<float>(scale_(BedEpsilon))).front();
const Polygon bed_poly = offset(Polygon::new_scale(wxGetApp().plater()->get_bed().get_shape()), static_cast<float>(scale_(BedEpsilon))).front();
const float bed_height = m_config->opt_float("max_print_height");
for (GLVolume* volume : m_volumes.volumes) {
if (volume->shader_outside_printer_detection_enabled) {
const ModelInstanceEPrintVolumeState state = printbed_collision_state(bed_poly, bed_height, volume->transformed_convex_hull_bounding_box());
const BoundingBoxf3& bb = volume->transformed_convex_hull_bounding_box();
const Polygon volume_hull_2d = its_convex_hull_2d_above(volume->convex_hull()->its, volume->world_matrix().cast<float>(), 0.0f);
const ModelInstanceEPrintVolumeState state = printbed_collision_state(bed_poly, bed_height, volume_hull_2d, bb.min.z(), bb.max.z());
volume->is_outside = (state != ModelInstancePVS_Inside);
}
else
@ -6407,11 +6426,12 @@ void GLCanvas3D::_set_warning_notification_if_needed(EWarning warning)
else {
if (wxGetApp().is_editor()) {
#if ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS
const ConfigOptionPoints* opt = dynamic_cast<const ConfigOptionPoints*>(m_config->option("bed_shape"));
const Polygon bed_poly = offset(Polygon::new_scale(opt->values), static_cast<float>(scale_(BedEpsilon))).front();
const float bed_height = m_config->opt_float("max_print_height");
const ModelInstanceEPrintVolumeState state = printbed_collision_state(bed_poly, bed_height, m_gcode_viewer.get_paths_bounding_box());
show = state != ModelInstancePVS_Inside;
if (current_printer_technology() != ptSLA) {
const Polygon bed_poly = offset(Polygon::new_scale(wxGetApp().plater()->get_bed().get_shape()), static_cast<float>(scale_(BedEpsilon))).front();
const float bed_height = m_config->opt_float("max_print_height");
const ModelInstanceEPrintVolumeState state = printbed_collision_state(bed_poly, bed_height, m_gcode_viewer.get_paths_bounding_box());
show = state != ModelInstancePVS_Inside;
}
#else
BoundingBoxf3 test_volume = (m_config != nullptr) ? print_volume(*m_config) : BoundingBoxf3();
const BoundingBoxf3& paths_volume = m_gcode_viewer.get_paths_bounding_box();
@ -6464,7 +6484,7 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state)
"Resolve the current problem to continue slicing.");
error = ErrorType::PLATER_ERROR;
break;
}
}
auto& notification_manager = *wxGetApp().plater()->get_notification_manager();
switch (error)
{
@ -6494,7 +6514,7 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state)
bool GLCanvas3D::_is_any_volume_outside() const
{
for (const GLVolume* volume : m_volumes.volumes) {
if ((volume != nullptr) && volume->is_outside)
if (volume != nullptr && volume->is_outside)
return true;
}