From 1b8553c747ad5c0eb9bdba46d2b7c8003ef9ad5f Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 20 Mar 2023 14:34:04 +0100 Subject: [PATCH 01/14] Reintroduced visualization of SLA supports and pad into 3D scene and gizmos Hollow and SLA support as it was in 2.5.0 --- src/slic3r/GUI/3DScene.cpp | 61 +++++++ src/slic3r/GUI/3DScene.hpp | 10 ++ src/slic3r/GUI/GLCanvas3D.cpp | 160 ++++++++++++++++++- src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp | 9 ++ src/slic3r/GUI/Gizmos/GLGizmoSlaBase.cpp | 67 ++++++-- src/slic3r/GUI/Gizmos/GLGizmoSlaBase.hpp | 4 + src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp | 7 +- src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp | 97 +++++------ src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp | 4 +- 9 files changed, 337 insertions(+), 82 deletions(-) diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index c25bff45d..843aa6a33 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -564,6 +564,67 @@ int GLVolumeCollection::load_wipe_tower_preview( return int(volumes.size() - 1); } +// Load SLA auxiliary GLVolumes (for support trees or pad). +// This function produces volumes for multiple instances in a single shot, +// as some object specific mesh conversions may be expensive. +void GLVolumeCollection::load_object_auxiliary( + const SLAPrintObject* print_object, + int obj_idx, + // pairs of + const std::vector>& instances, + SLAPrintObjectStep milestone, + // Timestamp of the last change of the milestone + size_t timestamp) +{ + if (print_object->get_mesh_to_print() == nullptr) + return; + const Transform3d mesh_trafo_inv = print_object->trafo().inverse(); + + auto add_volume = [this, &instances, timestamp](int obj_idx, int inst_idx, const ModelInstance& model_instance, SLAPrintObjectStep step, + const TriangleMesh& mesh, const ColorRGBA& color, std::optional convex_hull = std::nullopt) { + if (mesh.empty()) + return; + + GLVolume& v = *this->volumes.emplace_back(new GLVolume(color)); +#if ENABLE_SMOOTH_NORMALS + v.model.init_from(mesh, true); +#else + v.model.init_from(mesh); + v.model.set_color(color); + v.mesh_raycaster = std::make_unique(std::make_shared(mesh)); +#endif // ENABLE_SMOOTH_NORMALS + v.composite_id = GLVolume::CompositeID(obj_idx, -int(step), inst_idx); + v.geometry_id = std::pair(timestamp, model_instance.id().id); + if (convex_hull.has_value()) + v.set_convex_hull(*convex_hull); + v.is_modifier = false; + v.shader_outside_printer_detection_enabled = (step == slaposSupportTree); + v.set_instance_transformation(model_instance.get_transformation()); + }; + + // Get the support mesh. + TriangleMesh supports_mesh = print_object->support_mesh(); + if (!supports_mesh.empty()) { + supports_mesh.transform(mesh_trafo_inv); + TriangleMesh convex_hull = supports_mesh.convex_hull_3d(); + for (const std::pair& instance_idx : instances) { + const ModelInstance& model_instance = *print_object->model_object()->instances[instance_idx.first]; + add_volume(obj_idx, (int)instance_idx.first, model_instance, slaposSupportTree, supports_mesh, GLVolume::SLA_SUPPORT_COLOR, convex_hull); + } + } + + // Get the pad mesh. + TriangleMesh pad_mesh = print_object->pad_mesh(); + if (!pad_mesh.empty()) { + pad_mesh.transform(mesh_trafo_inv); + TriangleMesh convex_hull = pad_mesh.convex_hull_3d(); + for (const std::pair& instance_idx : instances) { + const ModelInstance& model_instance = *print_object->model_object()->instances[instance_idx.first]; + add_volume(obj_idx, (int)instance_idx.first, model_instance, slaposPad, pad_mesh, GLVolume::SLA_PAD_COLOR, convex_hull); + } + } +} + GLVolume* GLVolumeCollection::new_toolpath_volume(const ColorRGBA& rgba) { GLVolume* out = new_nontoolpath_volume(rgba); diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index 9791a0faf..9095885fc 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -430,6 +430,16 @@ public: float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool size_unknown, float brim_width); #endif // ENABLE_OPENGL_ES + // Load SLA auxiliary GLVolumes (for support trees or pad). + void load_object_auxiliary( + const SLAPrintObject* print_object, + int obj_idx, + // pairs of + const std::vector>& instances, + SLAPrintObjectStep milestone, + // Timestamp of the last change of the milestone + size_t timestamp); + GLVolume* new_toolpath_volume(const ColorRGBA& rgba); GLVolume* new_nontoolpath_volume(const ColorRGBA& rgba); // Render the volumes by OpenGL. diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 1f2f668c3..ea79739c4 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1881,6 +1881,15 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re size_t volume_idx; }; + // SLA steps to pull the preview meshes for. + typedef std::array SLASteps; + SLASteps sla_steps = { slaposDrillHoles, slaposSupportTree, slaposPad }; + struct SLASupportState { + std::array::value> step; + }; + // State of the sla_steps for all SLAPrintObjects. + std::vector sla_support_state; + std::vector instance_ids_selected; std::vector map_glvolume_old_to_new(m_volumes.volumes.size(), size_t(-1)); std::vector deleted_volumes; @@ -1906,6 +1915,37 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re } } + if (printer_technology == ptSLA) { + const SLAPrint* sla_print = this->sla_print(); +#ifndef NDEBUG + // Verify that the SLAPrint object is synchronized with m_model. + check_model_ids_equal(*m_model, sla_print->model()); +#endif // NDEBUG + sla_support_state.reserve(sla_print->objects().size()); + for (const SLAPrintObject* print_object : sla_print->objects()) { + SLASupportState state; + for (size_t istep = 0; istep < sla_steps.size(); ++istep) { + state.step[istep] = print_object->step_state_with_timestamp(sla_steps[istep]); + if (state.step[istep].state == PrintStateBase::State::Done) { + std::shared_ptr m = print_object->get_mesh_to_print(); + if (m == nullptr || m->empty()) + // Consider the DONE step without a valid mesh as invalid for the purpose + // of mesh visualization. + state.step[istep].state = PrintStateBase::State::Invalidated; + else { + for (const ModelInstance* model_instance : print_object->model_object()->instances) { + // Only the instances, which are currently printable, will have the SLA support structures kept. + // The instances outside the print bed will have the GLVolumes of their support structures released. + if (model_instance->is_printable()) + aux_volume_state.emplace_back(state.step[istep].timestamp, model_instance->id()); + } + } + } + } + sla_support_state.emplace_back(state); + } + } + std::sort(model_volume_state.begin(), model_volume_state.end(), model_volume_state_lower); std::sort(aux_volume_state.begin(), aux_volume_state.end(), model_volume_state_lower); // Release all ModelVolume based GLVolumes not found in the current Model. Find the GLVolume of a hollowed mesh. @@ -2020,6 +2060,118 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re } } + if (printer_technology == ptSLA) { + size_t idx = 0; + const SLAPrint *sla_print = this->sla_print(); + std::vector shift_zs(m_model->objects.size(), 0); + double relative_correction_z = sla_print->relative_correction().z(); + if (relative_correction_z <= EPSILON) + relative_correction_z = 1.; + for (const SLAPrintObject *print_object : sla_print->objects()) { + SLASupportState &state = sla_support_state[idx ++]; + const ModelObject *model_object = print_object->model_object(); + // Find an index of the ModelObject + int object_idx; + // There may be new SLA volumes added to the scene for this print_object. + // Find the object index of this print_object in the Model::objects list. + auto it = std::find(sla_print->model().objects.begin(), sla_print->model().objects.end(), model_object); + assert(it != sla_print->model().objects.end()); + object_idx = it - sla_print->model().objects.begin(); + // Cache the Z offset to be applied to all volumes with this object_idx. + shift_zs[object_idx] = print_object->get_current_elevation() / relative_correction_z; + // Collect indices of this print_object's instances, for which the SLA support meshes are to be added to the scene. + // pairs of + std::vector> instances[std::tuple_size::value]; + for (size_t print_instance_idx = 0; print_instance_idx < print_object->instances().size(); ++ print_instance_idx) { + const SLAPrintObject::Instance &instance = print_object->instances()[print_instance_idx]; + // Find index of ModelInstance corresponding to this SLAPrintObject::Instance. + auto it = std::find_if(model_object->instances.begin(), model_object->instances.end(), + [&instance](const ModelInstance *mi) { return mi->id() == instance.instance_id; }); + assert(it != model_object->instances.end()); + int instance_idx = it - model_object->instances.begin(); + for (size_t istep = 0; istep < sla_steps.size(); ++istep) { + if (sla_steps[istep] == slaposDrillHoles) { + // Hollowing is a special case, where the mesh from the backend is being loaded into the 1st volume of an instance, + // not into its own GLVolume. + // There shall always be such a GLVolume allocated. + ModelVolumeState key(model_object->volumes.front()->id(), instance.instance_id); + auto it = std::lower_bound(model_volume_state.begin(), model_volume_state.end(), key, model_volume_state_lower); + assert(it != model_volume_state.end() && it->geometry_id == key.geometry_id); + assert(!it->new_geometry()); + GLVolume& volume = *m_volumes.volumes[it->volume_idx]; + if (!volume.offsets.empty() && state.step[istep].timestamp != volume.offsets.front()) { + // The backend either produced a new hollowed mesh, or it invalidated the one that the front end has seen. + volume.model.reset(); + if (state.step[istep].state == PrintStateBase::State::Done) { + std::shared_ptr m = print_object->get_mesh_to_print(); + assert(m != nullptr && !m->empty()); + TriangleMesh mesh(*m); + // sla_trafo does not contain volume trafo. To get a mesh to create + // a new volume from, we have to apply vol trafo inverse separately. + const ModelObject& mo = *m_model->objects[volume.object_idx()]; + Transform3d trafo = sla_print->sla_trafo(mo) * mo.volumes.front()->get_transformation().get_matrix(); + mesh.transform(trafo.inverse()); +#if ENABLE_SMOOTH_NORMALS + volume.model.init_from(mesh, true); +#else + volume.model.init_from(mesh); + volume.mesh_raycaster = std::make_unique(std::make_shared(mesh)); +#endif // ENABLE_SMOOTH_NORMALS + } + else { + // Reload the original volume. +#if ENABLE_SMOOTH_NORMALS + volume.model.init_from(m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh(), true); +#else + const TriangleMesh& new_mesh = m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh(); + volume.model.init_from(new_mesh); + volume.mesh_raycaster = std::make_unique(std::make_shared(new_mesh)); +#endif // ENABLE_SMOOTH_NORMALS + } + } + //FIXME it is an ugly hack to write the timestamp into the "offsets" field to not have to add another member variable + // to the GLVolume. We should refactor GLVolume significantly, so that the GLVolume will not contain member variables + // of various concenrs (model vs. 3D print path). + volume.offsets = { state.step[istep].timestamp }; + } + else if (state.step[istep].state == PrintStateBase::State::Done) { + // Check whether there is an existing auxiliary volume to be updated, or a new auxiliary volume to be created. + ModelVolumeState key(state.step[istep].timestamp, instance.instance_id.id); + auto it = std::lower_bound(aux_volume_state.begin(), aux_volume_state.end(), key, model_volume_state_lower); + assert(it != aux_volume_state.end() && it->geometry_id == key.geometry_id); + if (it->new_geometry()) { + // This can be an SLA support structure that should not be rendered (in case someone used undo + // to revert to before it was generated). If that's the case, we should not generate anything. + if (model_object->sla_points_status != sla::PointsStatus::NoPoints) + instances[istep].emplace_back(std::pair(instance_idx, print_instance_idx)); + else + shift_zs[object_idx] = 0.; + } + else { + // Recycling an old GLVolume. Update the Object/Instance indices into the current Model. + m_volumes.volumes[it->volume_idx]->composite_id = GLVolume::CompositeID(object_idx, m_volumes.volumes[it->volume_idx]->volume_idx(), instance_idx); + m_volumes.volumes[it->volume_idx]->set_instance_transformation(model_object->instances[instance_idx]->get_transformation()); + } + } + } + } + + for (size_t istep = 0; istep < sla_steps.size(); ++istep) { + if (!instances[istep].empty()) + m_volumes.load_object_auxiliary(print_object, object_idx, instances[istep], sla_steps[istep], state.step[istep].timestamp); + } + } + + // Shift-up all volumes of the object so that it has the right elevation with respect to the print bed + for (GLVolume* volume : m_volumes.volumes) { + if (volume->object_idx() < (int)m_model->objects.size() && m_model->objects[volume->object_idx()]->instances[volume->instance_idx()]->is_printable()) { + const SLAPrintObject* po = sla_print->objects()[volume->object_idx()]; + float zoffs = po->get_current_elevation() / sla_print->relative_correction().z(); + volume->set_sla_shift_z(zoffs); + } + } + } + if (printer_technology == ptFFF && m_config->has("nozzle_diameter")) { // Should the wipe tower be visualized ? unsigned int extruders_count = (unsigned int)dynamic_cast(m_config->option("nozzle_diameter"))->values.size(); @@ -6805,9 +6957,9 @@ void GLCanvas3D::_load_sla_shells() // adds objects' volumes for (const SLAPrintObject* obj : print->objects()) { unsigned int initial_volumes_count = (unsigned int)m_volumes.volumes.size(); - for (const SLAPrintObject::Instance& instance : obj->instances()) { - std::shared_ptr m = obj->get_mesh_to_print(); - if (m && !m->empty()) { + std::shared_ptr m = obj->get_mesh_to_print(); + if (m && !m->empty()) { + for (const SLAPrintObject::Instance& instance : obj->instances()) { add_volume(*obj, 0, instance, *m, GLVolume::MODEL_COLOR[0], true); // Set the extruder_id and volume_id to achieve the same color as in the 3D scene when // through the update_volumes_colors_by_extruder() call. @@ -6818,7 +6970,7 @@ void GLCanvas3D::_load_sla_shells() add_volume(*obj, -int(slaposPad), instance, pad_mesh, GLVolume::SLA_PAD_COLOR, false); } } - double shift_z = obj->get_current_elevation(); + const double shift_z = obj->get_current_elevation(); for (unsigned int i = initial_volumes_count; i < m_volumes.volumes.size(); ++ i) { // apply shift z m_volumes.volumes[i]->set_sla_shift_z(shift_z); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp index d04a9cf2f..85e9d16ce 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp @@ -101,6 +101,7 @@ void GLGizmoHollow::on_render() m_selection_rectangle.render(m_parent); m_c->object_clipper()->render_cut(); + m_c->supports_clipper()->render_cut(); glsafe(::glDisable(GL_BLEND)); } @@ -772,6 +773,14 @@ RENDER_AGAIN: if (m_imgui->slider_float("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f")) m_c->object_clipper()->set_position_by_ratio(clp_dist, true); + // make sure supports are shown/hidden as appropriate + ImGui::Separator(); + bool show_sups = are_sla_supports_shown(); + if (m_imgui->checkbox(m_desc["show_supports"], show_sups)) { + show_sla_supports(show_sups); + force_refresh = true; + } + m_imgui->disabled_end(); m_imgui->end(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaBase.cpp index 3ac438902..dac76b391 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaBase.cpp @@ -30,7 +30,8 @@ CommonGizmosDataID GLGizmoSlaBase::on_get_requirements() const int(CommonGizmosDataID::SelectionInfo) | int(CommonGizmosDataID::InstancesHider) | int(CommonGizmosDataID::Raycaster) - | int(CommonGizmosDataID::ObjectClipper)); + | int(CommonGizmosDataID::ObjectClipper) + | int(CommonGizmosDataID::SupportsClipper)); } void GLGizmoSlaBase::update_volumes() @@ -50,27 +51,54 @@ void GLGizmoSlaBase::update_volumes() TriangleMesh backend_mesh; std::shared_ptr preview_mesh_ptr = po->get_mesh_to_print(); - if (preview_mesh_ptr) - backend_mesh = TriangleMesh{*preview_mesh_ptr}; + if (preview_mesh_ptr != nullptr) + backend_mesh = TriangleMesh(*preview_mesh_ptr); if (!backend_mesh.empty()) { - // The backend has generated a valid mesh. Use it - backend_mesh.transform(po->trafo().inverse()); - m_volumes.volumes.emplace_back(new GLVolume()); - GLVolume* new_volume = m_volumes.volumes.back(); - new_volume->model.init_from(backend_mesh); - new_volume->set_instance_transformation(po->model_object()->instances[m_parent.get_selection().get_instance_idx()]->get_transformation()); - new_volume->set_sla_shift_z(po->get_current_elevation()); - new_volume->mesh_raycaster = std::make_unique(backend_mesh); auto last_comp_step = static_cast(po->last_completed_step()); if (last_comp_step == slaposCount) last_comp_step = -1; m_input_enabled = last_comp_step >= m_min_sla_print_object_step; - if (m_input_enabled) - new_volume->selected = true; // to set the proper color - else - new_volume->set_color(DISABLED_COLOR); + + const int object_idx = m_parent.get_selection().get_object_idx(); + const int instance_idx = m_parent.get_selection().get_instance_idx(); + const Geometry::Transformation& inst_trafo = po->model_object()->instances[instance_idx]->get_transformation(); + const double current_elevation = po->get_current_elevation(); + + auto add_volume = [this, object_idx, instance_idx, &inst_trafo, current_elevation](const TriangleMesh& mesh, int volume_id, bool add_mesh_raycaster = false) { + GLVolume* volume = m_volumes.volumes.emplace_back(new GLVolume()); + volume->model.init_from(mesh); + volume->set_instance_transformation(inst_trafo); + volume->set_sla_shift_z(current_elevation); + if (add_mesh_raycaster) + volume->mesh_raycaster = std::make_unique(mesh); + if (m_input_enabled) + volume->selected = true; // to set the proper color + else + volume->set_color(DISABLED_COLOR); + volume->composite_id = GLVolume::CompositeID(object_idx, volume_id, instance_idx); + }; + + const Transform3d po_trafo_inverse = po->trafo().inverse(); + + // main mesh + backend_mesh.transform(po_trafo_inverse); + add_volume(backend_mesh, 0, true); + + // supports mesh + TriangleMesh supports_mesh = po->support_mesh(); + if (!supports_mesh.empty()) { + supports_mesh.transform(po_trafo_inverse); + add_volume(supports_mesh, -int(slaposSupportTree)); + } + + // pad mesh + TriangleMesh pad_mesh = po->pad_mesh(); + if (!pad_mesh.empty()) { + pad_mesh.transform(po_trafo_inverse); + add_volume(pad_mesh, -int(slaposPad)); + } } if (m_volumes.volumes.empty()) { @@ -110,7 +138,11 @@ void GLGizmoSlaBase::render_volumes() clipping_plane.set_normal(-clipping_plane.get_normal()); m_volumes.set_clipping_plane(clipping_plane.get_data()); - m_volumes.render(GLVolumeCollection::ERenderType::Opaque, false, camera.get_view_matrix(), camera.get_projection_matrix()); + for (GLVolume* v : m_volumes.volumes) { + v->is_active = m_show_sla_supports || (!v->is_sla_pad() && !v->is_sla_support()); + } + + m_volumes.render(GLVolumeCollection::ERenderType::Opaque, true, camera.get_view_matrix(), camera.get_projection_matrix()); shader->stop_using(); } @@ -119,7 +151,8 @@ void GLGizmoSlaBase::register_volume_raycasters_for_picking() { for (size_t i = 0; i < m_volumes.volumes.size(); ++i) { const GLVolume* v = m_volumes.volumes[i]; - m_volume_raycasters.emplace_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, VOLUME_RAYCASTERS_BASE_ID + (int)i, *v->mesh_raycaster, v->world_matrix())); + if (!v->is_sla_pad() && !v->is_sla_support()) + m_volume_raycasters.emplace_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, VOLUME_RAYCASTERS_BASE_ID + (int)i, *v->mesh_raycaster, v->world_matrix())); } } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaBase.hpp index 438477598..acda5a8a1 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaBase.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaBase.hpp @@ -40,11 +40,15 @@ protected: bool unproject_on_mesh(const Vec2d& mouse_pos, std::pair& pos_and_normal); + bool are_sla_supports_shown() const { return m_show_sla_supports; } + void show_sla_supports(bool show) { m_show_sla_supports = show; } + const GLVolumeCollection &volumes() const { return m_volumes; } private: GLVolumeCollection m_volumes; bool m_input_enabled{ false }; + bool m_show_sla_supports{ false }; int m_min_sla_print_object_step{ -1 }; std::vector> m_volume_raycasters; }; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index 4d76dfb04..073d3fa29 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -25,8 +25,10 @@ namespace Slic3r { namespace GUI { GLGizmoSlaSupports::GLGizmoSlaSupports(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) - : GLGizmoSlaBase(parent, icon_filename, sprite_id, slaposDrillHoles) -{} +: GLGizmoSlaBase(parent, icon_filename, sprite_id, slaposDrillHoles) +{ + show_sla_supports(true); +} bool GLGizmoSlaSupports::on_init() { @@ -127,6 +129,7 @@ void GLGizmoSlaSupports::on_render() m_selection_rectangle.render(m_parent); m_c->object_clipper()->render_cut(); + m_c->supports_clipper()->render_cut(); glsafe(::glDisable(GL_BLEND)); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp index a8dc16c55..1e5bd7955 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp @@ -453,83 +453,66 @@ void SupportsClipper::on_update() if (! mo || ! is_sla) return; - const GLCanvas3D* canvas = get_pool()->get_canvas(); - const PrintObjects& print_objects = canvas->sla_print()->objects(); - const SLAPrintObject* print_object = (m_print_object_idx >= 0 && m_print_object_idx < int(print_objects.size())) - ? print_objects[m_print_object_idx] - : nullptr; + const SLAPrintObject* print_object = get_pool()->selection_info()->print_object(); + if (print_object == nullptr) + return; - // Find the respective SLAPrintObject. - if (m_print_object_idx < 0 || m_print_objects_count != int(print_objects.size())) { - m_print_objects_count = print_objects.size(); - m_print_object_idx = -1; - for (const SLAPrintObject* po : print_objects) { - ++m_print_object_idx; - if (po->model_object()->id() == mo->id()) { - print_object = po; - break; - } - } + if (print_object->get_mesh_to_print() == nullptr) { + // The object has been not sliced yet. We better dump the cached data. + m_supports_clipper.reset(); + m_pad_clipper.reset(); + return; } - if (print_object - && print_object->is_step_done(slaposSupportTree) - && ! print_object->support_mesh().empty()) - { - // If the supports are already calculated, save the timestamp of the respective step - // so we can later tell they were recalculated. - size_t timestamp = print_object->step_state_with_timestamp(slaposSupportTree).timestamp; - if (! m_clipper || timestamp != m_old_timestamp) { - // The timestamp has changed. - m_clipper.reset(new MeshClipper); - // The mesh should already have the shared vertices calculated. - m_clipper->set_mesh(print_object->support_mesh().its); - m_old_timestamp = timestamp; - } + const TriangleMesh& support_mesh = print_object->support_mesh(); + if (support_mesh.empty()) { + // The supports are not available yet. We better dump the cached data. + m_supports_clipper.reset(); + } + else { + m_supports_clipper.reset(new MeshClipper); + m_supports_clipper->set_mesh(support_mesh.its); + } + + const TriangleMesh& pad_mesh = print_object->pad_mesh(); + if (pad_mesh.empty()) { + // The supports are not available yet. We better dump the cached data. + m_pad_clipper.reset(); + } + else { + m_pad_clipper.reset(new MeshClipper); + m_pad_clipper->set_mesh(pad_mesh.its); } - else - // The supports are not valid. We better dump the cached data. - m_clipper.reset(); } void SupportsClipper::on_release() { - m_clipper.reset(); - m_old_timestamp = 0; + m_supports_clipper.reset(); + m_pad_clipper.reset(); m_print_object_idx = -1; } void SupportsClipper::render_cut() const { const CommonGizmosDataObjects::ObjectClipper* ocl = get_pool()->object_clipper(); - if (ocl->get_position() == 0. - || ! m_clipper) + if (ocl->get_position() == 0.) return; const SelectionInfo* sel_info = get_pool()->selection_info(); - const ModelObject* mo = sel_info->model_object(); - const Geometry::Transformation inst_trafo = mo->instances[sel_info->get_active_instance()]->get_transformation(); - //Geometry::Transformation vol_trafo = mo->volumes.front()->get_transformation(); - Geometry::Transformation trafo = inst_trafo;// * vol_trafo; - trafo.set_offset(trafo.get_offset() + Vec3d(0., 0., sel_info->get_sla_shift())); + const Geometry::Transformation inst_trafo = sel_info->model_object()->instances[sel_info->get_active_instance()]->get_transformation(); + if (m_supports_clipper != nullptr) { + m_supports_clipper->set_plane(*ocl->get_clipping_plane()); + m_supports_clipper->set_transformation(inst_trafo); + m_supports_clipper->render_cut({ 1.0f, 0.f, 0.37f, 1.0f }); + } - // Get transformation of supports - Geometry::Transformation supports_trafo = trafo; - supports_trafo.set_scaling_factor(Vec3d::Ones()); - supports_trafo.set_offset(Vec3d(trafo.get_offset()(0), trafo.get_offset()(1), sel_info->get_sla_shift())); - supports_trafo.set_rotation(Vec3d(0., 0., trafo.get_rotation()(2))); - // I don't know why, but following seems to be correct. - supports_trafo.set_mirror(Vec3d(trafo.get_mirror()(0) * trafo.get_mirror()(1) * trafo.get_mirror()(2), - 1, - 1.)); - - m_clipper->set_plane(*ocl->get_clipping_plane()); - m_clipper->set_transformation(supports_trafo); - - m_clipper->render_cut({ 1.0f, 0.f, 0.37f, 1.0f }); - m_clipper->render_contour({ 1.f, 1.f, 1.f, 1.f }); + if (m_pad_clipper != nullptr) { + m_pad_clipper->set_plane(*ocl->get_clipping_plane()); + m_pad_clipper->set_transformation(inst_trafo); + m_pad_clipper->render_cut({ 0.6f, 0.f, 0.222f, 1.0f }); + } } diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp index 01b888be0..785c66076 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp @@ -293,10 +293,10 @@ protected: void on_release() override; private: - size_t m_old_timestamp = 0; int m_print_object_idx = -1; int m_print_objects_count = 0; - std::unique_ptr m_clipper; + std::unique_ptr m_supports_clipper; + std::unique_ptr m_pad_clipper; }; } // namespace CommonGizmosDataObjects From 9d156463b174b0b18b3aa2fe029bd9668fa306c6 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 21 Mar 2023 14:43:14 +0100 Subject: [PATCH 02/14] Fixed crash when rotating a part after slicing with sla printer --- src/slic3r/GUI/GLCanvas3D.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index ea79739c4..743b4504f 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -3766,7 +3766,7 @@ void GLCanvas3D::do_rotate(const std::string& snapshot_type) model_object->instances[instance_idx]->set_offset(v->get_instance_offset()); #endif // ENABLE_WORLD_COORDINATE } - else if (selection_mode == Selection::Volume) { + else if (selection_mode == Selection::Volume && volume_idx >= 0) { #if ENABLE_WORLD_COORDINATE model_object->volumes[volume_idx]->set_transformation(v->get_volume_transformation()); #else From 37edec974cb85fe7f694d523f000adda86d8d61b Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 21 Mar 2023 15:33:27 +0100 Subject: [PATCH 03/14] Gizmo Hollow - Show clipped supports only when the supports are visible --- src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp | 3 ++- src/slic3r/GUI/Gizmos/GLGizmoSlaBase.cpp | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp index 85e9d16ce..89e0809fd 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp @@ -101,7 +101,8 @@ void GLGizmoHollow::on_render() m_selection_rectangle.render(m_parent); m_c->object_clipper()->render_cut(); - m_c->supports_clipper()->render_cut(); + if (are_sla_supports_shown()) + m_c->supports_clipper()->render_cut(); glsafe(::glDisable(GL_BLEND)); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaBase.cpp index dac76b391..348fa5ca7 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaBase.cpp @@ -144,7 +144,6 @@ void GLGizmoSlaBase::render_volumes() m_volumes.render(GLVolumeCollection::ERenderType::Opaque, true, camera.get_view_matrix(), camera.get_projection_matrix()); shader->stop_using(); - } void GLGizmoSlaBase::register_volume_raycasters_for_picking() From c251122e8993ed5aebc51ad1106cc790bc6dc8fd Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 22 Mar 2023 09:41:30 +0100 Subject: [PATCH 04/14] Fixed SupportsClipper::render_cut() method --- src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp index 1e5bd7955..debb22535 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp @@ -453,18 +453,18 @@ void SupportsClipper::on_update() if (! mo || ! is_sla) return; - const SLAPrintObject* print_object = get_pool()->selection_info()->print_object(); - if (print_object == nullptr) + const SLAPrintObject* po = get_pool()->selection_info()->print_object(); + if (po == nullptr) return; - if (print_object->get_mesh_to_print() == nullptr) { + if (po->get_mesh_to_print() == nullptr) { // The object has been not sliced yet. We better dump the cached data. m_supports_clipper.reset(); m_pad_clipper.reset(); return; } - const TriangleMesh& support_mesh = print_object->support_mesh(); + const TriangleMesh& support_mesh = po->support_mesh(); if (support_mesh.empty()) { // The supports are not available yet. We better dump the cached data. m_supports_clipper.reset(); @@ -474,7 +474,7 @@ void SupportsClipper::on_update() m_supports_clipper->set_mesh(support_mesh.its); } - const TriangleMesh& pad_mesh = print_object->pad_mesh(); + const TriangleMesh& pad_mesh = po->pad_mesh(); if (pad_mesh.empty()) { // The supports are not available yet. We better dump the cached data. m_pad_clipper.reset(); @@ -499,8 +499,16 @@ void SupportsClipper::render_cut() const if (ocl->get_position() == 0.) return; + const SLAPrintObject* po = get_pool()->selection_info()->print_object(); + if (po == nullptr) + return; + + Geometry::Transformation po_trafo(po->trafo()); + const SelectionInfo* sel_info = get_pool()->selection_info(); - const Geometry::Transformation inst_trafo = sel_info->model_object()->instances[sel_info->get_active_instance()]->get_transformation(); + Geometry::Transformation inst_trafo = sel_info->model_object()->instances[sel_info->get_active_instance()]->get_transformation(); + inst_trafo = Geometry::Transformation(inst_trafo.get_matrix() * po_trafo.get_matrix().inverse()); + inst_trafo.set_offset(inst_trafo.get_offset() + Vec3d(0.0, 0.0, sel_info->get_sla_shift())); if (m_supports_clipper != nullptr) { m_supports_clipper->set_plane(*ocl->get_clipping_plane()); From e1c289f51ae51e4fcdeae8c4a68090959497e17f Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 22 Mar 2023 11:00:04 +0100 Subject: [PATCH 05/14] Fixed GLCanvas3D::reload_scene() method to avoid adding volumes coming from the sla backend --- src/slic3r/GUI/GLCanvas3D.cpp | 46 +---------------------------------- 1 file changed, 1 insertion(+), 45 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 743b4504f..a898d08fc 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -2090,51 +2090,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re assert(it != model_object->instances.end()); int instance_idx = it - model_object->instances.begin(); for (size_t istep = 0; istep < sla_steps.size(); ++istep) { - if (sla_steps[istep] == slaposDrillHoles) { - // Hollowing is a special case, where the mesh from the backend is being loaded into the 1st volume of an instance, - // not into its own GLVolume. - // There shall always be such a GLVolume allocated. - ModelVolumeState key(model_object->volumes.front()->id(), instance.instance_id); - auto it = std::lower_bound(model_volume_state.begin(), model_volume_state.end(), key, model_volume_state_lower); - assert(it != model_volume_state.end() && it->geometry_id == key.geometry_id); - assert(!it->new_geometry()); - GLVolume& volume = *m_volumes.volumes[it->volume_idx]; - if (!volume.offsets.empty() && state.step[istep].timestamp != volume.offsets.front()) { - // The backend either produced a new hollowed mesh, or it invalidated the one that the front end has seen. - volume.model.reset(); - if (state.step[istep].state == PrintStateBase::State::Done) { - std::shared_ptr m = print_object->get_mesh_to_print(); - assert(m != nullptr && !m->empty()); - TriangleMesh mesh(*m); - // sla_trafo does not contain volume trafo. To get a mesh to create - // a new volume from, we have to apply vol trafo inverse separately. - const ModelObject& mo = *m_model->objects[volume.object_idx()]; - Transform3d trafo = sla_print->sla_trafo(mo) * mo.volumes.front()->get_transformation().get_matrix(); - mesh.transform(trafo.inverse()); -#if ENABLE_SMOOTH_NORMALS - volume.model.init_from(mesh, true); -#else - volume.model.init_from(mesh); - volume.mesh_raycaster = std::make_unique(std::make_shared(mesh)); -#endif // ENABLE_SMOOTH_NORMALS - } - else { - // Reload the original volume. -#if ENABLE_SMOOTH_NORMALS - volume.model.init_from(m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh(), true); -#else - const TriangleMesh& new_mesh = m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh(); - volume.model.init_from(new_mesh); - volume.mesh_raycaster = std::make_unique(std::make_shared(new_mesh)); -#endif // ENABLE_SMOOTH_NORMALS - } - } - //FIXME it is an ugly hack to write the timestamp into the "offsets" field to not have to add another member variable - // to the GLVolume. We should refactor GLVolume significantly, so that the GLVolume will not contain member variables - // of various concenrs (model vs. 3D print path). - volume.offsets = { state.step[istep].timestamp }; - } - else if (state.step[istep].state == PrintStateBase::State::Done) { + if (state.step[istep].state == PrintStateBase::State::Done) { // Check whether there is an existing auxiliary volume to be updated, or a new auxiliary volume to be created. ModelVolumeState key(state.step[istep].timestamp, instance.instance_id.id); auto it = std::lower_bound(aux_volume_state.begin(), aux_volume_state.end(), key, model_volume_state_lower); From 760f74ce6a2cb458f52fe693afd247b69a0e247e Mon Sep 17 00:00:00 2001 From: YuSanka Date: Wed, 22 Mar 2023 12:36:32 +0100 Subject: [PATCH 06/14] CutGizmo: Respect to the SLA shift --- src/slic3r/GUI/Gizmos/GLGizmoCut.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp index e9b6fa694..5c18e9e96 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp @@ -876,6 +876,7 @@ void GLGizmoCut3D::on_set_state() } m_selected.clear(); m_parent.set_use_color_clip_plane(false); + m_c->selection_info()->set_use_shift(false); } } @@ -1239,7 +1240,10 @@ BoundingBoxf3 GLGizmoCut3D::transformed_bounding_box(const Vec3d& plane_center, { const Selection& selection = m_parent.get_selection(); - const Vec3d& instance_offset = selection.get_first_volume()->get_instance_offset(); + const auto first_volume = selection.get_first_volume(); + Vec3d instance_offset = first_volume->get_instance_offset(); + instance_offset[Z] += first_volume->get_sla_shift_z(); + const auto cut_matrix = Transform3d::Identity() * rotation_m.inverse() * translation_transform(instance_offset - plane_center); const Selection::IndicesList& idxs = selection.get_volume_idxs(); @@ -1357,6 +1361,12 @@ void GLGizmoCut3D::render_clipper_cut() void GLGizmoCut3D::on_render() { + if (m_state == On) { + // This gizmo is showing the object elevated. Tell the common + // SelectionInfo object to lie about the actual shift. + m_c->selection_info()->set_use_shift(true); + } + update_clipper(); init_picking_models(); From e585fd22218f4679d4ba86fbfbb0b63504854d58 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Thu, 23 Mar 2023 10:16:13 +0100 Subject: [PATCH 07/14] Fixed duplication of auxiliary volumes when GLCanvas3D::reload_scene() is called for SLA printers --- src/slic3r/GUI/3DScene.cpp | 32 ++++++++++++++++++-------------- src/slic3r/GUI/GLCanvas3D.cpp | 2 +- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 843aa6a33..f8b41da8a 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -603,24 +603,28 @@ void GLVolumeCollection::load_object_auxiliary( }; // Get the support mesh. - TriangleMesh supports_mesh = print_object->support_mesh(); - if (!supports_mesh.empty()) { - supports_mesh.transform(mesh_trafo_inv); - TriangleMesh convex_hull = supports_mesh.convex_hull_3d(); - for (const std::pair& instance_idx : instances) { - const ModelInstance& model_instance = *print_object->model_object()->instances[instance_idx.first]; - add_volume(obj_idx, (int)instance_idx.first, model_instance, slaposSupportTree, supports_mesh, GLVolume::SLA_SUPPORT_COLOR, convex_hull); + if (milestone == SLAPrintObjectStep::slaposSupportTree) { + TriangleMesh supports_mesh = print_object->support_mesh(); + if (!supports_mesh.empty()) { + supports_mesh.transform(mesh_trafo_inv); + TriangleMesh convex_hull = supports_mesh.convex_hull_3d(); + for (const std::pair& instance_idx : instances) { + const ModelInstance& model_instance = *print_object->model_object()->instances[instance_idx.first]; + add_volume(obj_idx, (int)instance_idx.first, model_instance, slaposSupportTree, supports_mesh, GLVolume::SLA_SUPPORT_COLOR, convex_hull); + } } } // Get the pad mesh. - TriangleMesh pad_mesh = print_object->pad_mesh(); - if (!pad_mesh.empty()) { - pad_mesh.transform(mesh_trafo_inv); - TriangleMesh convex_hull = pad_mesh.convex_hull_3d(); - for (const std::pair& instance_idx : instances) { - const ModelInstance& model_instance = *print_object->model_object()->instances[instance_idx.first]; - add_volume(obj_idx, (int)instance_idx.first, model_instance, slaposPad, pad_mesh, GLVolume::SLA_PAD_COLOR, convex_hull); + if (milestone == SLAPrintObjectStep::slaposPad) { + TriangleMesh pad_mesh = print_object->pad_mesh(); + if (!pad_mesh.empty()) { + pad_mesh.transform(mesh_trafo_inv); + TriangleMesh convex_hull = pad_mesh.convex_hull_3d(); + for (const std::pair& instance_idx : instances) { + const ModelInstance& model_instance = *print_object->model_object()->instances[instance_idx.first]; + add_volume(obj_idx, (int)instance_idx.first, model_instance, slaposPad, pad_mesh, GLVolume::SLA_PAD_COLOR, convex_hull); + } } } } diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index e6b23c4b8..ad1c8fe03 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -2162,7 +2162,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re } update_volumes_colors_by_extruder(); - // Update selection indices based on the old/new GLVolumeCollection. + // Update selection indices based on the old/new GLVolumeCollection. if (m_selection.get_mode() == Selection::Instance) m_selection.instances_changed(instance_ids_selected); else From 84284b44189d73fd57c6a34a80fcea9403859b6c Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Thu, 23 Mar 2023 11:42:46 +0100 Subject: [PATCH 08/14] Fixed crash when scaling object to fit print volume with SLA printers --- src/slic3r/GUI/GLCanvas3D.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index ad1c8fe03..a433f6dbd 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -2119,10 +2119,11 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re // Shift-up all volumes of the object so that it has the right elevation with respect to the print bed for (GLVolume* volume : m_volumes.volumes) { - if (volume->object_idx() < (int)m_model->objects.size() && m_model->objects[volume->object_idx()]->instances[volume->instance_idx()]->is_printable()) { - const SLAPrintObject* po = sla_print->objects()[volume->object_idx()]; - float zoffs = po->get_current_elevation() / sla_print->relative_correction().z(); - volume->set_sla_shift_z(zoffs); + const ModelObject* model_object = (volume->object_idx() < (int)m_model->objects.size()) ? m_model->objects[volume->object_idx()] : nullptr; + if (model_object != nullptr && model_object->instances[volume->instance_idx()]->is_printable()) { + const SLAPrintObject* po = sla_print->get_print_object_by_model_object_id(model_object->id()); + if (po != nullptr) + volume->set_sla_shift_z(po->get_current_elevation() / sla_print->relative_correction().z()); } } } From 582f51cdfd9360cf81dc82843a838faf7a87b4dd Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 24 Mar 2023 08:36:43 +0100 Subject: [PATCH 09/14] Fixed crash when opening Emboss Gizmo pressing 'T' key after slicing an object using SLA printer --- src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp index dd18cb878..a4ba6de32 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp @@ -3444,7 +3444,7 @@ void priv::find_closest_volume(const Selection &selection, for (unsigned int id : indices) { const GLVolume *gl_volume = selection.get_volume(id); const ModelVolume *volume = get_model_volume(*gl_volume, objects); - if (!volume->is_model_part()) continue; + if (volume == nullptr || !volume->is_model_part()) continue; Slic3r::Polygon hull = CameraUtils::create_hull2d(camera, *gl_volume); Vec2d c = hull.centroid().cast(); Vec2d d = c - screen_center; From 6ba067ad36b10641744d88423ce29bbea85b2256 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 24 Mar 2023 08:40:32 +0100 Subject: [PATCH 10/14] Fixed crash when trying to add text on an object sliced using SLA printer by right clicking on supports or pad --- src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp index a4ba6de32..215517470 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp @@ -3394,6 +3394,7 @@ bool priv::start_create_volume_on_surface_job( { assert(gl_volume != nullptr); if (gl_volume == nullptr) return false; + if (gl_volume->volume_idx() < 0) return false; Plater *plater = wxGetApp().plater(); const ModelObjectPtrs &objects = plater->model().objects; From 7f1df7b110c89864b1a10bc52055e6f194645d24 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 24 Mar 2023 12:57:07 +0100 Subject: [PATCH 11/14] Fixed Fit to print volume command when applied to an object sliced using SLA printer --- src/slic3r/GUI/GLCanvas3D.cpp | 15 ++++++++++++--- src/slic3r/GUI/Selection.cpp | 14 +++++++++++++- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index dc4acebbc..b5b4a9ca0 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -3605,6 +3605,9 @@ void GLCanvas3D::do_move(const std::string& snapshot_type) int instance_idx = v->instance_idx(); int volume_idx = v->volume_idx(); + if (volume_idx < 0) + continue; + std::pair done_id(object_idx, instance_idx); if (0 <= object_idx && object_idx < (int)m_model->objects.size()) { @@ -3619,7 +3622,7 @@ void GLCanvas3D::do_move(const std::string& snapshot_type) #else model_object->instances[instance_idx]->set_offset(v->get_instance_offset()); #endif // ENABLE_WORLD_COORDINATE - else if (volume_idx >= 0 && selection_mode == Selection::Volume) + else if (selection_mode == Selection::Volume) #if ENABLE_WORLD_COORDINATE model_object->volumes[volume_idx]->set_transformation(v->get_volume_transformation()); #else @@ -3710,6 +3713,9 @@ void GLCanvas3D::do_rotate(const std::string& snapshot_type) const int instance_idx = v->instance_idx(); const int volume_idx = v->volume_idx(); + if (volume_idx < 0) + continue; + done.insert(std::pair(object_idx, instance_idx)); // Rotate instances/volumes. @@ -3723,7 +3729,7 @@ void GLCanvas3D::do_rotate(const std::string& snapshot_type) model_object->instances[instance_idx]->set_offset(v->get_instance_offset()); #endif // ENABLE_WORLD_COORDINATE } - else if (selection_mode == Selection::Volume && volume_idx >= 0) { + else if (selection_mode == Selection::Volume) { #if ENABLE_WORLD_COORDINATE model_object->volumes[volume_idx]->set_transformation(v->get_volume_transformation()); #else @@ -3786,6 +3792,9 @@ void GLCanvas3D::do_scale(const std::string& snapshot_type) const int instance_idx = v->instance_idx(); const int volume_idx = v->volume_idx(); + if (volume_idx < 0) + continue; + done.insert(std::pair(object_idx, instance_idx)); // Rotate instances/volumes @@ -3799,7 +3808,7 @@ void GLCanvas3D::do_scale(const std::string& snapshot_type) model_object->instances[instance_idx]->set_offset(v->get_instance_offset()); #endif // ENABLE_WORLD_COORDINATE } - else if (selection_mode == Selection::Volume && volume_idx >= 0) { + else if (selection_mode == Selection::Volume) { #if ENABLE_WORLD_COORDINATE model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation()); model_object->volumes[volume_idx]->set_transformation(v->get_volume_transformation()); diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index 2b77fe7ff..28cf367fd 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -1396,6 +1396,18 @@ void Selection::scale_to_fit_print_volume(const BuildVolume& volume) // used to keep track whether the undo/redo snapshot has already been taken bool undoredo_snapshot = false; + if (wxGetApp().plater()->printer_technology() == ptSLA) { + // remove SLA auxiliary volumes from the selection to ensure that the proper bounding box is calculated + std::vector to_remove; + for (unsigned int i : m_list) { + if ((*m_volumes)[i]->volume_idx() < 0) + to_remove.push_back(i); + } + + if (!to_remove.empty()) + remove_volumes(m_mode, to_remove); + } + switch (volume.type()) { case BuildVolume::Type::Rectangle: { undoredo_snapshot = fit_rectangle(volume, !undoredo_snapshot); break; } @@ -3006,7 +3018,7 @@ static void verify_instances_rotation_synchronized(const Model &model, const GLV continue; const Transform3d::ConstLinearPart& rotation0 = volumes[idx_volume_first]->get_instance_transformation().get_matrix().linear(); for (int i = idx_volume_first + 1; i < (int)volumes.size(); ++i) - if (volumes[i]->object_idx() == idx_object) { + if (volumes[i]->object_idx() == idx_object && volumes[i]->volume_idx() >= 0) { const Transform3d::ConstLinearPart& rotation = volumes[i]->get_instance_transformation().get_matrix().linear(); assert(is_rotation_xy_synchronized(rotation, rotation0)); } From 989ca9d8ee4ce442508d2ef949f561d551fc033c Mon Sep 17 00:00:00 2001 From: YuSanka Date: Mon, 27 Mar 2023 16:00:13 +0200 Subject: [PATCH 12/14] CutGizmo: Fix for Cut by Line --- src/slic3r/GUI/Gizmos/GLGizmoCut.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp index c65f4fad0..5d8a69e41 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp @@ -2298,7 +2298,10 @@ bool GLGizmoCut3D::process_cut_line(SLAGizmoEventType action, const Vec2d& mouse const Vec3d new_plane_center = m_bb_center + cross_dir * cross_dir.dot(pt - m_bb_center); // update transformed bb const auto new_tbb = transformed_bounding_box(new_plane_center, m); - const Vec3d& instance_offset = m_parent.get_selection().get_first_volume()->get_instance_offset(); + const GLVolume* first_volume = m_parent.get_selection().get_first_volume(); + Vec3d instance_offset = first_volume->get_instance_offset(); + instance_offset[Z] += first_volume->get_sla_shift_z(); + const Vec3d trans_center_pos = m.inverse() * (new_plane_center - instance_offset) + new_tbb.center(); if (new_tbb.contains(trans_center_pos)) { Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Cut by line"), UndoRedo::SnapshotType::GizmoAction); From 56d15253d41953e2a319f7cf195f1059e6a0075a Mon Sep 17 00:00:00 2001 From: Filip Sykala - NTB T15p Date: Tue, 28 Mar 2023 16:07:00 +0200 Subject: [PATCH 13/14] Fix update of model after finish text jobs. --- src/slic3r/GUI/Jobs/EmbossJob.cpp | 65 +++++++++++++++++++++++-------- src/slic3r/GUI/Jobs/EmbossJob.hpp | 2 +- 2 files changed, 49 insertions(+), 18 deletions(-) diff --git a/src/slic3r/GUI/Jobs/EmbossJob.cpp b/src/slic3r/GUI/Jobs/EmbossJob.cpp index 208cb2c0b..a265c4de9 100644 --- a/src/slic3r/GUI/Jobs/EmbossJob.cpp +++ b/src/slic3r/GUI/Jobs/EmbossJob.cpp @@ -483,10 +483,46 @@ TriangleMesh priv::create_default_mesh() return triangle_mesh; } +namespace{ +void update_volume_name(const ModelVolume &volume, const ObjectList *obj_list) +{ + if (obj_list == nullptr) + return; + + const std::vector* objects = obj_list->objects(); + if (objects == nullptr) + return; + + int object_idx = -1; + int volume_idx = -1; + for (size_t oi = 0; oi < objects->size(); ++oi) { + const ModelObject *mo = objects->at(oi); + if (mo == nullptr) + continue; + if (volume.get_object()->id() != mo->id()) + continue; + const ModelVolumePtrs& volumes = mo->volumes; + for (size_t vi = 0; vi < volumes.size(); ++vi) { + const ModelVolume *mv = volumes[vi]; + if (mv == nullptr) + continue; + if (mv->id() == volume.id()){ + object_idx = static_cast(oi); + volume_idx = static_cast(vi); + break; + } + } + if (volume_idx > 0) + break; + } + obj_list->update_name_in_list(object_idx, volume_idx); +} +} + void UpdateJob::update_volume(ModelVolume *volume, TriangleMesh &&mesh, const TextConfiguration &text_configuration, - const std::string &volume_name) + std::string_view volume_name) { // check inputs bool is_valid_input = @@ -506,19 +542,12 @@ void UpdateJob::update_volume(ModelVolume *volume, // discard information about rotation, should not be stored in volume volume->text_configuration->style.prop.angle.reset(); - GUI_App &app = wxGetApp(); // may be move to input - GLCanvas3D *canvas = app.plater()->canvas3D(); - const Selection &selection = canvas->get_selection(); - const GLVolume *gl_volume = selection.get_volume(*selection.get_volume_idxs().begin()); - int object_idx = gl_volume->object_idx(); + GUI_App &app = wxGetApp(); // may be move ObjectList and Plater to input? + // update volume name in right panel( volume / object name) if (volume->name != volume_name) { volume->name = volume_name; - - // update volume name in right panel( volume / object name) - int volume_idx = gl_volume->volume_idx(); - ObjectList *obj_list = app.obj_list(); - obj_list->update_name_in_list(object_idx, volume_idx); + update_volume_name(*volume, app.obj_list()); } // When text is object. @@ -528,11 +557,12 @@ void UpdateJob::update_volume(ModelVolume *volume, volume->get_object()->ensure_on_bed(); // redraw scene - bool refresh_immediately = false; - canvas->reload_scene(refresh_immediately); + Plater *plater = app.plater(); + if (plater == nullptr) + return; - // Change buttons "Export G-code" into "Slice now" - canvas->post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); + // Update Model and redraw scene + plater->update(); } void priv::update_volume(TriangleMesh &&mesh, const DataUpdate &data, Transform3d* tr) @@ -646,8 +676,9 @@ void priv::create_volume( if (manager.get_current_type() != GLGizmosManager::Emboss) manager.open_gizmo(GLGizmosManager::Emboss); - // redraw scene - canvas->reload_scene(true); + // update model and redraw scene + //canvas->reload_scene(true); + plater->update(); } ModelVolume *priv::get_volume(ModelObjectPtrs &objects, diff --git a/src/slic3r/GUI/Jobs/EmbossJob.hpp b/src/slic3r/GUI/Jobs/EmbossJob.hpp index d3896c0a6..d4b32cf61 100644 --- a/src/slic3r/GUI/Jobs/EmbossJob.hpp +++ b/src/slic3r/GUI/Jobs/EmbossJob.hpp @@ -145,7 +145,7 @@ public: static void update_volume(ModelVolume *volume, TriangleMesh &&mesh, const TextConfiguration &text_configuration, - const std::string &volume_name); + std::string_view volume_name); }; struct SurfaceVolumeData From 392dbba96f13026041e97f6d0e8042d05e326423 Mon Sep 17 00:00:00 2001 From: Filip Sykala - NTB T15p Date: Tue, 28 Mar 2023 17:10:56 +0200 Subject: [PATCH 14/14] Fix offsets for SLA Text dragging with visible supports. --- src/slic3r/GUI/SurfaceDrag.cpp | 72 ++++++++++++---------------------- src/slic3r/GUI/SurfaceDrag.hpp | 3 ++ 2 files changed, 27 insertions(+), 48 deletions(-) diff --git a/src/slic3r/GUI/SurfaceDrag.cpp b/src/slic3r/GUI/SurfaceDrag.cpp index a202ae5de..40b01a2af 100644 --- a/src/slic3r/GUI/SurfaceDrag.cpp +++ b/src/slic3r/GUI/SurfaceDrag.cpp @@ -9,50 +9,6 @@ #include "libslic3r/Emboss.hpp" namespace Slic3r::GUI { - -/// -/// Calculate offset from mouse position to center of text -/// -/// Position on screen[in Px] e.g. mouse position -/// Selected volume(text) -/// Actual position and view direction of camera -/// Offset in screen coordinate -static Vec2d calc_screen_offset_to_volume_center(const Vec2d &screen_coor, const ModelVolume &volume, const Camera &camera) -{ - const Transform3d &volume_tr = volume.get_matrix(); - assert(volume.text_configuration.has_value()); - - auto calc_offset = [&screen_coor, &volume_tr, &camera, &volume](const Transform3d &instrance_tr) -> Vec2d { - Transform3d to_world = instrance_tr * volume_tr; - - // Use fix of .3mf loaded tranformation when exist - if (volume.text_configuration->fix_3mf_tr.has_value()) - to_world = to_world * (*volume.text_configuration->fix_3mf_tr); - // zero point of volume in world coordinate system - Vec3d volume_center = to_world.translation(); - // screen coordinate of volume center - Vec2i coor = CameraUtils::project(camera, volume_center); - return coor.cast() - screen_coor; - }; - - auto object = volume.get_object(); - assert(!object->instances.empty()); - // Speed up for one instance - if (object->instances.size() == 1) - return calc_offset(object->instances.front()->get_matrix()); - - Vec2d nearest_offset; - double nearest_offset_size = std::numeric_limits::max(); - for (const ModelInstance *instance : object->instances) { - Vec2d offset = calc_offset(instance->get_matrix()); - double offset_size = offset.norm(); - if (nearest_offset_size < offset_size) - continue; - nearest_offset_size = offset_size; - nearest_offset = offset; - } - return nearest_offset; -} // Calculate scale in world for check in debug [[maybe_unused]] static std::optional calc_scale(const Matrix3d &from, const Matrix3d &to, const Vec3d &dir) @@ -109,7 +65,8 @@ bool on_mouse_surface_drag(const wxMouseEvent &mouse_event, gl_volumes[hovered_idx_] != gl_volume) return false; - const ModelObject *object = get_model_object(*gl_volume, canvas.get_model()->objects); + const ModelObjectPtrs &objects = canvas.get_model()->objects; + const ModelObject *object = get_model_object(*gl_volume, objects); assert(object != nullptr); if (object == nullptr) return false; @@ -148,7 +105,26 @@ bool on_mouse_surface_drag(const wxMouseEvent &mouse_event, // wxCoord == int --> wx/types.h Vec2i mouse_coord(mouse_event.GetX(), mouse_event.GetY()); Vec2d mouse_pos = mouse_coord.cast(); - Vec2d mouse_offset = calc_screen_offset_to_volume_center(mouse_pos, *volume, camera); + + // world_matrix_fixed() without sla shift + Transform3d to_world = world_matrix_fixed(*gl_volume, objects); + + // zero point of volume in world coordinate system + Vec3d volume_center = to_world.translation(); + // screen coordinate of volume center + Vec2i coor = CameraUtils::project(camera, volume_center); + Vec2d mouse_offset = coor.cast() - mouse_pos; + Vec2d mouse_offset_without_sla_shift = mouse_offset; + if (double sla_shift = gl_volume->get_sla_shift_z(); !is_approx(sla_shift, 0.)) { + Transform3d to_world_without_sla_move = instance->get_matrix() * volume->get_matrix(); + if (volume->text_configuration.has_value() && volume->text_configuration->fix_3mf_tr.has_value()) + to_world_without_sla_move = to_world_without_sla_move * (*volume->text_configuration->fix_3mf_tr); + // zero point of volume in world coordinate system + volume_center = to_world_without_sla_move.translation(); + // screen coordinate of volume center + coor = CameraUtils::project(camera, volume_center); + mouse_offset_without_sla_shift = coor.cast() - mouse_pos; + } Transform3d volume_tr = gl_volume->get_volume_transformation().get_matrix(); @@ -165,7 +141,7 @@ bool on_mouse_surface_drag(const wxMouseEvent &mouse_event, std::optional start_angle; if (up_limit.has_value()) start_angle = Emboss::calc_up(world_tr, *up_limit); - surface_drag = SurfaceDrag{mouse_offset, world_tr, instance_tr_inv, gl_volume, condition, start_angle}; + surface_drag = SurfaceDrag{mouse_offset, world_tr, instance_tr_inv, gl_volume, condition, start_angle, true, mouse_offset_without_sla_shift}; // disable moving with object by mouse canvas.enable_moving(false); @@ -181,7 +157,7 @@ bool on_mouse_surface_drag(const wxMouseEvent &mouse_event, // wxCoord == int --> wx/types.h Vec2i mouse_coord(mouse_event.GetX(), mouse_event.GetY()); Vec2d mouse_pos = mouse_coord.cast(); - Vec2d offseted_mouse = mouse_pos + surface_drag->mouse_offset; + Vec2d offseted_mouse = mouse_pos + surface_drag->mouse_offset_without_sla_shift; std::optional hit = ray_from_camera( raycast_manager, offseted_mouse, camera, &surface_drag->condition); diff --git a/src/slic3r/GUI/SurfaceDrag.hpp b/src/slic3r/GUI/SurfaceDrag.hpp index bb2600c28..48d6a33fe 100644 --- a/src/slic3r/GUI/SurfaceDrag.hpp +++ b/src/slic3r/GUI/SurfaceDrag.hpp @@ -39,6 +39,9 @@ struct SurfaceDrag // Flag whether coordinate hit some volume bool exist_hit = true; + + // hold screen coor offset of cursor from object center without SLA shift + Vec2d mouse_offset_without_sla_shift; }; ///