Merge remote-tracking branch 'remotes/origin/master' into vb_print_regions

This commit is contained in:
Vojtech Bubnik 2021-05-31 14:05:53 +02:00
commit 033d9f3a5e
38 changed files with 1502 additions and 587 deletions

View file

@ -1,6 +1,8 @@
#include "libslic3r/libslic3r.h"
#include "GLCanvas3D.hpp"
#include <igl/unproject.h>
#include "libslic3r/ClipperUtils.hpp"
#include "libslic3r/PrintConfig.hpp"
#include "libslic3r/GCode/ThumbnailData.hpp"
@ -787,6 +789,97 @@ void GLCanvas3D::Tooltip::render(const Vec2d& mouse_position, GLCanvas3D& canvas
ImGui::PopStyleVar(2);
}
#if ENABLE_SEQUENTIAL_LIMITS
void GLCanvas3D::SequentialPrintClearance::set(const Polygons& polygons, bool fill)
{
m_render_fill = fill;
m_perimeter.reset();
m_fill.reset();
if (polygons.empty())
return;
size_t triangles_count = 0;
for (const Polygon& poly : polygons) {
triangles_count += poly.points.size() - 2;
}
size_t vertices_count = 3 * triangles_count;
if (fill) {
GLModel::InitializationData fill_data;
GLModel::InitializationData::Entity entity;
entity.type = GLModel::PrimitiveType::Triangles;
entity.color = { 0.3333f, 0.0f, 0.0f, 0.5f };
entity.positions.reserve(vertices_count);
entity.normals.reserve(vertices_count);
entity.indices.reserve(vertices_count);
ExPolygons polygons_union = union_ex(polygons);
for (const ExPolygon& poly : polygons_union) {
std::vector<Vec3d> triangulation = triangulate_expolygon_3d(poly, false);
for (const Vec3d& v : triangulation) {
entity.positions.emplace_back(v.cast<float>() + Vec3f(0.0f, 0.0f, 0.0125f)); // add a small positive z to avoid z-fighting
entity.normals.emplace_back(Vec3f::UnitZ());
size_t positions_count = entity.positions.size();
if (positions_count % 3 == 0) {
entity.indices.emplace_back(positions_count - 3);
entity.indices.emplace_back(positions_count - 2);
entity.indices.emplace_back(positions_count - 1);
}
}
}
fill_data.entities.emplace_back(entity);
m_fill.init_from(fill_data);
}
GLModel::InitializationData perimeter_data;
for (const Polygon& poly : polygons) {
GLModel::InitializationData::Entity ent;
ent.type = GLModel::PrimitiveType::LineLoop;
ent.positions.reserve(poly.points.size());
ent.indices.reserve(poly.points.size());
unsigned int id_count = 0;
for (const Point& p : poly.points) {
ent.positions.emplace_back(unscale<float>(p.x()), unscale<float>(p.y()), 0.025f); // add a small positive z to avoid z-fighting
ent.normals.emplace_back(Vec3f::UnitZ());
ent.indices.emplace_back(id_count++);
}
perimeter_data.entities.emplace_back(ent);
}
m_perimeter.init_from(perimeter_data);
}
void GLCanvas3D::SequentialPrintClearance::render() const
{
std::array<float, 4> FILL_COLOR = { 1.0f, 0.0f, 0.0f, 0.5f };
std::array<float, 4> NO_FILL_COLOR = { 1.0f, 1.0f, 1.0f, 0.75f };
GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light");
if (shader == nullptr)
return;
shader->start_using();
glsafe(::glEnable(GL_DEPTH_TEST));
glsafe(::glDisable(GL_CULL_FACE));
glsafe(::glEnable(GL_BLEND));
glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
const_cast<GLModel*>(&m_perimeter)->set_color(-1, m_render_fill ? FILL_COLOR : NO_FILL_COLOR);
m_perimeter.render();
m_fill.render();
glsafe(::glDisable(GL_BLEND));
glsafe(::glEnable(GL_CULL_FACE));
glsafe(::glDisable(GL_DEPTH_TEST));
shader->stop_using();
}
#endif // ENABLE_SEQUENTIAL_LIMITS
wxDEFINE_EVENT(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS, SimpleEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_OBJECT_SELECT, SimpleEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_RIGHT_CLICK, RBtnEvent);
@ -1375,7 +1468,11 @@ void GLCanvas3D::render()
_render_sla_slices();
_render_selection();
_render_bed(!camera.is_looking_downward(), true);
#if ENABLE_SEQUENTIAL_LIMITS
if (m_gizmos.get_current_type() == GLGizmosManager::EType::Undefined &&
!m_layers_editing.is_enabled())
_render_sequential_clearance();
#endif // ENABLE_SEQUENTIAL_LIMITS
#if ENABLE_RENDER_SELECTION_CENTER
_render_selection_center();
#endif // ENABLE_RENDER_SELECTION_CENTER
@ -1616,6 +1713,8 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
_set_current();
m_hover_volume_idxs.clear();
struct ModelVolumeState {
ModelVolumeState(const GLVolume* volume) :
model_volume(nullptr), geometry_id(volume->geometry_id), volume_idx(-1) {}
@ -1914,7 +2013,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
bool wt = dynamic_cast<const ConfigOptionBool*>(m_config->option("wipe_tower"))->value;
bool co = dynamic_cast<const ConfigOptionBool*>(m_config->option("complete_objects"))->value;
if ((extruders_count > 1) && wt && !co) {
if (extruders_count > 1 && wt && !co) {
// Height of a print (Show at least a slab)
double height = std::max(m_model->bounding_box().max(2), 10.0);
@ -2861,6 +2960,23 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
m_mouse.set_start_position_3D_as_invalid();
m_mouse.position = pos.cast<double>();
#if ENABLE_SEQUENTIAL_LIMITS
if (evt.Dragging() && current_printer_technology() == ptFFF && fff_print()->config().complete_objects) {
switch (m_gizmos.get_current_type())
{
case GLGizmosManager::EType::Move:
case GLGizmosManager::EType::Scale:
case GLGizmosManager::EType::Rotate:
{
update_sequential_clearance();
break;
}
default: { break; }
}
}
#endif // ENABLE_SEQUENTIAL_LIMITS
return;
}
@ -2983,6 +3099,9 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
m_mouse.drag.move_volume_idx = volume_idx;
m_selection.start_dragging();
m_mouse.drag.start_position_3D = m_mouse.scene_position;
#if ENABLE_SEQUENTIAL_LIMITS
m_sequential_print_clearance_first_displacement = true;
#endif // ENABLE_SEQUENTIAL_LIMITS
m_moving = true;
}
}
@ -3028,6 +3147,10 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
}
m_selection.translate(cur_pos - m_mouse.drag.start_position_3D);
#if ENABLE_SEQUENTIAL_LIMITS
if (current_printer_technology() == ptFFF && fff_print()->config().complete_objects)
update_sequential_clearance();
#endif // ENABLE_SEQUENTIAL_LIMITS
wxGetApp().obj_manipul()->set_dirty();
m_dirty = true;
}
@ -3060,7 +3183,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
// See GH issue #3816.
Camera& camera = wxGetApp().plater()->get_camera();
camera.recover_from_free_camera();
camera.rotate_on_sphere(rot.x(), rot.y(), wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA);
camera.rotate_on_sphere(rot.x(), rot.y(), current_printer_technology() != ptSLA);
}
m_dirty = true;
@ -3277,15 +3400,15 @@ void GLCanvas3D::do_move(const std::string& snapshot_type)
for (const std::pair<int, int>& i : done) {
ModelObject* m = m_model->objects[i.first];
#if ENABLE_ALLOW_NEGATIVE_Z
double shift_z = m->get_instance_min_z(i.second);
const double shift_z = m->get_instance_min_z(i.second);
#if DISABLE_ALLOW_NEGATIVE_Z_FOR_SLA
if (current_printer_technology() == ptSLA || shift_z > 0.0) {
#else
if (shift_z > 0.0) {
#endif // DISABLE_ALLOW_NEGATIVE_Z_FOR_SLA
Vec3d shift(0.0, 0.0, -shift_z);
const Vec3d shift(0.0, 0.0, -shift_z);
#else
Vec3d shift(0.0, 0.0, -m->get_instance_min_z(i.second));
const Vec3d shift(0.0, 0.0, -m->get_instance_min_z(i.second));
#endif // ENABLE_ALLOW_NEGATIVE_Z
m_selection.translate(i.first, i.second, shift);
m->translate_instance(i.second, shift);
@ -3307,6 +3430,10 @@ void GLCanvas3D::do_move(const std::string& snapshot_type)
if (wipe_tower_origin != Vec3d::Zero())
post_event(Vec3dEvent(EVT_GLCANVAS_WIPETOWER_MOVED, std::move(wipe_tower_origin)));
#if ENABLE_SEQUENTIAL_LIMITS
set_sequential_print_clearance(Polygons(), false);
#endif // ENABLE_SEQUENTIAL_LIMITS
m_dirty = true;
}
@ -3653,6 +3780,93 @@ void GLCanvas3D::mouse_up_cleanup()
m_canvas->ReleaseMouse();
}
#if ENABLE_SEQUENTIAL_LIMITS
void GLCanvas3D::update_sequential_clearance()
{
if (current_printer_technology() != ptFFF || !fff_print()->config().complete_objects)
return;
// collects instance transformations from volumes
// first define temporary cache
unsigned int instances_count = 0;
std::vector<std::vector<std::optional<Geometry::Transformation>>> instance_transforms;
for (size_t obj = 0; obj < m_model->objects.size(); ++obj) {
instance_transforms.emplace_back(std::vector<std::optional<Geometry::Transformation>>());
const ModelObject* model_object = m_model->objects[obj];
for (size_t i = 0; i < model_object->instances.size(); ++i) {
instance_transforms[obj].emplace_back(std::optional<Geometry::Transformation>());
++instances_count;
}
}
if (instances_count == 1)
return;
// second fill temporary cache with data from volumes
for (const GLVolume* v : m_volumes.volumes) {
if (v->is_modifier || v->is_wipe_tower)
continue;
auto& transform = instance_transforms[v->object_idx()][v->instance_idx()];
if (!transform.has_value())
transform = v->get_instance_transformation();
}
// calculates objects 2d hulls (see also: Print::sequential_print_horizontal_clearance_valid())
// this is done only the first time this method is called while moving the mouse,
// the results are then cached for following displacements
if (m_sequential_print_clearance_first_displacement) {
m_sequential_print_clearance.m_hull_2d_cache.clear();
float shrink_factor = static_cast<float>(scale_(0.5 * fff_print()->config().extruder_clearance_radius.value - EPSILON));
double mitter_limit = scale_(0.1);
m_sequential_print_clearance.m_hull_2d_cache.reserve(m_model->objects.size());
for (size_t i = 0; i < m_model->objects.size(); ++i) {
ModelObject* model_object = m_model->objects[i];
ModelInstance* model_instance0 = model_object->instances.front();
Polygon hull_2d = offset(model_object->convex_hull_2d(Geometry::assemble_transform({ 0.0, 0.0, model_instance0->get_offset().z() }, model_instance0->get_rotation(),
model_instance0->get_scaling_factor(), model_instance0->get_mirror())),
// Shrink the extruder_clearance_radius a tiny bit, so that if the object arrangement algorithm placed the objects
// exactly by satisfying the extruder_clearance_radius, this test will not trigger collision.
shrink_factor,
jtRound, mitter_limit).front();
Pointf3s& cache_hull_2d = m_sequential_print_clearance.m_hull_2d_cache.emplace_back(Pointf3s());
cache_hull_2d.reserve(hull_2d.points.size());
for (const Point& p : hull_2d.points) {
cache_hull_2d.emplace_back(unscale<double>(p.x()), unscale<double>(p.y()), 0.0);
}
}
m_sequential_print_clearance_first_displacement = false;
}
// calculates instances 2d hulls (see also: Print::sequential_print_horizontal_clearance_valid())
Polygons polygons;
polygons.reserve(instances_count);
for (size_t i = 0; i < instance_transforms.size(); ++i) {
const auto& instances = instance_transforms[i];
double rotation_z0 = instances.front()->get_rotation().z();
for (const auto& instance : instances) {
Geometry::Transformation transformation;
const Vec3d& offset = instance->get_offset();
transformation.set_offset({ offset.x(), offset.y(), 0.0 });
transformation.set_rotation(Z, instance->get_rotation().z() - rotation_z0);
const Transform3d& trafo = transformation.get_matrix();
const Pointf3s& hull_2d = m_sequential_print_clearance.m_hull_2d_cache[i];
Points inst_pts;
inst_pts.reserve(hull_2d.size());
for (size_t j = 0; j < hull_2d.size(); ++j) {
const Vec3d p = trafo * hull_2d[j];
inst_pts.emplace_back(scaled<double>(p.x()), scaled<double>(p.y()));
}
polygons.emplace_back(Geometry::convex_hull(std::move(inst_pts)));
}
}
// sends instances 2d hulls to be rendered
set_sequential_print_clearance(polygons, false);
}
#endif // ENABLE_SEQUENTIAL_LIMITS
bool GLCanvas3D::_is_shown_on_screen() const
{
return (m_canvas != nullptr) ? m_canvas->IsShownOnScreen() : false;
@ -3916,7 +4130,7 @@ void GLCanvas3D::_render_thumbnail_internal(ThumbnailData& thumbnail_data, bool
glsafe(::glEnable(GL_DEPTH_TEST));
shader->start_using();
shader->set_uniform("print_box.volume_detection", 0);
shader->set_uniform("emission_factor", 0.0);
for (GLVolume* vol : visible_volumes) {
shader->set_uniform("uniform_color", (vol->printable && !vol->is_outside) ? orange : gray);
@ -4754,7 +4968,7 @@ void GLCanvas3D::_render_background() const
bool use_error_color = false;
if (wxGetApp().is_editor()) {
use_error_color = m_dynamic_background_enabled &&
(wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA || !m_volumes.empty());
(current_printer_technology() != ptSLA || !m_volumes.empty());
if (!m_volumes.empty())
use_error_color &= _is_any_volume_outside();
@ -4902,6 +5116,13 @@ void GLCanvas3D::_render_selection() const
m_selection.render(scale_factor);
}
#if ENABLE_SEQUENTIAL_LIMITS
void GLCanvas3D::_render_sequential_clearance() const
{
m_sequential_print_clearance.render();
}
#endif // ENABLE_SEQUENTIAL_LIMITS
#if ENABLE_RENDER_SELECTION_CENTER
void GLCanvas3D::_render_selection_center() const
{
@ -5167,7 +5388,7 @@ void GLCanvas3D::_render_camera_target() const
void GLCanvas3D::_render_sla_slices() const
{
if (!m_use_clipping_planes || wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA)
if (!m_use_clipping_planes || current_printer_technology() != ptSLA)
return;
const SLAPrint* print = this->sla_print();
@ -5393,9 +5614,9 @@ Vec3d GLCanvas3D::_mouse_to_3d(const Point& mouse_pos, float* z)
return Vec3d(DBL_MAX, DBL_MAX, DBL_MAX);
const Camera& camera = wxGetApp().plater()->get_camera();
const std::array<int, 4>& viewport = camera.get_viewport();
const Transform3d& modelview_matrix = camera.get_view_matrix();
const Transform3d& projection_matrix = camera.get_projection_matrix();
Matrix4d modelview = camera.get_view_matrix().matrix();
Matrix4d projection= camera.get_projection_matrix().matrix();
Vec4i viewport(camera.get_viewport().data());
GLint y = viewport[3] - (GLint)mouse_pos(1);
GLfloat mouse_z;
@ -5404,9 +5625,9 @@ Vec3d GLCanvas3D::_mouse_to_3d(const Point& mouse_pos, float* z)
else
mouse_z = *z;
GLdouble out_x, out_y, out_z;
::gluUnProject((GLdouble)mouse_pos(0), (GLdouble)y, (GLdouble)mouse_z, (GLdouble*)modelview_matrix.data(), (GLdouble*)projection_matrix.data(), (GLint*)viewport.data(), &out_x, &out_y, &out_z);
return Vec3d((double)out_x, (double)out_y, (double)out_z);
Vec3d out;
igl::unproject(Vec3d(mouse_pos(0), y, mouse_z), modelview, projection, viewport, out);
return out;
}
Vec3d GLCanvas3D::_mouse_to_bed_3d(const Point& mouse_pos)