From 02a22ba991b5516c2ec749e7fd920046e1722744 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Wed, 16 Jan 2019 09:59:25 +0100 Subject: [PATCH 01/18] Fixed convex hull of sla supports --- src/slic3r/GUI/3DScene.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index d44789b7a..0ee89296a 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -696,7 +696,6 @@ void GLVolumeCollection::load_object_auxiliary( mesh.transform(mesh_trafo_inv); // Convex hull is required for out of print bed detection. TriangleMesh convex_hull = mesh.convex_hull_3d(); - convex_hull.transform(mesh_trafo_inv); for (const std::pair &instance_idx : instances) { const ModelInstance &model_instance = *print_object->model_object()->instances[instance_idx.first]; const SLAPrintObject::Instance &print_instance = print_object->instances()[instance_idx.second]; From 52493e17397cac76e79d66ff0d8651863a6468f2 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Wed, 16 Jan 2019 11:10:24 +0100 Subject: [PATCH 02/18] Show gizmos and toolbars tooltips when hovering on a disabled item --- src/slic3r/GUI/GLCanvas3D.cpp | 19 ++++++++++--------- src/slic3r/GUI/GLToolbar.cpp | 20 ++++++++------------ 2 files changed, 18 insertions(+), 21 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 9a2ea4b44..93ba79f2c 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -2800,13 +2800,13 @@ std::string GLCanvas3D::Gizmos::update_hover_state(const GLCanvas3D& canvas, con float icon_size = (float)it->second->get_textures_size() * OverlayIconsScale; + bool inside = (OverlayBorder <= (float)mouse_pos(0)) && ((float)mouse_pos(0) <= OverlayBorder + icon_size) && (top_y <= (float)mouse_pos(1)) && ((float)mouse_pos(1) <= top_y + icon_size); + if (inside) + name = it->second->get_name(); + if (it->second->is_activable(selection) && (it->second->get_state() != GLGizmoBase::On)) - { - bool inside = (OverlayBorder <= (float)mouse_pos(0)) && ((float)mouse_pos(0) <= OverlayBorder + icon_size) && (top_y <= (float)mouse_pos(1)) && ((float)mouse_pos(1) <= top_y + icon_size); it->second->set_state(inside ? GLGizmoBase::Hover : GLGizmoBase::Off); - if (inside) - name = it->second->get_name(); - } + top_y += (icon_size + OverlayGapY); } @@ -5365,9 +5365,8 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) std::string tooltip = ""; // updates gizmos overlay - if (!m_selection.is_empty()) - tooltip = m_gizmos.update_hover_state(*this, m_mouse.position, m_selection); - else + tooltip = m_gizmos.update_hover_state(*this, m_mouse.position, m_selection); + if (m_selection.is_empty()) m_gizmos.reset_all_states(); // updates toolbar overlay @@ -5452,7 +5451,9 @@ void GLCanvas3D::set_tooltip(const std::string& tooltip) const wxToolTip* t = m_canvas->GetToolTip(); if (t != nullptr) { - if (t->GetTip() != tooltip) + if (tooltip.empty()) + m_canvas->UnsetToolTip(); + else t->SetTip(tooltip); } else diff --git a/src/slic3r/GUI/GLToolbar.cpp b/src/slic3r/GUI/GLToolbar.cpp index 0efc19dee..8a9c12f26 100644 --- a/src/slic3r/GUI/GLToolbar.cpp +++ b/src/slic3r/GUI/GLToolbar.cpp @@ -530,6 +530,8 @@ std::string GLToolbar::update_hover_state_horizontal(const Vec2d& mouse_pos, GLC GLToolbarItem::EState state = item->get_state(); bool inside = (left <= (float)scaled_mouse_pos(0)) && ((float)scaled_mouse_pos(0) <= right) && (bottom <= (float)scaled_mouse_pos(1)) && ((float)scaled_mouse_pos(1) <= top); + if (inside) + tooltip = item->get_tooltip(); switch (state) { @@ -545,9 +547,7 @@ std::string GLToolbar::update_hover_state_horizontal(const Vec2d& mouse_pos, GLC } case GLToolbarItem::Hover: { - if (inside) - tooltip = item->get_tooltip(); - else + if (!inside) { item->set_state(GLToolbarItem::Normal); parent.set_as_dirty(); @@ -567,9 +567,7 @@ std::string GLToolbar::update_hover_state_horizontal(const Vec2d& mouse_pos, GLC } case GLToolbarItem::HoverPressed: { - if (inside) - tooltip = item->get_tooltip(); - else + if (!inside) { item->set_state(GLToolbarItem::Pressed); parent.set_as_dirty(); @@ -623,6 +621,8 @@ std::string GLToolbar::update_hover_state_vertical(const Vec2d& mouse_pos, GLCan GLToolbarItem::EState state = item->get_state(); bool inside = (left <= (float)scaled_mouse_pos(0)) && ((float)scaled_mouse_pos(0) <= right) && (bottom <= (float)scaled_mouse_pos(1)) && ((float)scaled_mouse_pos(1) <= top); + if (inside) + tooltip = item->get_tooltip(); switch (state) { @@ -638,9 +638,7 @@ std::string GLToolbar::update_hover_state_vertical(const Vec2d& mouse_pos, GLCan } case GLToolbarItem::Hover: { - if (inside) - tooltip = item->get_tooltip(); - else + if (!inside) { item->set_state(GLToolbarItem::Normal); parent.set_as_dirty(); @@ -660,9 +658,7 @@ std::string GLToolbar::update_hover_state_vertical(const Vec2d& mouse_pos, GLCan } case GLToolbarItem::HoverPressed: { - if (inside) - tooltip = item->get_tooltip(); - else + if (!inside) { item->set_state(GLToolbarItem::Pressed); parent.set_as_dirty(); From 8146be5510c76cb6a678cee036bf766dfbfb3c2d Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Wed, 16 Jan 2019 11:51:30 +0100 Subject: [PATCH 03/18] Added shortcut strings to gizmos and toolbars tooltips --- src/slic3r/GUI/GLCanvas3D.cpp | 12 ++++++------ src/slic3r/GUI/GLGizmo.cpp | 13 ++++++------- src/slic3r/GUI/KBShortcutsDialog.cpp | 3 +-- src/slic3r/GUI/Plater.cpp | 4 ++-- 4 files changed, 15 insertions(+), 17 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 93ba79f2c..4e2eae7a6 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -5784,7 +5784,7 @@ bool GLCanvas3D::_init_toolbar() GLToolbarItem::Data item; item.name = "add"; - item.tooltip = GUI::L_str("Add..."); + item.tooltip = GUI::L_str("Add... [Ctrl+I]"); item.sprite_id = 0; item.is_toggable = false; item.action_event = EVT_GLTOOLBAR_ADD; @@ -5792,7 +5792,7 @@ bool GLCanvas3D::_init_toolbar() return false; item.name = "delete"; - item.tooltip = GUI::L_str("Delete"); + item.tooltip = GUI::L_str("Delete [Del]"); item.sprite_id = 1; item.is_toggable = false; item.action_event = EVT_GLTOOLBAR_DELETE; @@ -5800,7 +5800,7 @@ bool GLCanvas3D::_init_toolbar() return false; item.name = "deleteall"; - item.tooltip = GUI::L_str("Delete all"); + item.tooltip = GUI::L_str("Delete all [Ctrl+Del]"); item.sprite_id = 2; item.is_toggable = false; item.action_event = EVT_GLTOOLBAR_DELETE_ALL; @@ -5808,7 +5808,7 @@ bool GLCanvas3D::_init_toolbar() return false; item.name = "arrange"; - item.tooltip = GUI::L_str("Arrange"); + item.tooltip = GUI::L_str("Arrange [A]"); item.sprite_id = 3; item.is_toggable = false; item.action_event = EVT_GLTOOLBAR_ARRANGE; @@ -5819,7 +5819,7 @@ bool GLCanvas3D::_init_toolbar() return false; item.name = "more"; - item.tooltip = GUI::L_str("Add instance"); + item.tooltip = GUI::L_str("Add instance [+]"); item.sprite_id = 4; item.is_toggable = false; item.action_event = EVT_GLTOOLBAR_MORE; @@ -5827,7 +5827,7 @@ bool GLCanvas3D::_init_toolbar() return false; item.name = "fewer"; - item.tooltip = GUI::L_str("Remove instance"); + item.tooltip = GUI::L_str("Remove instance [-]"); item.sprite_id = 5; item.is_toggable = false; item.action_event = EVT_GLTOOLBAR_FEWER; diff --git a/src/slic3r/GUI/GLGizmo.cpp b/src/slic3r/GUI/GLGizmo.cpp index dda89d5f9..a7953572e 100644 --- a/src/slic3r/GUI/GLGizmo.cpp +++ b/src/slic3r/GUI/GLGizmo.cpp @@ -748,7 +748,7 @@ bool GLGizmoRotate3D::on_init() std::string GLGizmoRotate3D::on_get_name() const { - return L("Rotate"); + return L("Rotate [R]"); } void GLGizmoRotate3D::on_start_dragging(const GLCanvas3D::Selection& selection) @@ -838,7 +838,7 @@ bool GLGizmoScale3D::on_init() std::string GLGizmoScale3D::on_get_name() const { - return L("Scale"); + return L("Scale [S]"); } void GLGizmoScale3D::on_start_dragging(const GLCanvas3D::Selection& selection) @@ -1197,7 +1197,7 @@ bool GLGizmoMove3D::on_init() std::string GLGizmoMove3D::on_get_name() const { - return L("Move"); + return L("Move [M]"); } void GLGizmoMove3D::on_start_dragging(const GLCanvas3D::Selection& selection) @@ -1427,7 +1427,7 @@ bool GLGizmoFlatten::on_init() std::string GLGizmoFlatten::on_get_name() const { - return L("Place on face"); + return L("Place on face [F]"); } bool GLGizmoFlatten::on_is_activable(const GLCanvas3D::Selection& selection) const @@ -2240,9 +2240,8 @@ bool GLGizmoSlaSupports::on_is_selectable() const } std::string GLGizmoSlaSupports::on_get_name() const - { - return L("SLA Support Points"); + return L("SLA Support Points [L]"); } @@ -2353,7 +2352,7 @@ bool GLGizmoCut::on_init() std::string GLGizmoCut::on_get_name() const { - return L("Cut"); + return L("Cut [C]"); } void GLGizmoCut::on_set_state() diff --git a/src/slic3r/GUI/KBShortcutsDialog.cpp b/src/slic3r/GUI/KBShortcutsDialog.cpp index 939301635..688cf1af0 100644 --- a/src/slic3r/GUI/KBShortcutsDialog.cpp +++ b/src/slic3r/GUI/KBShortcutsDialog.cpp @@ -120,8 +120,7 @@ void KBShortcutsDialog::fill_shortcuts() main_shortcuts.push_back(Shortcut("+" ,L("Add Instance to selected object "))); main_shortcuts.push_back(Shortcut("-" ,L("Remove Instance from selected object"))); main_shortcuts.push_back(Shortcut("?" ,L("Show keyboard shortcuts list"))); - main_shortcuts.push_back(Shortcut("PgUp/PgDn" ,L("Switch between 3D and Preview"))); - main_shortcuts.push_back(Shortcut("Shift+LeftMouse" ,L("Select multiple object/Move multiple object"))); + main_shortcuts.push_back(Shortcut("Shift+LeftMouse", L("Select multiple object/Move multiple object"))); m_full_shortcuts.emplace(_(L("Main Shortcuts")), main_shortcuts); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 96a6b1cff..d3dad31e9 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -2490,7 +2490,7 @@ void Plater::priv::init_view_toolbar() GLToolbarItem::Data item; item.name = "3D"; - item.tooltip = GUI::L_str("3D editor view"); + item.tooltip = GUI::L_str("3D editor view [Ctrl+5]"); item.sprite_id = 0; item.action_event = EVT_GLVIEWTOOLBAR_3D; item.is_toggable = false; @@ -2498,7 +2498,7 @@ void Plater::priv::init_view_toolbar() return; item.name = "Preview"; - item.tooltip = GUI::L_str("Preview"); + item.tooltip = GUI::L_str("Preview [Ctrl+6]"); item.sprite_id = 1; item.action_event = EVT_GLVIEWTOOLBAR_PREVIEW; item.is_toggable = false; From 7b449a53618c226e7098cf017e6a59293ec5880d Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 16 Jan 2019 14:39:25 +0100 Subject: [PATCH 04/18] Place on bed - increased tolerance for neighbouring triangles normals differences --- src/slic3r/GUI/GLGizmo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/GLGizmo.cpp b/src/slic3r/GUI/GLGizmo.cpp index a7953572e..9decc625d 100644 --- a/src/slic3r/GUI/GLGizmo.cpp +++ b/src/slic3r/GUI/GLGizmo.cpp @@ -1559,7 +1559,7 @@ void GLGizmoFlatten::update_planes() while (facet_queue_cnt > 0) { int facet_idx = facet_queue[-- facet_queue_cnt]; const stl_normal& this_normal = ch.stl.facet_start[facet_idx].normal; - if (this_normal.isApprox(*normal_ptr)) { + if (std::abs(this_normal(0) - (*normal_ptr)(0)) < 0.001 && std::abs(this_normal(1) - (*normal_ptr)(1)) < 0.001 && std::abs(this_normal(2) - (*normal_ptr)(2)) < 0.001) { stl_vertex* first_vertex = ch.stl.facet_start[facet_idx].vertex; for (int j=0; j<3; ++j) m_planes.back().vertices.emplace_back((double)first_vertex[j](0), (double)first_vertex[j](1), (double)first_vertex[j](2)); From e8d63f3eb13052ba8d813e6599a50c4eb0b6ecb4 Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Wed, 16 Jan 2019 12:22:17 +0100 Subject: [PATCH 05/18] Upgrade Boost to 1.66 on Windows --- deps/deps-windows.cmake | 4 ++-- src/libslic3r/CMakeLists.txt | 4 ++-- src/libslic3r/libslic3r.h | 4 +++- src/slic3r/GUI/Tab.cpp | 2 +- xs/CMakeLists.txt | 2 +- xs/main.xs.in | 2 +- xs/src/perlglue.cpp | 2 +- xs/src/xsinit.h | 9 ++++++++- xs/xsp/my.map | 6 +++--- xs/xsp/typemap.xspt | 6 +++--- 10 files changed, 25 insertions(+), 16 deletions(-) diff --git a/deps/deps-windows.cmake b/deps/deps-windows.cmake index ec61cb422..44a1843bb 100644 --- a/deps/deps-windows.cmake +++ b/deps/deps-windows.cmake @@ -15,8 +15,8 @@ endif () ExternalProject_Add(dep_boost EXCLUDE_FROM_ALL 1 - URL "https://dl.bintray.com/boostorg/release/1.63.0/source/boost_1_63_0.tar.gz" - URL_HASH SHA256=fe34a4e119798e10b8cc9e565b3b0284e9fd3977ec8a1b19586ad1dec397088b + URL "https://dl.bintray.com/boostorg/release/1.66.0/source/boost_1_66_0.tar.gz" + URL_HASH SHA256=bd0df411efd9a585e5a2212275f8762079fed8842264954675a4fddc46cfcf60 BUILD_IN_SOURCE 1 CONFIGURE_COMMAND bootstrap.bat BUILD_COMMAND b2.exe diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index c97d3d972..baf860bd4 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -88,8 +88,8 @@ add_library(libslic3r STATIC GCode.hpp GCodeReader.cpp GCodeReader.hpp - GCodeSender.cpp - GCodeSender.hpp + # GCodeSender.cpp + # GCodeSender.hpp GCodeTimeEstimator.cpp GCodeTimeEstimator.hpp GCodeWriter.cpp diff --git a/src/libslic3r/libslic3r.h b/src/libslic3r/libslic3r.h index f8088faea..19c6d3065 100644 --- a/src/libslic3r/libslic3r.h +++ b/src/libslic3r/libslic3r.h @@ -4,6 +4,8 @@ #include "libslic3r_version.h" // this needs to be included early for MSVC (listing it in Build.PL is not enough) +#include +#include #include #include #include @@ -13,7 +15,7 @@ #include #include #include -#include +#include #include "Technologies.hpp" diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 452e3bf20..02366c721 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -1,4 +1,4 @@ -#include "libslic3r/GCodeSender.hpp" +// #include "libslic3r/GCodeSender.hpp" #include "Tab.hpp" #include "PresetBundle.hpp" #include "PresetHints.hpp" diff --git a/xs/CMakeLists.txt b/xs/CMakeLists.txt index f14499bf9..4696badc4 100644 --- a/xs/CMakeLists.txt +++ b/xs/CMakeLists.txt @@ -53,7 +53,7 @@ set(XS_XSP_FILES ${XSP_DIR}/Filler.xsp ${XSP_DIR}/Flow.xsp ${XSP_DIR}/GCode.xsp - ${XSP_DIR}/GCodeSender.xsp + # ${XSP_DIR}/GCodeSender.xsp ${XSP_DIR}/Geometry.xsp ${XSP_DIR}/Layer.xsp ${XSP_DIR}/Line.xsp diff --git a/xs/main.xs.in b/xs/main.xs.in index d2bb2518b..3523d569e 100644 --- a/xs/main.xs.in +++ b/xs/main.xs.in @@ -2,7 +2,7 @@ #include #include #include -#include +// #include #ifdef __cplusplus extern "C" { diff --git a/xs/src/perlglue.cpp b/xs/src/perlglue.cpp index 98a124c3f..bcf84b957 100644 --- a/xs/src/perlglue.cpp +++ b/xs/src/perlglue.cpp @@ -16,7 +16,7 @@ REGISTER_CLASS(Flow, "Flow"); REGISTER_CLASS(CoolingBuffer, "GCode::CoolingBuffer"); REGISTER_CLASS(GCode, "GCode"); REGISTER_CLASS(GCodePreviewData, "GCode::PreviewData"); -REGISTER_CLASS(GCodeSender, "GCode::Sender"); +// REGISTER_CLASS(GCodeSender, "GCode::Sender"); REGISTER_CLASS(Layer, "Layer"); REGISTER_CLASS(SupportLayer, "Layer::Support"); REGISTER_CLASS(LayerRegion, "Layer::Region"); diff --git a/xs/src/xsinit.h b/xs/src/xsinit.h index e36376bd1..506ef0a0b 100644 --- a/xs/src/xsinit.h +++ b/xs/src/xsinit.h @@ -37,7 +37,7 @@ #include #include #include -#include +// #include #ifdef SLIC3RXS extern "C" { @@ -68,12 +68,19 @@ extern "C" { #undef fputc #undef fwrite #undef fclose + #undef sleep + #undef test + #undef accept + #undef wait // Breaks compilation with Eigen matrices embedded into Slic3r::Point. #undef malloc #undef realloc #undef free #undef select + + // Because of TBB + #define _WIN32_WINNT 0x0502 #endif /* _MSC_VER */ #undef Zero #undef Packet diff --git a/xs/xsp/my.map b/xs/xsp/my.map index 07e4a3799..fd50d2975 100644 --- a/xs/xsp/my.map +++ b/xs/xsp/my.map @@ -199,9 +199,9 @@ MotionPlanner* O_OBJECT_SLIC3R Ref O_OBJECT_SLIC3R_T Clone O_OBJECT_SLIC3R_T -GCodeSender* O_OBJECT_SLIC3R -Ref O_OBJECT_SLIC3R_T -Clone O_OBJECT_SLIC3R_T +// GCodeSender* O_OBJECT_SLIC3R +// Ref O_OBJECT_SLIC3R_T +// Clone O_OBJECT_SLIC3R_T BridgeDetector* O_OBJECT_SLIC3R Ref O_OBJECT_SLIC3R_T diff --git a/xs/xsp/typemap.xspt b/xs/xsp/typemap.xspt index 121033db4..7e277703b 100644 --- a/xs/xsp/typemap.xspt +++ b/xs/xsp/typemap.xspt @@ -100,9 +100,9 @@ %typemap{MotionPlanner*}; %typemap{Ref}{simple}; %typemap{Clone}{simple}; -%typemap{GCodeSender*}; -%typemap{Ref}{simple}; -%typemap{Clone}{simple}; +// %typemap{GCodeSender*}; +// %typemap{Ref}{simple}; +// %typemap{Clone}{simple}; %typemap{BridgeDetector*}; %typemap{Ref}{simple}; %typemap{Clone}{simple}; From aa7ff0700b4af1ec81d9d2b6ba37c53def1f9bcb Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 17 Jan 2019 13:21:33 +0100 Subject: [PATCH 06/18] Reworked management of bed shape changes (may fix #1671) --- src/libslic3r/Technologies.hpp | 2 ++ src/slic3r/GUI/GLCanvas3D.cpp | 33 +++++++++++++++++++++++++++++++++ src/slic3r/GUI/GLCanvas3D.hpp | 8 ++++++++ src/slic3r/GUI/GUI_Preview.cpp | 4 ++++ src/slic3r/GUI/Plater.cpp | 10 +++++++--- 5 files changed, 54 insertions(+), 3 deletions(-) diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index 3d63f781c..05bb07616 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -60,3 +60,5 @@ #define ENABLE_MOVE_MIN_THRESHOLD (1 && ENABLE_1_42_0_ALPHA4) // Modified initial default placement of generic subparts #define ENABLE_GENERIC_SUBPARTS_PLACEMENT (1 && ENABLE_1_42_0_ALPHA4) +// Reworked management of bed shape changes +#define ENABLE_REWORKED_BED_SHAPE_CHANGE (1 && ENABLE_1_42_0_ALPHA4) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 4e2eae7a6..16f519455 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -3718,7 +3718,11 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas) , m_dirty(true) , m_initialized(false) , m_use_VBOs(false) +#if ENABLE_REWORKED_BED_SHAPE_CHANGE + , m_requires_zoom_to_bed(false) +#else , m_force_zoom_to_bed_enabled(false) +#endif // ENABLE_REWORKED_BED_SHAPE_CHANGE , m_apply_zoom_to_volumes_filter(false) , m_hover_volume_id(-1) , m_toolbar_action_running(false) @@ -3937,7 +3941,11 @@ void GLCanvas3D::set_bed_shape(const Pointfs& shape) set_bed_axes_length(0.1 * m_bed.get_bounding_box().max_size()); if (new_shape) +#if ENABLE_REWORKED_BED_SHAPE_CHANGE + m_requires_zoom_to_bed = true; +#else zoom_to_bed(); +#endif // ENABLE_REWORKED_BED_SHAPE_CHANGE m_dirty = true; } @@ -4032,10 +4040,12 @@ void GLCanvas3D::enable_toolbar(bool enable) m_toolbar.set_enabled(enable); } +#if !ENABLE_REWORKED_BED_SHAPE_CHANGE void GLCanvas3D::enable_force_zoom_to_bed(bool enable) { m_force_zoom_to_bed_enabled = enable; } +#endif // !ENABLE_REWORKED_BED_SHAPE_CHANGE void GLCanvas3D::enable_dynamic_background(bool enable) { @@ -4116,6 +4126,9 @@ void GLCanvas3D::set_viewport_from_scene(const GLCanvas3D& other) m_camera.set_scene_box(other.m_camera.get_scene_box(), *this); m_camera.set_target(other.m_camera.get_target(), *this); m_camera.zoom = other.m_camera.zoom; +#if ENABLE_REWORKED_BED_SHAPE_CHANGE + m_requires_zoom_to_bed = false; +#endif // ENABLE_REWORKED_BED_SHAPE_CHANGE m_dirty = true; } @@ -4168,8 +4181,18 @@ void GLCanvas3D::render() #endif // ENABLE_USE_UNIQUE_GLCONTEXT return; +#if ENABLE_REWORKED_BED_SHAPE_CHANGE + if (m_requires_zoom_to_bed) + { + zoom_to_bed(); + const Size& cnv_size = get_canvas_size(); + _resize((unsigned int)cnv_size.get_width(), (unsigned int)cnv_size.get_height()); + m_requires_zoom_to_bed = false; + } +#else if (m_force_zoom_to_bed_enabled) _force_zoom_to_bed(); +#endif // ENABLE_REWORKED_BED_SHAPE_CHANGE _camera_tranform(); @@ -5738,11 +5761,13 @@ bool GLCanvas3D::_is_shown_on_screen() const return (m_canvas != nullptr) ? m_canvas->IsShownOnScreen() : false; } +#if !ENABLE_REWORKED_BED_SHAPE_CHANGE void GLCanvas3D::_force_zoom_to_bed() { zoom_to_bed(); m_force_zoom_to_bed_enabled = false; } +#endif // !ENABLE_REWORKED_BED_SHAPE_CHANGE bool GLCanvas3D::_init_toolbar() { @@ -5974,7 +5999,11 @@ void GLCanvas3D::_zoom_to_bounding_box(const BoundingBoxf3& bbox) viewport_changed(); +#if ENABLE_REWORKED_BED_SHAPE_CHANGE + m_dirty = true; +#else _refresh_if_shown_on_screen(); +#endif // ENABLE_REWORKED_BED_SHAPE_CHANGE } } @@ -6076,11 +6105,15 @@ void GLCanvas3D::_refresh_if_shown_on_screen() // Because of performance problems on macOS, where PaintEvents are not delivered // frequently enough, we call render() here directly when we can. +#if ENABLE_REWORKED_BED_SHAPE_CHANGE + render(); +#else // We can't do that when m_force_zoom_to_bed_enabled == true, because then render() // ends up calling back here via _force_zoom_to_bed(), causing a stack overflow. if (m_canvas != nullptr) { m_force_zoom_to_bed_enabled ? m_canvas->Refresh() : render(); } +#endif // ENABLE_REWORKED_BED_SHAPE_CHANGE } } diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index f1ccdf54b..625c73169 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -829,7 +829,11 @@ private: bool m_dirty; bool m_initialized; bool m_use_VBOs; +#if ENABLE_REWORKED_BED_SHAPE_CHANGE + bool m_requires_zoom_to_bed; +#else bool m_force_zoom_to_bed_enabled; +#endif // ENABLE_REWORKED_BED_SHAPE_CHANGE bool m_apply_zoom_to_volumes_filter; mutable int m_hover_volume_id; bool m_toolbar_action_running; @@ -920,7 +924,9 @@ public: void enable_moving(bool enable); void enable_gizmos(bool enable); void enable_toolbar(bool enable); +#if !ENABLE_REWORKED_BED_SHAPE_CHANGE void enable_force_zoom_to_bed(bool enable); +#endif // !ENABLE_REWORKED_BED_SHAPE_CHANGE void enable_dynamic_background(bool enable); void allow_multisample(bool allow); @@ -1001,7 +1007,9 @@ public: private: bool _is_shown_on_screen() const; +#if !ENABLE_REWORKED_BED_SHAPE_CHANGE void _force_zoom_to_bed(); +#endif // !ENABLE_REWORKED_BED_SHAPE_CHANGE bool _init_toolbar(); diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp index f791145a2..ad432c273 100644 --- a/src/slic3r/GUI/GUI_Preview.cpp +++ b/src/slic3r/GUI/GUI_Preview.cpp @@ -69,7 +69,9 @@ bool View3D::init(wxWindow* parent, Model* model, DynamicPrintConfig* config, Ba m_canvas->set_config(config); m_canvas->enable_gizmos(true); m_canvas->enable_toolbar(true); +#if !ENABLE_REWORKED_BED_SHAPE_CHANGE m_canvas->enable_force_zoom_to_bed(true); +#endif // !ENABLE_REWORKED_BED_SHAPE_CHANGE #if !ENABLE_IMGUI m_gizmo_widget = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize); @@ -107,7 +109,9 @@ void View3D::set_bed_shape(const Pointfs& shape) if (m_canvas != nullptr) { m_canvas->set_bed_shape(shape); +#if !ENABLE_REWORKED_BED_SHAPE_CHANGE m_canvas->zoom_to_bed(); +#endif // !ENABLE_REWORKED_BED_SHAPE_CHANGE } } diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index d3dad31e9..ad4472bcf 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1125,9 +1125,11 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) this->background_process_timer.SetOwner(this->q, 0); this->q->Bind(wxEVT_TIMER, [this](wxTimerEvent &evt) { this->update_restart_background_process(false, false); }); +#if !ENABLE_REWORKED_BED_SHAPE_CHANGE auto *bed_shape = config->opt("bed_shape"); view3D->set_bed_shape(bed_shape->values); preview->set_bed_shape(bed_shape->values); +#endif // !ENABLE_REWORKED_BED_SHAPE_CHANGE update(); @@ -2965,7 +2967,7 @@ void Plater::on_config_change(const DynamicPrintConfig &config) p->config->set_key_value(opt_key, config.option(opt_key)->clone()); if (opt_key == "printer_technology") this->set_printer_technology(config.opt_enum(opt_key)); - else if (opt_key == "bed_shape") { + else if (opt_key == "bed_shape") { if (p->view3D) p->view3D->set_bed_shape(p->config->option(opt_key)->values); if (p->preview) p->preview->set_bed_shape(p->config->option(opt_key)->values); update_scheduled = true; @@ -2990,12 +2992,14 @@ void Plater::on_config_change(const DynamicPrintConfig &config) p->preview->set_number_extruders(p->config->option(opt_key)->values.size()); } else if(opt_key == "max_print_height") { update_scheduled = true; - } else if(opt_key == "printer_model") { + } + else if (opt_key == "printer_model") { // update to force bed selection(for texturing) if (p->view3D) p->view3D->set_bed_shape(p->config->option("bed_shape")->values); if (p->preview) p->preview->set_bed_shape(p->config->option("bed_shape")->values); update_scheduled = true; - } else if (opt_key == "host_type" && this->p->printer_technology == ptSLA) { + } + else if (opt_key == "host_type" && this->p->printer_technology == ptSLA) { p->config->option>(opt_key)->value = htSL1; } } From d59fc1939bd39124c23461274eddf85ba0aae81d Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Thu, 17 Jan 2019 13:49:10 +0100 Subject: [PATCH 07/18] Fix a missing header in GCodeReader --- src/libslic3r/GCodeReader.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libslic3r/GCodeReader.cpp b/src/libslic3r/GCodeReader.cpp index 51853e9fa..cd1ff867b 100644 --- a/src/libslic3r/GCodeReader.cpp +++ b/src/libslic3r/GCodeReader.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include From 6175eda867e982de79397fdaf7f25f1609d37aca Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Thu, 17 Jan 2019 15:40:09 +0100 Subject: [PATCH 08/18] Fix build --- src/libslic3r/PlaceholderParser.cpp | 6 +++--- src/libslic3r/Slicing.hpp | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/libslic3r/PlaceholderParser.cpp b/src/libslic3r/PlaceholderParser.cpp index eae8f418b..42caa999e 100644 --- a/src/libslic3r/PlaceholderParser.cpp +++ b/src/libslic3r/PlaceholderParser.cpp @@ -270,9 +270,9 @@ namespace client { std::string out; switch (type) { - case TYPE_BOOL: out = boost::to_string(data.b); break; - case TYPE_INT: out = boost::to_string(data.i); break; - case TYPE_DOUBLE: out = boost::to_string(data.d); break; + case TYPE_BOOL: out = std::to_string(data.b); break; + case TYPE_INT: out = std::to_string(data.i); break; + case TYPE_DOUBLE: out = std::to_string(data.d); break; case TYPE_STRING: out = *data.s; break; default: break; } diff --git a/src/libslic3r/Slicing.hpp b/src/libslic3r/Slicing.hpp index b4a074bb5..6070864e1 100644 --- a/src/libslic3r/Slicing.hpp +++ b/src/libslic3r/Slicing.hpp @@ -5,6 +5,7 @@ #include #include +#include #include "libslic3r.h" namespace Slic3r From 570cc6e16710ccade37e7c02223bae8d856d12f0 Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Thu, 17 Jan 2019 16:47:01 +0100 Subject: [PATCH 09/18] Fix string conversions in PlaceholderParser --- src/libslic3r/PlaceholderParser.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libslic3r/PlaceholderParser.cpp b/src/libslic3r/PlaceholderParser.cpp index 42caa999e..443b5e8f9 100644 --- a/src/libslic3r/PlaceholderParser.cpp +++ b/src/libslic3r/PlaceholderParser.cpp @@ -270,9 +270,9 @@ namespace client { std::string out; switch (type) { - case TYPE_BOOL: out = std::to_string(data.b); break; - case TYPE_INT: out = std::to_string(data.i); break; - case TYPE_DOUBLE: out = std::to_string(data.d); break; + case TYPE_BOOL: out = boost::lexical_cast(data.b); break; + case TYPE_INT: out = boost::lexical_cast(data.i); break; + case TYPE_DOUBLE: out = boost::lexical_cast(data.d); break; case TYPE_STRING: out = *data.s; break; default: break; } From 606789130e4dfc99e1b6066fb33c6b3434326bfe Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Thu, 17 Jan 2019 16:10:32 +0100 Subject: [PATCH 10/18] Fix build against wx 3.1.2 on Windows --- src/slic3r/GUI/wxExtensions.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index 096db2c5f..52eb3180d 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -288,7 +288,7 @@ bool PrusaCollapsiblePaneMSW::Create(wxWindow *parent, wxWindowID id, const wxSt { if (!wxControl::Create(parent, id, pos, size, style, val, name)) return false; - m_pStaticLine = NULL; + // m_pStaticLine = NULL; m_strLabel = label; // sizer containing the expand button and possibly a static line From 3a48f362682389d25f9c1989710506ae49b5cbff Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Thu, 17 Jan 2019 19:00:08 +0100 Subject: [PATCH 11/18] Revert "Fix string conversions in PlaceholderParser" This reverts commit 570cc6e16710ccade37e7c02223bae8d856d12f0. Not an improvement --- src/libslic3r/PlaceholderParser.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libslic3r/PlaceholderParser.cpp b/src/libslic3r/PlaceholderParser.cpp index 443b5e8f9..42caa999e 100644 --- a/src/libslic3r/PlaceholderParser.cpp +++ b/src/libslic3r/PlaceholderParser.cpp @@ -270,9 +270,9 @@ namespace client { std::string out; switch (type) { - case TYPE_BOOL: out = boost::lexical_cast(data.b); break; - case TYPE_INT: out = boost::lexical_cast(data.i); break; - case TYPE_DOUBLE: out = boost::lexical_cast(data.d); break; + case TYPE_BOOL: out = std::to_string(data.b); break; + case TYPE_INT: out = std::to_string(data.i); break; + case TYPE_DOUBLE: out = std::to_string(data.d); break; case TYPE_STRING: out = *data.s; break; default: break; } From 668d374779f7249d226891e479ced01c84631ec5 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Thu, 17 Jan 2019 20:34:19 +0100 Subject: [PATCH 12/18] Implemented post-processing scripts on Windows. Fixes https://github.com/prusa3d/Slic3r/issues/1666 --- src/libslic3r/GCode/PostProcessor.cpp | 190 ++++++++++++++++++++------ 1 file changed, 149 insertions(+), 41 deletions(-) diff --git a/src/libslic3r/GCode/PostProcessor.cpp b/src/libslic3r/GCode/PostProcessor.cpp index e44faa220..3bac88733 100644 --- a/src/libslic3r/GCode/PostProcessor.cpp +++ b/src/libslic3r/GCode/PostProcessor.cpp @@ -1,22 +1,136 @@ #include "PostProcessor.hpp" #include +#include #ifdef WIN32 -namespace Slic3r { +// The standard Windows includes. +#define WIN32_LEAN_AND_MEAN +#define NOMINMAX +#include -//FIXME Ignore until we include boost::process -void run_post_process_scripts(const std::string &path, const PrintConfig &config) +// https://blogs.msdn.microsoft.com/twistylittlepassagesallalike/2011/04/23/everyone-quotes-command-line-arguments-the-wrong-way/ +// This routine appends the given argument to a command line such that CommandLineToArgvW will return the argument string unchanged. +// Arguments in a command line should be separated by spaces; this function does not add these spaces. +// Argument - Supplies the argument to encode. +// CommandLine - Supplies the command line to which we append the encoded argument string. +static void quote_argv_winapi(const std::wstring &argument, std::wstring &commmand_line_out) { + // Don't quote unless we actually need to do so --- hopefully avoid problems if programs won't parse quotes properly. + if (argument.empty() == false && argument.find_first_of(L" \t\n\v\"") == argument.npos) + commmand_line_out.append(argument); + else { + commmand_line_out.push_back(L'"'); + for (auto it = argument.begin(); ; ++ it) { + unsigned number_backslashes = 0; + while (it != argument.end() && *it == L'\\') { + ++ it; + ++ number_backslashes; + } + if (it == argument.end()) { + // Escape all backslashes, but let the terminating double quotation mark we add below be interpreted as a metacharacter. + commmand_line_out.append(number_backslashes * 2, L'\\'); + break; + } else if (*it == L'"') { + // Escape all backslashes and the following double quotation mark. + commmand_line_out.append(number_backslashes * 2 + 1, L'\\'); + commmand_line_out.push_back(*it); + } else { + // Backslashes aren't special here. + commmand_line_out.append(number_backslashes, L'\\'); + commmand_line_out.push_back(*it); + } + } + commmand_line_out.push_back(L'"'); + } } -} // namespace Slic3r +static DWORD execute_process_winapi(const std::wstring &command_line) +{ + // Extract the current environment to be passed to the child process. + std::wstring envstr; + { + wchar_t *env = GetEnvironmentStrings(); + assert(env != nullptr); + const wchar_t* var = env; + size_t totallen = 0; + size_t len; + while ((len = wcslen(var)) > 0) { + totallen += len + 1; + var += len + 1; + } + envstr = std::wstring(env, totallen); + FreeEnvironmentStrings(env); + } + + STARTUPINFOW startup_info; + memset(&startup_info, 0, sizeof(startup_info)); + startup_info.cb = sizeof(STARTUPINFO); +#if 0 + startup_info.dwFlags = STARTF_USESHOWWINDOW; + startup_info.wShowWindow = SW_HIDE; +#endif + PROCESS_INFORMATION process_info; + if (! ::CreateProcessW( + nullptr /* lpApplicationName */, (LPWSTR)command_line.c_str(), nullptr /* lpProcessAttributes */, nullptr /* lpThreadAttributes */, false /* bInheritHandles */, + CREATE_UNICODE_ENVIRONMENT /* | CREATE_NEW_CONSOLE */ /* dwCreationFlags */, (LPVOID)envstr.c_str(), nullptr /* lpCurrentDirectory */, &startup_info, &process_info)) + throw std::runtime_error(std::string("Failed starting the script ") + boost::nowide::narrow(command_line) + ", Win32 error: " + std::to_string(int(::GetLastError()))); + ::WaitForSingleObject(process_info.hProcess, INFINITE); + ULONG rc = 0; + ::GetExitCodeProcess(process_info.hProcess, &rc); + ::CloseHandle(process_info.hThread); + ::CloseHandle(process_info.hProcess); + return rc; +} + +// Run the script. If it is a perl script, run it through the bundled perl interpreter. +// If it is a batch file, run it through the cmd.exe. +// Otherwise run it directly. +static int run_script_win32(const std::string &script, const std::string &gcode) +{ + // Unpack the argument list provided by the user. + int nArgs; + LPWSTR *szArglist = CommandLineToArgvW(boost::nowide::widen(script).c_str(), &nArgs); + if (szArglist == nullptr || nArgs <= 0) { + // CommandLineToArgvW failed. Maybe the command line escapment is invalid? + throw std::runtime_error(std::string("Post processing script ") + script + " on file " + gcode + " failed. CommandLineToArgvW() refused to parse the command line path."); + } + + std::wstring command_line; + std::wstring command = szArglist[0]; + if (! boost::filesystem::exists(boost::filesystem::path(command))) + throw std::runtime_error(std::string("The configured post-processing script does not exist: ") + boost::nowide::narrow(command)); + if (boost::iends_with(command, L".pl")) { + // This is a perl script. Run it through the perl interpreter. + // The current process may be slic3r.exe or slic3r-console.exe. + // Find the path of the process: + wchar_t wpath_exe[_MAX_PATH + 1]; + ::GetModuleFileNameW(nullptr, wpath_exe, _MAX_PATH); + boost::filesystem::path path_exe(wpath_exe); + boost::filesystem::path path_perl = path_exe.parent_path() / "perl" / "perl.exe"; + if (! boost::filesystem::exists(path_perl)) { + LocalFree(szArglist); + throw std::runtime_error(std::string("Perl interpreter ") + path_perl.string() + " does not exist."); + } + // Replace it with the current perl interpreter. + quote_argv_winapi(boost::nowide::widen(path_perl.string()), command_line); + command_line += L" "; + } else if (boost::iends_with(command, ".bat")) { + // Run a batch file through the command line interpreter. + command_line = L"cmd.exe /C "; + } + + for (int i = 0; i < nArgs; ++ i) { + quote_argv_winapi(szArglist[i], command_line); + command_line += L" "; + } + LocalFree(szArglist); + quote_argv_winapi(boost::nowide::widen(gcode), command_line); + return (int)execute_process_winapi(command_line); +} #else - -#include -#ifndef WIN32 #include //for getting filesystem UID/GID #include //for getting current UID/GID #endif @@ -33,44 +147,38 @@ void run_post_process_scripts(const std::string &path, const PrintConfig &config if (! boost::filesystem::exists(gcode_file)) throw std::runtime_error(std::string("Post-processor can't find exported gcode file")); - for (std::string script: config.post_process.values) { - // Ignore empty post processing script lines. - boost::trim(script); - if (script.empty()) - continue; - BOOST_LOG_TRIVIAL(info) << "Executing script " << script << " on file " << path; - if (! boost::filesystem::exists(boost::filesystem::path(script))) - throw std::runtime_error(std::string("The configured post-processing script does not exist: ") + script); -#ifndef WIN32 - struct stat info; - if (stat(script.c_str(), &info)) - throw std::runtime_error(std::string("Cannot read information for post-processing script: ") + script); - boost::filesystem::perms script_perms = boost::filesystem::status(script).permissions(); - //if UID matches, check UID perm. else if GID matches, check GID perm. Otherwise check other perm. - if (!(script_perms & ((info.st_uid == geteuid()) ? boost::filesystem::perms::owner_exe - : ((info.st_gid == getegid()) ? boost::filesystem::perms::group_exe - : boost::filesystem::perms::others_exe)))) - throw std::runtime_error(std::string("The configured post-processing script is not executable: check permissions. ") + script); -#endif - int result = 0; + for (const std::string &scripts : config.post_process.values) { + std::vector lines; + boost::split(lines, scripts, boost::is_any_of("\r\n")); + for (std::string script : lines) { + // Ignore empty post processing script lines. + boost::trim(script); + if (script.empty()) + continue; + BOOST_LOG_TRIVIAL(info) << "Executing script " << script << " on file " << path; #ifdef WIN32 - if (boost::iends_with(file, ".gcode")) { - // The current process may be slic3r.exe or slic3r-console.exe. - // Find the path of the process: - wchar_t wpath_exe[_MAX_PATH + 1]; - ::GetModuleFileNameW(nullptr, wpath_exe, _MAX_PATH); - boost::filesystem::path path_exe(wpath_exe); - // Replace it with the current perl interpreter. - result = boost::process::system((path_exe.parent_path() / "perl5.24.0.exe").string(), script, gcode_file); - } else + int result = run_script_win32(script, gcode_file.string()); #else - result = boost::process::system(script, gcode_file); + //FIXME testing existence of a script is risky, as the script line may contain the script and some additional command line parameters. + // We would have to process the script line into parameters before testing for the existence of the command, the command may be looked up + // in the PATH etc. + if (! boost::filesystem::exists(boost::filesystem::path(script))) + throw std::runtime_error(std::string("The configured post-processing script does not exist: ") + script); + struct stat info; + if (stat(script.c_str(), &info)) + throw std::runtime_error(std::string("Cannot read information for post-processing script: ") + script); + boost::filesystem::perms script_perms = boost::filesystem::status(script).permissions(); + //if UID matches, check UID perm. else if GID matches, check GID perm. Otherwise check other perm. + if (!(script_perms & ((info.st_uid == geteuid()) ? boost::filesystem::perms::owner_exe + : ((info.st_gid == getegid()) ? boost::filesystem::perms::group_exe + : boost::filesystem::perms::others_exe)))) + throw std::runtime_error(std::string("The configured post-processing script is not executable: check permissions. ") + script); + int result = boost::process::system(script, gcode_file); + if (result < 0) + BOOST_LOG_TRIVIAL(error) << "Script " << script << " on file " << path << " failed. Negative error code returned."; #endif - if (result < 0) - BOOST_LOG_TRIVIAL(error) << "Script " << script << " on file " << path << " failed. Negative error code returned."; + } } } } // namespace Slic3r - -#endif From 13f0da3ace8119633f71b92818b7f4bec6445f77 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Fri, 18 Jan 2019 09:50:56 +0100 Subject: [PATCH 13/18] Fixed conversion of floating point values to string from PlaceholderParser after boost::to_string() was removed from boost 1.66. --- src/libslic3r/PlaceholderParser.cpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/libslic3r/PlaceholderParser.cpp b/src/libslic3r/PlaceholderParser.cpp index 42caa999e..ae66178aa 100644 --- a/src/libslic3r/PlaceholderParser.cpp +++ b/src/libslic3r/PlaceholderParser.cpp @@ -270,9 +270,22 @@ namespace client { std::string out; switch (type) { - case TYPE_BOOL: out = std::to_string(data.b); break; + case TYPE_BOOL: out = data.b ? "true" : "false"; break; case TYPE_INT: out = std::to_string(data.i); break; - case TYPE_DOUBLE: out = std::to_string(data.d); break; + case TYPE_DOUBLE: +#if 0 + // The default converter produces trailing zeros after the decimal point. + out = std::to_string(data.d); +#else + // ostringstream default converter produces no trailing zeros after the decimal point. + // It seems to be doing what the old boost::to_string() did. + { + std::ostringstream ss; + ss << data.d; + out = ss.str(); + } +#endif + break; case TYPE_STRING: out = *data.s; break; default: break; } From 3e289056216777986a89f4c044b4090c2b9a3a73 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Fri, 18 Jan 2019 10:16:53 +0100 Subject: [PATCH 14/18] Fixed missing includes in PostProcessor.cpp Fixes https://github.com/prusa3d/Slic3r/issues/1679 --- src/libslic3r/GCode/PostProcessor.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libslic3r/GCode/PostProcessor.cpp b/src/libslic3r/GCode/PostProcessor.cpp index 3bac88733..e86463b84 100644 --- a/src/libslic3r/GCode/PostProcessor.cpp +++ b/src/libslic3r/GCode/PostProcessor.cpp @@ -1,5 +1,6 @@ #include "PostProcessor.hpp" +#include #include #include @@ -133,6 +134,7 @@ static int run_script_win32(const std::string &script, const std::string &gcode) #else #include //for getting filesystem UID/GID #include //for getting current UID/GID + #include #endif namespace Slic3r { From 4ffe76f012529185aa7834adea53087063b3959f Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Fri, 18 Jan 2019 15:02:07 +0100 Subject: [PATCH 15/18] Cut: Prevent the neither part kept option --- src/slic3r/GUI/GLGizmo.cpp | 4 +++- src/slic3r/GUI/ImGuiWrapper.cpp | 23 +++++++++++++++++++++++ src/slic3r/GUI/ImGuiWrapper.hpp | 5 ++++- src/slic3r/GUI/Plater.cpp | 4 ++++ 4 files changed, 34 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/GLGizmo.cpp b/src/slic3r/GUI/GLGizmo.cpp index 9decc625d..2ea7e677e 100644 --- a/src/slic3r/GUI/GLGizmo.cpp +++ b/src/slic3r/GUI/GLGizmo.cpp @@ -2466,11 +2466,13 @@ void GLGizmoCut::on_render_input_window(float x, float y, const GLCanvas3D::Sele m_imgui->checkbox(_(L("Keep lower part")), m_keep_lower); m_imgui->checkbox(_(L("Rotate lower part upwards")), m_rotate_lower); + m_imgui->disabled_begin(!m_keep_upper && !m_keep_lower); const bool cut_clicked = m_imgui->button(_(L("Perform cut"))); + m_imgui->disabled_end(); m_imgui->end(); - if (cut_clicked) { + if (cut_clicked && (m_keep_upper || m_keep_lower)) { perform_cut(selection); } } diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp index 2cc22d2b5..7ce34d4e2 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -12,6 +12,8 @@ #include +#include + #include "libslic3r/libslic3r.h" #include "libslic3r/Utils.hpp" #include "GUI.hpp" @@ -23,6 +25,7 @@ namespace GUI { ImGuiWrapper::ImGuiWrapper() : m_font_texture(0) , m_mouse_buttons(0) + , m_disabled(false) { } @@ -154,6 +157,26 @@ void ImGuiWrapper::text(const wxString &label) ImGui::Text(label_utf8.c_str(), NULL); } +void ImGuiWrapper::disabled_begin(bool disabled) +{ + wxCHECK_RET(!m_disabled, "ImGUI: Unbalanced disabled_begin() call"); + + if (disabled) { + ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true); + ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.5f); + m_disabled = true; + } +} + +void ImGuiWrapper::disabled_end() +{ + if (m_disabled) { + ImGui::PopItemFlag(); + ImGui::PopStyleVar(); + m_disabled = false; + } +} + bool ImGuiWrapper::want_mouse() const { return ImGui::GetIO().WantCaptureMouse; diff --git a/src/slic3r/GUI/ImGuiWrapper.hpp b/src/slic3r/GUI/ImGuiWrapper.hpp index cd8508aef..5293bee26 100644 --- a/src/slic3r/GUI/ImGuiWrapper.hpp +++ b/src/slic3r/GUI/ImGuiWrapper.hpp @@ -21,8 +21,8 @@ class ImGuiWrapper FontsMap m_fonts; unsigned m_font_texture; - unsigned m_mouse_buttons; + bool m_disabled; public: ImGuiWrapper(); @@ -50,6 +50,9 @@ public: bool checkbox(const wxString &label, bool &value); void text(const wxString &label); + void disabled_begin(bool disabled); + void disabled_end(); + bool want_mouse() const; bool want_keyboard() const; bool want_text_input() const; diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index ad4472bcf..7cdb8cfc8 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -2767,6 +2767,10 @@ void Plater::cut(size_t obj_idx, size_t instance_idx, coordf_t z, bool keep_uppe wxCHECK_RET(instance_idx < object->instances.size(), "instance_idx out of bounds"); + if (!keep_upper && !keep_lower) { + return; + } + const auto new_objects = object->cut(instance_idx, z, keep_upper, keep_lower, rotate_lower); remove(obj_idx); From d64b55d27d1716cb3f5ead25c269dce73028899a Mon Sep 17 00:00:00 2001 From: bubnikv Date: Mon, 21 Jan 2019 10:06:51 +0100 Subject: [PATCH 16/18] WIP Restoration of the layer editing. --- src/libslic3r/Format/3mf.cpp | 5 +- src/libslic3r/Format/AMF.cpp | 3 +- src/libslic3r/Model.cpp | 2 - src/libslic3r/Model.hpp | 8 +- src/libslic3r/Print.cpp | 75 +------ src/libslic3r/Print.hpp | 35 ++- src/libslic3r/PrintObject.cpp | 117 ++++++---- src/libslic3r/PrintRegion.cpp | 16 ++ src/libslic3r/Slicing.hpp | 2 +- src/slic3r/GUI/3DScene.cpp | 144 ++---------- src/slic3r/GUI/3DScene.hpp | 88 +------- src/slic3r/GUI/GLCanvas3D.cpp | 385 +++++++++++++++++---------------- src/slic3r/GUI/GLCanvas3D.hpp | 71 ++++-- src/slic3r/GUI/GUI_Preview.cpp | 2 +- src/slic3r/GUI/MainFrame.cpp | 1 + src/slic3r/GUI/Plater.cpp | 10 +- src/slic3r/GUI/Tab.cpp | 3 - 17 files changed, 398 insertions(+), 569 deletions(-) diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp index 6b8a38f5c..8b0c28cd6 100644 --- a/src/libslic3r/Format/3mf.cpp +++ b/src/libslic3r/Format/3mf.cpp @@ -582,10 +582,7 @@ namespace Slic3r { IdToLayerHeightsProfileMap::iterator obj_layer_heights_profile = m_layer_heights_profiles.find(object.first); if (obj_layer_heights_profile != m_layer_heights_profiles.end()) - { object.second->layer_height_profile = obj_layer_heights_profile->second; - object.second->layer_height_profile_valid = true; - } IdToSlaSupportPointsMap::iterator obj_sla_support_points = m_sla_support_points.find(object.first); if (obj_sla_support_points != m_sla_support_points.end() && !obj_sla_support_points->second.empty()) @@ -1926,7 +1923,7 @@ namespace Slic3r { for (const ModelObject* object : model.objects) { ++count; - std::vector layer_height_profile = object->layer_height_profile_valid ? object->layer_height_profile : std::vector(); + const std::vector &layer_height_profile = object->layer_height_profile; if ((layer_height_profile.size() >= 4) && ((layer_height_profile.size() % 2) == 0)) { sprintf(buffer, "object_id=%d|", count); diff --git a/src/libslic3r/Format/AMF.cpp b/src/libslic3r/Format/AMF.cpp index 089368865..83f931b0c 100644 --- a/src/libslic3r/Format/AMF.cpp +++ b/src/libslic3r/Format/AMF.cpp @@ -578,7 +578,6 @@ void AMFParserContext::endElement(const char * /* name */) break; p = end + 1; } - m_object->layer_height_profile_valid = true; } else if (m_path.size() == 3 && m_path[1] == NODE_TYPE_OBJECT && m_object && strcmp(opt_key, "sla_support_points") == 0) { // Parse object's layer height profile, a semicolon separated list of floats. @@ -885,7 +884,7 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config) stream << " " << object->config.serialize(key) << "\n"; if (!object->name.empty()) stream << " " << xml_escape(object->name) << "\n"; - std::vector layer_height_profile = object->layer_height_profile_valid ? object->layer_height_profile : std::vector(); + const std::vector &layer_height_profile = object->layer_height_profile; if (layer_height_profile.size() >= 4 && (layer_height_profile.size() % 2) == 0) { // Store the layer height profile as a single semicolon separated list. stream << " "; diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 81ed392c2..de3646738 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -570,7 +570,6 @@ ModelObject& ModelObject::assign_copy(const ModelObject &rhs) this->sla_support_points = rhs.sla_support_points; this->layer_height_ranges = rhs.layer_height_ranges; this->layer_height_profile = rhs.layer_height_profile; - this->layer_height_profile_valid = rhs.layer_height_profile_valid; this->origin_translation = rhs.origin_translation; m_bounding_box = rhs.m_bounding_box; m_bounding_box_valid = rhs.m_bounding_box_valid; @@ -602,7 +601,6 @@ ModelObject& ModelObject::assign_copy(ModelObject &&rhs) this->sla_support_points = std::move(rhs.sla_support_points); this->layer_height_ranges = std::move(rhs.layer_height_ranges); this->layer_height_profile = std::move(rhs.layer_height_profile); - this->layer_height_profile_valid = std::move(rhs.layer_height_profile_valid); this->origin_translation = std::move(rhs.origin_translation); m_bounding_box = std::move(rhs.m_bounding_box); m_bounding_box_valid = std::move(rhs.m_bounding_box_valid); diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 947301437..477b64b73 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -170,12 +170,8 @@ public: // Variation of a layer thickness for spans of Z coordinates. t_layer_height_ranges layer_height_ranges; // Profile of increasing z to a layer height, to be linearly interpolated when calculating the layers. - // The pairs of are packed into a 1D array to simplify handling by the Perl XS. + // The pairs of are packed into a 1D array. std::vector layer_height_profile; - // layer_height_profile is initialized when the layer editing mode is entered. - // Only if the user really modified the layer height, layer_height_profile_valid is set - // and used subsequently by the PrintObject. - bool layer_height_profile_valid; // This vector holds position of selected support points for SLA. The data are // saved in mesh coordinates to allow using them for several instances. @@ -261,7 +257,7 @@ protected: void set_model(Model *model) { m_model = model; } private: - ModelObject(Model *model) : layer_height_profile_valid(false), m_model(model), origin_translation(Vec3d::Zero()), m_bounding_box_valid(false) {} + ModelObject(Model *model) : m_model(model), origin_translation(Vec3d::Zero()), m_bounding_box_valid(false) {} ~ModelObject(); /* To be able to return an object from own copy / clone methods. Hopefully the compiler will do the "Copy elision" */ diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 1981f338e..acaba9d6a 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -287,18 +287,8 @@ std::vector Print::object_extruders() const { std::vector extruders; extruders.reserve(m_regions.size() * 3); - - for (const PrintRegion *region : m_regions) { - // these checks reflect the same logic used in the GUI for enabling/disabling - // extruder selection fields - if (region->config().perimeters.value > 0 || m_config.brim_width.value > 0) - extruders.emplace_back(region->config().perimeter_extruder - 1); - if (region->config().fill_density.value > 0) - extruders.emplace_back(region->config().infill_extruder - 1); - if (region->config().top_solid_layers.value > 0 || region->config().bottom_solid_layers.value > 0) - extruders.emplace_back(region->config().solid_infill_extruder - 1); - } - + for (const PrintRegion *region : m_regions) + region->collect_object_printing_extruders(extruders); sort_remove_duplicates(extruders); return extruders; } @@ -366,37 +356,6 @@ double Print::max_allowed_layer_height() const return nozzle_diameter_max; } -static void clamp_exturder_to_default(ConfigOptionInt &opt, size_t num_extruders) -{ - if (opt.value > (int)num_extruders) - // assign the default extruder - opt.value = 1; -} - -static PrintObjectConfig object_config_from_model(const PrintObjectConfig &default_object_config, const ModelObject &object, size_t num_extruders) -{ - PrintObjectConfig config = default_object_config; - normalize_and_apply_config(config, object.config); - // Clamp invalid extruders to the default extruder (with index 1). - clamp_exturder_to_default(config.support_material_extruder, num_extruders); - clamp_exturder_to_default(config.support_material_interface_extruder, num_extruders); - return config; -} - -static PrintRegionConfig region_config_from_model_volume(const PrintRegionConfig &default_region_config, const ModelVolume &volume, size_t num_extruders) -{ - PrintRegionConfig config = default_region_config; - normalize_and_apply_config(config, volume.get_object()->config); - normalize_and_apply_config(config, volume.config); - if (! volume.material_id().empty()) - normalize_and_apply_config(config, volume.material()->config); - // Clamp invalid extruders to the default extruder (with index 1). - clamp_exturder_to_default(config.infill_extruder, num_extruders); - clamp_exturder_to_default(config.perimeter_extruder, num_extruders); - clamp_exturder_to_default(config.solid_infill_extruder, num_extruders); - return config; -} - // Caller is responsible for supplying models whose objects don't collide // and have explicit instance positions. void Print::add_model_object(ModelObject* model_object, int idx) @@ -433,7 +392,7 @@ void Print::add_model_object(ModelObject* model_object, int idx) if (! volume->is_model_part() && ! volume->is_modifier()) continue; // Get the config applied to this volume. - PrintRegionConfig config = region_config_from_model_volume(m_default_region_config, *volume, 99999); + PrintRegionConfig config = PrintObject::region_config_from_model_volume(m_default_region_config, *volume, 99999); // Find an existing print region with the same config. size_t region_id = size_t(-1); for (size_t i = 0; i < m_regions.size(); ++ i) @@ -514,12 +473,12 @@ bool Print::apply_config(DynamicPrintConfig config) // If the new config for this volume differs from the other // volume configs currently associated to this region, it means // the region subdivision does not make sense anymore. - if (! this_region_config.equals(region_config_from_model_volume(m_default_region_config, volume, 99999))) { + if (! this_region_config.equals(PrintObject::region_config_from_model_volume(m_default_region_config, volume, 99999))) { rearrange_regions = true; goto exit_for_rearrange_regions; } } else { - this_region_config = region_config_from_model_volume(m_default_region_config, volume, 99999); + this_region_config = PrintObject::region_config_from_model_volume(m_default_region_config, volume, 99999); this_region_config_set = true; } for (const PrintRegionConfig &cfg : other_region_configs) { @@ -563,10 +522,6 @@ exit_for_rearrange_regions: invalidated = true; } - // Always make sure that the layer_height_profiles are set, as they should not be modified from the worker threads. - for (PrintObject *object : m_objects) - object->update_layer_height_profile(); - return invalidated; } @@ -888,8 +843,7 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co if (model_parts_differ || modifiers_differ || model_object.origin_translation != model_object_new.origin_translation || model_object.layer_height_ranges != model_object_new.layer_height_ranges || - model_object.layer_height_profile != model_object_new.layer_height_profile || - model_object.layer_height_profile_valid != model_object_new.layer_height_profile_valid) { + model_object.layer_height_profile != model_object_new.layer_height_profile) { // The very first step (the slicing step) is invalidated. One may freely remove all associated PrintObjects. auto range = print_object_status.equal_range(PrintObjectStatus(model_object.id())); for (auto it = range.first; it != range.second; ++ it) { @@ -915,7 +869,7 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co if (object_config_changed) model_object.config = model_object_new.config; if (! object_diff.empty() || object_config_changed) { - PrintObjectConfig new_config = object_config_from_model(m_default_object_config, model_object, num_extruders); + PrintObjectConfig new_config = PrintObject::object_config_from_model_object(m_default_object_config, model_object, num_extruders); auto range = print_object_status.equal_range(PrintObjectStatus(model_object.id())); for (auto it = range.first; it != range.second; ++ it) { t_config_option_keys diff = it->print_object->config().diff(new_config); @@ -957,7 +911,7 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co old.emplace_back(&(*it)); } // Generate a list of trafos and XY offsets for instances of a ModelObject - PrintObjectConfig config = object_config_from_model(m_default_object_config, *model_object, num_extruders); + PrintObjectConfig config = PrintObject::object_config_from_model_object(m_default_object_config, *model_object, num_extruders); std::vector new_print_instances = print_objects_from_model_object(*model_object); if (old.empty()) { // Simple case, just generate new instances. @@ -1048,11 +1002,11 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co // If the new config for this volume differs from the other // volume configs currently associated to this region, it means // the region subdivision does not make sense anymore. - if (! this_region_config.equals(region_config_from_model_volume(m_default_region_config, volume, num_extruders))) + if (! this_region_config.equals(PrintObject::region_config_from_model_volume(m_default_region_config, volume, num_extruders))) // Regions were split. Reset this print_object. goto print_object_end; } else { - this_region_config = region_config_from_model_volume(m_default_region_config, volume, num_extruders); + this_region_config = PrintObject::region_config_from_model_volume(m_default_region_config, volume, num_extruders); for (size_t i = 0; i < region_id; ++i) { const PrintRegion ®ion_other = *m_regions[i]; if (region_other.m_refcnt != 0 && region_other.config().equals(this_region_config)) @@ -1103,7 +1057,7 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co int region_id = -1; if (&print_object == &print_object0) { // Get the config applied to this volume. - PrintRegionConfig config = region_config_from_model_volume(m_default_region_config, *volume, num_extruders); + PrintRegionConfig config = PrintObject::region_config_from_model_volume(m_default_region_config, *volume, num_extruders); // Find an existing print region with the same config. int idx_empty_slot = -1; for (int i = 0; i < (int)m_regions.size(); ++ i) { @@ -1139,13 +1093,6 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co } } - // Always make sure that the layer_height_profiles are set, as they should not be modified from the worker threads. - for (PrintObject *object : m_objects) - if (! object->layer_height_profile_valid) - // No need to call the next line as the step should already be invalidated above. - // update_apply_status(object->invalidate_step(posSlice)); - object->update_layer_height_profile(); - //FIXME there may be a race condition with the G-code export running at the background thread. this->update_object_placeholders(); diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index eaad767ea..d0591e764 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -45,6 +45,10 @@ public: // Average diameter of nozzles participating on extruding this region. coordf_t bridging_height_avg(const PrintConfig &print_config) const; + // Collect extruder indices used to print this region's object. + void collect_object_printing_extruders(std::vector &object_extruders) const; + static void collect_object_printing_extruders(const PrintConfig &print_config, const PrintRegionConfig ®ion_config, std::vector &object_extruders); + // Methods modifying the PrintRegion's state: public: Print* print() { return m_print; } @@ -80,14 +84,8 @@ public: std::vector> region_volumes; // Profile of increasing z to a layer height, to be linearly interpolated when calculating the layers. - // The pairs of are packed into a 1D array to simplify handling by the Perl XS. - // layer_height_profile must not be set by the background thread. + // The pairs of are packed into a 1D array. std::vector layer_height_profile; - // There is a layer_height_profile at both PrintObject and ModelObject. The layer_height_profile at the ModelObject - // is used for interactive editing and for loading / storing into a project file (AMF file as of today). - // This flag indicates that the layer_height_profile at the UI has been updated, therefore the backend needs to get it. - // This flag is necessary as we cannot safely clear the layer_height_profile if the background calculation is running. - bool layer_height_profile_valid; // this is set to true when LayerRegion->slices is split in top/internal/bottom // so that next call to make_perimeters() performs a union() before computing loops @@ -129,23 +127,19 @@ public: SupportLayerPtrs::const_iterator insert_support_layer(SupportLayerPtrs::const_iterator pos, int id, coordf_t height, coordf_t print_z, coordf_t slice_z); void delete_support_layer(int idx); - // To be used over the layer_height_profile of both the PrintObject and ModelObject - // to initialize the height profile with the height ranges. - bool update_layer_height_profile(std::vector &layer_height_profile) const; - - // Process layer_height_ranges, the raft layers and first layer thickness into layer_height_profile. - // The layer_height_profile may be later modified interactively by the user to refine layers at sloping surfaces. - bool update_layer_height_profile(); - - void reset_layer_height_profile(); - - void adjust_layer_height_profile(coordf_t z, coordf_t layer_thickness_delta, coordf_t band_width, int action); + // Initialize the layer_height_profile from the model_object's layer_height_profile, from model_object's layer height table, or from slicing parameters. + // Returns true, if the layer_height_profile was changed. + static bool update_layer_height_profile(const ModelObject &model_object, const SlicingParameters &slicing_parameters, std::vector &layer_height_profile); // Collect the slicing parameters, to be used by variable layer thickness algorithm, // by the interactive layer height editor and by the printing process itself. // The slicing parameters are dependent on various configuration values // (layer height, first layer height, raft settings, print nozzle diameter etc). - SlicingParameters slicing_parameters() const; + SlicingParameters slicing_parameters() const; + static SlicingParameters slicing_parameters(const DynamicPrintConfig &full_config, const ModelObject &model_object); + + // returns 0-based indices of extruders used to print the object (without brim, support and other helper extrusions) + std::vector object_extruders() const; // Called when slicing to SVG (see Print.pm sub export_svg), and used by perimeters.t void slice(); @@ -172,6 +166,9 @@ protected: // Invalidate steps based on a set of parameters changed. bool invalidate_state_by_config_options(const std::vector &opt_keys); + static PrintObjectConfig object_config_from_model_object(const PrintObjectConfig &default_object_config, const ModelObject &object, size_t num_extruders); + static PrintRegionConfig region_config_from_model_volume(const PrintRegionConfig &default_region_config, const ModelVolume &volume, size_t num_extruders); + private: void make_perimeters(); void prepare_infill(); diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index a7214afa3..9dd101123 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -38,8 +38,7 @@ namespace Slic3r { PrintObject::PrintObject(Print* print, ModelObject* model_object, bool add_instances) : PrintObjectBaseWithState(print, model_object), typed_slices(false), - size(Vec3crd::Zero()), - layer_height_profile_valid(false) + size(Vec3crd::Zero()) { // Compute the translation to be applied to our meshes so that we work with smaller coordinates { @@ -106,6 +105,8 @@ void PrintObject::slice() if (! this->set_started(posSlice)) return; m_print->set_status(10, "Processing triangulated mesh"); + this->update_layer_height_profile(*this->model_object(), this->slicing_parameters(), this->layer_height_profile); + m_print->throw_if_canceled(); this->_slice(); m_print->throw_if_canceled(); // Fix the model. @@ -455,7 +456,6 @@ bool PrintObject::invalidate_state_by_config_options(const std::vectorreset_layer_height_profile(); } else if ( opt_key == "clip_multipart_objects" @@ -542,7 +542,6 @@ bool PrintObject::invalidate_state_by_config_options(const std::vectorinvalidate_all_steps(); - this->reset_layer_height_profile(); invalidated = true; } } @@ -1329,55 +1328,107 @@ void PrintObject::bridge_over_infill() } } +static void clamp_exturder_to_default(ConfigOptionInt &opt, size_t num_extruders) +{ + if (opt.value > (int)num_extruders) + // assign the default extruder + opt.value = 1; +} + +PrintObjectConfig PrintObject::object_config_from_model_object(const PrintObjectConfig &default_object_config, const ModelObject &object, size_t num_extruders) +{ + PrintObjectConfig config = default_object_config; + normalize_and_apply_config(config, object.config); + // Clamp invalid extruders to the default extruder (with index 1). + clamp_exturder_to_default(config.support_material_extruder, num_extruders); + clamp_exturder_to_default(config.support_material_interface_extruder, num_extruders); + return config; +} + +PrintRegionConfig PrintObject::region_config_from_model_volume(const PrintRegionConfig &default_region_config, const ModelVolume &volume, size_t num_extruders) +{ + PrintRegionConfig config = default_region_config; + normalize_and_apply_config(config, volume.get_object()->config); + normalize_and_apply_config(config, volume.config); + if (! volume.material_id().empty()) + normalize_and_apply_config(config, volume.material()->config); + // Clamp invalid extruders to the default extruder (with index 1). + clamp_exturder_to_default(config.infill_extruder, num_extruders); + clamp_exturder_to_default(config.perimeter_extruder, num_extruders); + clamp_exturder_to_default(config.solid_infill_extruder, num_extruders); + return config; +} + SlicingParameters PrintObject::slicing_parameters() const { return SlicingParameters::create_from_config( this->print()->config(), m_config, - unscale(this->size(2)), this->print()->object_extruders()); + unscale(this->size(2)), this->object_extruders()); } -bool PrintObject::update_layer_height_profile(std::vector &layer_height_profile) const +SlicingParameters PrintObject::slicing_parameters(const DynamicPrintConfig &full_config, const ModelObject &model_object) +{ + PrintConfig print_config; + PrintObjectConfig object_config; + PrintRegionConfig default_region_config; + print_config .apply(full_config, true); + object_config.apply(full_config, true); + default_region_config.apply(full_config, true); + size_t num_extruders = print_config.nozzle_diameter.size(); + object_config = object_config_from_model_object(object_config, model_object, num_extruders); + + std::vector object_extruders; + for (const ModelVolume *model_volume : model_object.volumes) + if (model_volume->is_model_part()) + PrintRegion::collect_object_printing_extruders( + print_config, + region_config_from_model_volume(default_region_config, *model_volume, num_extruders), + object_extruders); + sort_remove_duplicates(object_extruders); + + return SlicingParameters::create_from_config(print_config, object_config, model_object.bounding_box().max.z(), object_extruders); +} + +// returns 0-based indices of extruders used to print the object (without brim, support and other helper extrusions) +std::vector PrintObject::object_extruders() const +{ + std::vector extruders; + extruders.reserve(this->region_volumes.size() * 3); + for (size_t idx_region = 0; idx_region < this->region_volumes.size(); ++ idx_region) + if (! this->region_volumes[idx_region].empty()) + m_print->get_region(idx_region)->collect_object_printing_extruders(extruders); + sort_remove_duplicates(extruders); + return extruders; +} + +bool PrintObject::update_layer_height_profile(const ModelObject &model_object, const SlicingParameters &slicing_parameters, std::vector &layer_height_profile) { bool updated = false; - // If the layer height profile is not set, try to use the one stored at the ModelObject. if (layer_height_profile.empty()) { - layer_height_profile = this->model_object()->layer_height_profile; + layer_height_profile = model_object.layer_height_profile; updated = true; } // Verify the layer_height_profile. - SlicingParameters slicing_params = this->slicing_parameters(); if (! layer_height_profile.empty() && // Must not be of even length. ((layer_height_profile.size() & 1) != 0 || // Last entry must be at the top of the object. - std::abs(layer_height_profile[layer_height_profile.size() - 2] - slicing_params.object_print_z_height()) > 1e-3)) + std::abs(layer_height_profile[layer_height_profile.size() - 2] - slicing_parameters.object_print_z_height()) > 1e-3)) layer_height_profile.clear(); if (layer_height_profile.empty()) { if (0) // if (this->layer_height_profile.empty()) - layer_height_profile = layer_height_profile_adaptive(slicing_params, this->model_object()->layer_height_ranges, this->model_object()->volumes); + layer_height_profile = layer_height_profile_adaptive(slicing_parameters, model_object.layer_height_ranges, model_object.volumes); else - layer_height_profile = layer_height_profile_from_ranges(slicing_params, this->model_object()->layer_height_ranges); + layer_height_profile = layer_height_profile_from_ranges(slicing_parameters, model_object.layer_height_ranges); updated = true; } return updated; } -// This must be called from the main thread as it modifies the layer_height_profile. -bool PrintObject::update_layer_height_profile() -{ - // If the layer height profile has been marked as invalid for some reason (modified at the UI level - // or invalidated due to the slicing parameters), clear it now. - if (! this->layer_height_profile_valid) { - this->layer_height_profile.clear(); - this->layer_height_profile_valid = true; - } - return this->update_layer_height_profile(this->layer_height_profile); -} - // 1) Decides Z positions of the layers, // 2) Initializes layers and their regions // 3) Slices the object meshes @@ -2198,22 +2249,4 @@ void PrintObject::_generate_support_material() support_material.generate(*this); } -void PrintObject::reset_layer_height_profile() -{ - // Reset the layer_heigth_profile. - this->layer_height_profile.clear(); - this->layer_height_profile_valid = false; - // Reset the source layer_height_profile if it exists at the ModelObject. - this->model_object()->layer_height_profile.clear(); - this->model_object()->layer_height_profile_valid = false; -} - -void PrintObject::adjust_layer_height_profile(coordf_t z, coordf_t layer_thickness_delta, coordf_t band_width, int action) -{ - update_layer_height_profile(m_model_object->layer_height_profile); - Slic3r::adjust_layer_height_profile(slicing_parameters(), m_model_object->layer_height_profile, z, layer_thickness_delta, band_width, LayerHeightEditActionType(action)); - m_model_object->layer_height_profile_valid = true; - layer_height_profile_valid = false; -} - } // namespace Slic3r diff --git a/src/libslic3r/PrintRegion.cpp b/src/libslic3r/PrintRegion.cpp index 4ea777b4a..73b40487b 100644 --- a/src/libslic3r/PrintRegion.cpp +++ b/src/libslic3r/PrintRegion.cpp @@ -61,4 +61,20 @@ coordf_t PrintRegion::bridging_height_avg(const PrintConfig &print_config) const return this->nozzle_dmr_avg(print_config) * sqrt(m_config.bridge_flow_ratio.value); } +void PrintRegion::collect_object_printing_extruders(const PrintConfig &print_config, const PrintRegionConfig ®ion_config, std::vector &object_extruders) +{ + // These checks reflect the same logic used in the GUI for enabling/disabling extruder selection fields. + if (region_config.perimeters.value > 0 || print_config.brim_width.value > 0) + object_extruders.emplace_back(region_config.perimeter_extruder - 1); + if (region_config.fill_density.value > 0) + object_extruders.emplace_back(region_config.infill_extruder - 1); + if (region_config.top_solid_layers.value > 0 || region_config.bottom_solid_layers.value > 0) + object_extruders.emplace_back(region_config.solid_infill_extruder - 1); +} + +void PrintRegion::collect_object_printing_extruders(std::vector &object_extruders) const +{ + collect_object_printing_extruders(print()->config(), this->config(), object_extruders); +} + } diff --git a/src/libslic3r/Slicing.hpp b/src/libslic3r/Slicing.hpp index 6070864e1..395fedc9f 100644 --- a/src/libslic3r/Slicing.hpp +++ b/src/libslic3r/Slicing.hpp @@ -131,7 +131,7 @@ extern std::vector layer_height_profile_adaptive( const ModelVolumePtrs &volumes); -enum LayerHeightEditActionType { +enum LayerHeightEditActionType : unsigned int { LAYER_HEIGHT_EDIT_ACTION_INCREASE = 0, LAYER_HEIGHT_EDIT_ACTION_DECREASE = 1, LAYER_HEIGHT_EDIT_ACTION_REDUCE = 2, diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 0ee89296a..c6265f275 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -386,58 +386,6 @@ void GLVolume::render() const ::glPopMatrix(); } -void GLVolume::render_using_layer_height() const -{ - if (!is_active) - return; - - GLint current_program_id; - glGetIntegerv(GL_CURRENT_PROGRAM, ¤t_program_id); - - if ((layer_height_texture_data.shader_id > 0) && (layer_height_texture_data.shader_id != current_program_id)) - glUseProgram(layer_height_texture_data.shader_id); - - GLint z_to_texture_row_id = (layer_height_texture_data.shader_id > 0) ? glGetUniformLocation(layer_height_texture_data.shader_id, "z_to_texture_row") : -1; - GLint z_texture_row_to_normalized_id = (layer_height_texture_data.shader_id > 0) ? glGetUniformLocation(layer_height_texture_data.shader_id, "z_texture_row_to_normalized") : -1; - GLint z_cursor_id = (layer_height_texture_data.shader_id > 0) ? glGetUniformLocation(layer_height_texture_data.shader_id, "z_cursor") : -1; - GLint z_cursor_band_width_id = (layer_height_texture_data.shader_id > 0) ? glGetUniformLocation(layer_height_texture_data.shader_id, "z_cursor_band_width") : -1; - GLint world_matrix_id = (layer_height_texture_data.shader_id > 0) ? glGetUniformLocation(layer_height_texture_data.shader_id, "volume_world_matrix") : -1; - - if (z_to_texture_row_id >= 0) - glUniform1f(z_to_texture_row_id, (GLfloat)layer_height_texture_z_to_row_id()); - - if (z_texture_row_to_normalized_id >= 0) - glUniform1f(z_texture_row_to_normalized_id, (GLfloat)(1.0f / layer_height_texture_height())); - - if (z_cursor_id >= 0) - glUniform1f(z_cursor_id, (GLfloat)(layer_height_texture_data.print_object->model_object()->bounding_box().max(2) * layer_height_texture_data.z_cursor_relative)); - - if (z_cursor_band_width_id >= 0) - glUniform1f(z_cursor_band_width_id, (GLfloat)layer_height_texture_data.edit_band_width); - - if (world_matrix_id >= 0) - ::glUniformMatrix4fv(world_matrix_id, 1, GL_FALSE, (const GLfloat*)world_matrix().cast().data()); - - GLsizei w = (GLsizei)layer_height_texture_width(); - GLsizei h = (GLsizei)layer_height_texture_height(); - GLsizei half_w = w / 2; - GLsizei half_h = h / 2; - - ::glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - glBindTexture(GL_TEXTURE_2D, layer_height_texture_data.texture_id); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); - glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, half_w, half_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, layer_height_texture_data_ptr_level0()); - glTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, half_w, half_h, GL_RGBA, GL_UNSIGNED_BYTE, layer_height_texture_data_ptr_level1()); - - render(); - - glBindTexture(GL_TEXTURE_2D, 0); - - if ((current_program_id > 0) && (layer_height_texture_data.shader_id != current_program_id)) - glUseProgram(current_program_id); -} - void GLVolume::render_VBOs(int color_id, int detection_id, int worldmatrix_id) const { if (!is_active) @@ -446,16 +394,6 @@ void GLVolume::render_VBOs(int color_id, int detection_id, int worldmatrix_id) c if (!indexed_vertex_array.vertices_and_normals_interleaved_VBO_id) return; - if (layer_height_texture_data.can_use()) - { - ::glDisableClientState(GL_VERTEX_ARRAY); - ::glDisableClientState(GL_NORMAL_ARRAY); - render_using_layer_height(); - ::glEnableClientState(GL_VERTEX_ARRAY); - ::glEnableClientState(GL_NORMAL_ARRAY); - return; - } - GLsizei n_triangles = GLsizei(std::min(indexed_vertex_array.triangle_indices_size, tverts_range.second - tverts_range.first)); GLsizei n_quads = GLsizei(std::min(indexed_vertex_array.quad_indices_size, qverts_range.second - qverts_range.first)); if (n_triangles + n_quads == 0) @@ -558,44 +496,6 @@ void GLVolume::render_legacy() const ::glPopMatrix(); } -double GLVolume::layer_height_texture_z_to_row_id() const -{ - return (this->layer_height_texture.get() == nullptr) ? 0.0 : double(this->layer_height_texture->cells - 1) / (double(this->layer_height_texture->width) * this->layer_height_texture_data.print_object->model_object()->bounding_box().max(2)); -} - -void GLVolume::generate_layer_height_texture(const PrintObject *print_object, bool force) -{ - LayersTexture *tex = this->layer_height_texture.get(); - if (tex == nullptr) - // No layer_height_texture is assigned to this GLVolume, therefore the layer height texture cannot be filled. - return; - - // Always try to update the layer height profile. - bool update = print_object->update_layer_height_profile(const_cast(print_object->model_object())->layer_height_profile) || force; - // Update if the layer height profile was changed, or when the texture is not valid. - if (! update && ! tex->data.empty() && tex->cells > 0) - // Texture is valid, don't update. - return; - - if (tex->data.empty()) { - tex->width = 1024; - tex->height = 1024; - tex->levels = 2; - tex->data.assign(tex->width * tex->height * 5, 0); - } - - SlicingParameters slicing_params = print_object->slicing_parameters(); - bool level_of_detail_2nd_level = true; - tex->cells = Slic3r::generate_layer_height_texture( - slicing_params, - Slic3r::generate_object_layers(slicing_params, print_object->model_object()->layer_height_profile), - tex->data.data(), tex->height, tex->width, level_of_detail_2nd_level); -} - -// 512x512 bitmaps are supported everywhere, but that may not be sufficent for super large print volumes. -#define LAYER_HEIGHT_TEXTURE_WIDTH 1024 -#define LAYER_HEIGHT_TEXTURE_HEIGHT 1024 - std::vector GLVolumeCollection::load_object( const ModelObject *model_object, int obj_idx, @@ -603,19 +503,15 @@ std::vector GLVolumeCollection::load_object( const std::string &color_by, bool use_VBOs) { - // Object will share a single common layer height texture between all printable volumes. - std::shared_ptr layer_height_texture = std::make_shared(); std::vector volumes_idx; for (int volume_idx = 0; volume_idx < int(model_object->volumes.size()); ++ volume_idx) for (int instance_idx : instance_idxs) - volumes_idx.emplace_back(this->GLVolumeCollection::load_object_volume(model_object, layer_height_texture, obj_idx, volume_idx, instance_idx, color_by, use_VBOs)); + volumes_idx.emplace_back(this->GLVolumeCollection::load_object_volume(model_object, obj_idx, volume_idx, instance_idx, color_by, use_VBOs)); return volumes_idx; } int GLVolumeCollection::load_object_volume( const ModelObject *model_object, - // Layer height texture is shared between all printable volumes of a single ModelObject. - std::shared_ptr &layer_height_texture, int obj_idx, int volume_idx, int instance_idx, @@ -666,7 +562,6 @@ int GLVolumeCollection::load_object_volume( v.set_convex_hull(&model_volume->get_convex_hull(), false); if (extruder_id != -1) v.extruder_id = extruder_id; - v.layer_height_texture = layer_height_texture; } v.is_modifier = ! model_volume->is_model_part(); v.shader_outside_printer_detection_enabled = model_volume->is_model_part(); @@ -795,17 +690,19 @@ int GLVolumeCollection::load_wipe_tower_preview( #if ENABLE_IMPROVED_TRANSPARENT_VOLUMES_RENDERING typedef std::pair GLVolumeWithZ; typedef std::vector GLVolumesWithZList; -GLVolumesWithZList volumes_to_render(const GLVolumePtrs& volumes, GLVolumeCollection::ERenderType type) +static GLVolumesWithZList volumes_to_render(const GLVolumePtrs& volumes, GLVolumeCollection::ERenderType type, std::function filter_func) { GLVolumesWithZList list; + list.reserve(volumes.size()); for (GLVolume* volume : volumes) { bool is_transparent = (volume->render_color[3] < 1.0f); - if (((type == GLVolumeCollection::Opaque) && !is_transparent) || - ((type == GLVolumeCollection::Transparent) && is_transparent) || - (type == GLVolumeCollection::All)) - list.push_back(std::make_pair(volume, 0.0)); + if ((((type == GLVolumeCollection::Opaque) && !is_transparent) || + ((type == GLVolumeCollection::Transparent) && is_transparent) || + (type == GLVolumeCollection::All)) && + (! filter_func || filter_func(*volume))) + list.emplace_back(std::make_pair(volume, 0.0)); } if ((type == GLVolumeCollection::Transparent) && (list.size() > 1)) @@ -826,7 +723,7 @@ GLVolumesWithZList volumes_to_render(const GLVolumePtrs& volumes, GLVolumeCollec return list; } -void GLVolumeCollection::render_VBOs(GLVolumeCollection::ERenderType type, bool disable_cullface) const +void GLVolumeCollection::render_VBOs(GLVolumeCollection::ERenderType type, bool disable_cullface, std::function filter_func) const #else void GLVolumeCollection::render_VBOs() const #endif // ENABLE_IMPROVED_TRANSPARENT_VOLUMES_RENDERING @@ -862,26 +759,17 @@ void GLVolumeCollection::render_VBOs() const ::glUniform2fv(z_range_id, 1, (const GLfloat*)z_range); #if ENABLE_IMPROVED_TRANSPARENT_VOLUMES_RENDERING - GLVolumesWithZList to_render = volumes_to_render(this->volumes, type); - for (GLVolumeWithZ& volume : to_render) - { - if (volume.first->layer_height_texture_data.can_use()) - volume.first->generate_layer_height_texture(volume.first->layer_height_texture_data.print_object, false); - else - volume.first->set_render_color(); - + GLVolumesWithZList to_render = volumes_to_render(this->volumes, type, filter_func); + for (GLVolumeWithZ& volume : to_render) { + volume.first->set_render_color(); volume.first->render_VBOs(color_id, print_box_detection_id, print_box_worldmatrix_id); } #else for (GLVolume *volume : this->volumes) - { - if (volume->layer_height_texture_data.can_use()) - volume->generate_layer_height_texture(volume->layer_height_texture_data.print_object, false); - else + if (! filter_func || filter_func(*volume)) { volume->set_render_color(); - - volume->render_VBOs(color_id, print_box_detection_id, print_box_worldmatrix_id); - } + volume->render_VBOs(color_id, print_box_detection_id, print_box_worldmatrix_id); + } #endif // ENABLE_IMPROVED_TRANSPARENT_VOLUMES_RENDERING ::glBindBuffer(GL_ARRAY_BUFFER, 0); @@ -917,7 +805,7 @@ void GLVolumeCollection::render_legacy() const glEnableClientState(GL_NORMAL_ARRAY); #if ENABLE_IMPROVED_TRANSPARENT_VOLUMES_RENDERING - GLVolumesWithZList to_render = volumes_to_render(this->volumes, type); + GLVolumesWithZList to_render = volumes_to_render(this->volumes, type, std::function()); for (GLVolumeWithZ& volume : to_render) { volume.first->set_render_color(); diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index b7b1af73d..1ea69a22f 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -9,6 +9,8 @@ #include "libslic3r/Model.hpp" #include "slic3r/GUI/GLCanvas3DManager.hpp" +#include + namespace Slic3r { class Print; @@ -199,50 +201,7 @@ private: } }; -class LayersTexture -{ -public: - LayersTexture() : width(0), height(0), levels(0), cells(0) {} - - // Texture data - std::vector data; - // Width of the texture, top level. - size_t width; - // Height of the texture, top level. - size_t height; - // For how many levels of detail is the data allocated? - size_t levels; - // Number of texture cells allocated for the height texture. - size_t cells; -}; - class GLVolume { - struct LayerHeightTextureData - { - // ID of the layer height texture - unsigned int texture_id; - // ID of the shader used to render with the layer height texture - unsigned int shader_id; - // The print object to update when generating the layer height texture - const PrintObject* print_object; - - float z_cursor_relative; - float edit_band_width; - - LayerHeightTextureData() { reset(); } - - void reset() - { - texture_id = 0; - shader_id = 0; - print_object = nullptr; - z_cursor_relative = 0.0f; - edit_band_width = 0.0f; - } - - bool can_use() const { return (texture_id > 0) && (shader_id > 0) && (print_object != nullptr); } - }; - public: static const float SELECTED_COLOR[4]; static const float HOVER_COLOR[4]; @@ -406,7 +365,7 @@ public: int volume_idx() const { return this->composite_id.volume_id; } int instance_idx() const { return this->composite_id.instance_id; } - Transform3d world_matrix() const; + Transform3d world_matrix() const; const BoundingBoxf3& transformed_bounding_box() const; const BoundingBoxf3& transformed_convex_hull_bounding_box() const; @@ -416,49 +375,13 @@ public: void set_range(coordf_t low, coordf_t high); void render() const; - void render_using_layer_height() const; void render_VBOs(int color_id, int detection_id, int worldmatrix_id) const; void render_legacy() const; void finalize_geometry(bool use_VBOs) { this->indexed_vertex_array.finalize_geometry(use_VBOs); } void release_geometry() { this->indexed_vertex_array.release_geometry(); } - /************************************************ Layer height texture ****************************************************/ - std::shared_ptr layer_height_texture; - // Data to render this volume using the layer height texture - LayerHeightTextureData layer_height_texture_data; - - bool has_layer_height_texture() const - { return this->layer_height_texture.get() != nullptr; } - size_t layer_height_texture_width() const - { return (this->layer_height_texture.get() == nullptr) ? 0 : this->layer_height_texture->width; } - size_t layer_height_texture_height() const - { return (this->layer_height_texture.get() == nullptr) ? 0 : this->layer_height_texture->height; } - size_t layer_height_texture_cells() const - { return (this->layer_height_texture.get() == nullptr) ? 0 : this->layer_height_texture->cells; } - void* layer_height_texture_data_ptr_level0() const { - return (layer_height_texture.get() == nullptr) ? 0 : - (void*)layer_height_texture->data.data(); - } - void* layer_height_texture_data_ptr_level1() const { - return (layer_height_texture.get() == nullptr) ? 0 : - (void*)(layer_height_texture->data.data() + layer_height_texture->width * layer_height_texture->height * 4); - } - double layer_height_texture_z_to_row_id() const; - void generate_layer_height_texture(const PrintObject *print_object, bool force); - - void set_layer_height_texture_data(unsigned int texture_id, unsigned int shader_id, const PrintObject* print_object, float z_cursor_relative, float edit_band_width) - { - layer_height_texture_data.texture_id = texture_id; - layer_height_texture_data.shader_id = shader_id; - layer_height_texture_data.print_object = print_object; - layer_height_texture_data.z_cursor_relative = z_cursor_relative; - layer_height_texture_data.edit_band_width = edit_band_width; - } - - void reset_layer_height_texture_data() { layer_height_texture_data.reset(); } - - void set_bounding_boxes_as_dirty() { m_transformed_bounding_box_dirty = true; m_transformed_convex_hull_bounding_box_dirty = true; } + void set_bounding_boxes_as_dirty() { m_transformed_bounding_box_dirty = true; m_transformed_convex_hull_bounding_box_dirty = true; } }; typedef std::vector GLVolumePtrs; @@ -498,7 +421,6 @@ public: int load_object_volume( const ModelObject *model_object, - std::shared_ptr &layer_height_texture, int obj_idx, int volume_idx, int instance_idx, @@ -521,7 +443,7 @@ public: // Render the volumes by OpenGL. #if ENABLE_IMPROVED_TRANSPARENT_VOLUMES_RENDERING - void render_VBOs(ERenderType type, bool disable_cullface) const; + void render_VBOs(ERenderType type, bool disable_cullface, std::function filter_func = std::function()) const; void render_legacy(ERenderType type, bool disable_cullface) const; #else void render_VBOs() const; diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 16f519455..24998cd60 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -819,12 +819,16 @@ GLCanvas3D::LayersEditing::LayersEditing() : m_use_legacy_opengl(false) , m_enabled(false) , m_z_texture_id(0) + , m_model_object(nullptr) + , m_object_max_z(0.f) + , m_slicing_parameters(new SlicingParameters) + , m_layer_height_profile_modified(false) , state(Unknown) , band_width(2.0f) , strength(0.005f) , last_object_id(-1) , last_z(0.0f) - , last_action(0) + , last_action(LAYER_HEIGHT_EDIT_ACTION_INCREASE) { } @@ -835,6 +839,7 @@ GLCanvas3D::LayersEditing::~LayersEditing() ::glDeleteTextures(1, &m_z_texture_id); m_z_texture_id = 0; } + delete m_slicing_parameters; } bool GLCanvas3D::LayersEditing::init(const std::string& vertex_shader_filename, const std::string& fragment_shader_filename) @@ -854,9 +859,20 @@ bool GLCanvas3D::LayersEditing::init(const std::string& vertex_shader_filename, return true; } +void GLCanvas3D::LayersEditing::select_object(const Model &model, int object_id) +{ + m_model_object = (object_id >= 0) ? model.objects[object_id] : nullptr; + m_object_max_z = (m_model_object == nullptr) ? 0.f : m_model_object->bounding_box().max.z(); + if (m_model_object == nullptr || this->last_object_id != object_id) { + m_layer_height_profile.clear(); + m_layer_height_profile_modified = false; + } + this->last_object_id = object_id; +} + bool GLCanvas3D::LayersEditing::is_allowed() const { - return !m_use_legacy_opengl && m_shader.is_initialized(); + return !m_use_legacy_opengl && m_shader.is_initialized() && m_shader.get_shader()->shader_program_id > 0 && m_z_texture_id > 0; } void GLCanvas3D::LayersEditing::set_use_legacy_opengl(bool use_legacy_opengl) @@ -874,12 +890,7 @@ void GLCanvas3D::LayersEditing::set_enabled(bool enabled) m_enabled = is_allowed() && enabled; } -unsigned int GLCanvas3D::LayersEditing::get_z_texture_id() const -{ - return m_z_texture_id; -} - -void GLCanvas3D::LayersEditing::render(const GLCanvas3D& canvas, const PrintObject& print_object, const GLVolume& volume) const +void GLCanvas3D::LayersEditing::render_overlay(const GLCanvas3D& canvas) const { if (!m_enabled) return; @@ -896,8 +907,8 @@ void GLCanvas3D::LayersEditing::render(const GLCanvas3D& canvas, const PrintObje _render_tooltip_texture(canvas, bar_rect, reset_rect); _render_reset_texture(reset_rect); - _render_active_object_annotations(canvas, volume, print_object, bar_rect); - _render_profile(print_object, bar_rect); + _render_active_object_annotations(canvas, bar_rect); + _render_profile(bar_rect); // Revert the matrices. ::glPopMatrix(); @@ -905,12 +916,6 @@ void GLCanvas3D::LayersEditing::render(const GLCanvas3D& canvas, const PrintObje ::glEnable(GL_DEPTH_TEST); } -int GLCanvas3D::LayersEditing::get_shader_program_id() const -{ - const GLShader* shader = m_shader.get_shader(); - return (shader != nullptr) ? shader->shader_program_id : -1; -} - float GLCanvas3D::LayersEditing::get_cursor_z_relative(const GLCanvas3D& canvas) { const Point& mouse_pos = canvas.get_local_mouse_position(); @@ -1023,21 +1028,19 @@ void GLCanvas3D::LayersEditing::_render_reset_texture(const Rect& reset_rect) co GLTexture::render_texture(m_reset_texture.get_id(), reset_rect.get_left(), reset_rect.get_right(), reset_rect.get_bottom(), reset_rect.get_top()); } -void GLCanvas3D::LayersEditing::_render_active_object_annotations(const GLCanvas3D& canvas, const GLVolume& volume, const PrintObject& print_object, const Rect& bar_rect) const +void GLCanvas3D::LayersEditing::_render_active_object_annotations(const GLCanvas3D& canvas, const Rect& bar_rect) const { - float max_z = print_object.model_object()->bounding_box().max(2); - m_shader.start_using(); - m_shader.set_uniform("z_to_texture_row", (float)volume.layer_height_texture_z_to_row_id()); - m_shader.set_uniform("z_texture_row_to_normalized", 1.0f / (float)volume.layer_height_texture_height()); - m_shader.set_uniform("z_cursor", max_z * get_cursor_z_relative(canvas)); + m_shader.set_uniform("z_to_texture_row", float(m_layers_texture.cells - 1) / (float(m_layers_texture.width) * m_object_max_z)); + m_shader.set_uniform("z_texture_row_to_normalized", 1.0f / (float)m_layers_texture.height); + m_shader.set_uniform("z_cursor", m_object_max_z * this->get_cursor_z_relative(canvas)); m_shader.set_uniform("z_cursor_band_width", band_width); // The shader requires the original model coordinates when rendering to the texture, so we pass it the unit matrix m_shader.set_uniform("volume_world_matrix", UNIT_MATRIX); - GLsizei w = (GLsizei)volume.layer_height_texture_width(); - GLsizei h = (GLsizei)volume.layer_height_texture_height(); + GLsizei w = (GLsizei)m_layers_texture.width; + GLsizei h = (GLsizei)m_layers_texture.height; GLsizei half_w = w / 2; GLsizei half_h = h / 2; @@ -1045,8 +1048,8 @@ void GLCanvas3D::LayersEditing::_render_active_object_annotations(const GLCanvas ::glBindTexture(GL_TEXTURE_2D, m_z_texture_id); ::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); ::glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, half_w, half_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); - ::glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, volume.layer_height_texture_data_ptr_level0()); - ::glTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, half_w, half_h, GL_RGBA, GL_UNSIGNED_BYTE, volume.layer_height_texture_data_ptr_level1()); + ::glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, m_layers_texture.data.data()); + ::glTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, half_w, half_h, GL_RGBA, GL_UNSIGNED_BYTE, m_layers_texture.data.data() + m_layers_texture.width * m_layers_texture.height * 4); // Render the color bar float l = bar_rect.get_left(); @@ -1057,25 +1060,24 @@ void GLCanvas3D::LayersEditing::_render_active_object_annotations(const GLCanvas ::glBegin(GL_QUADS); ::glVertex3f(l, b, 0.0f); ::glVertex3f(r, b, 0.0f); - ::glVertex3f(r, t, max_z); - ::glVertex3f(l, t, max_z); + ::glVertex3f(r, t, m_object_max_z); + ::glVertex3f(l, t, m_object_max_z); ::glEnd(); ::glBindTexture(GL_TEXTURE_2D, 0); m_shader.stop_using(); } -void GLCanvas3D::LayersEditing::_render_profile(const PrintObject& print_object, const Rect& bar_rect) const +void GLCanvas3D::LayersEditing::_render_profile(const Rect& bar_rect) const { - // FIXME show some kind of legend. + //FIXME show some kind of legend. // Get a maximum layer height value. - // FIXME This is a duplicate code of Slicing.cpp. + //FIXME This is a duplicate code of Slicing.cpp. double layer_height_max = DBL_MAX; - const PrintConfig& print_config = print_object.print()->config(); - const std::vector& nozzle_diameters = dynamic_cast(print_config.option("nozzle_diameter"))->values; - const std::vector& layer_heights_min = dynamic_cast(print_config.option("min_layer_height"))->values; - const std::vector& layer_heights_max = dynamic_cast(print_config.option("max_layer_height"))->values; + const std::vector& nozzle_diameters = dynamic_cast(m_config->option("nozzle_diameter"))->values; + const std::vector& layer_heights_min = dynamic_cast(m_config->option("min_layer_height"))->values; + const std::vector& layer_heights_max = dynamic_cast(m_config->option("max_layer_height"))->values; for (unsigned int i = 0; i < (unsigned int)nozzle_diameters.size(); ++i) { double lh_min = (layer_heights_min[i] == 0.0) ? 0.07 : std::max(0.01, layer_heights_min[i]); @@ -1086,15 +1088,19 @@ void GLCanvas3D::LayersEditing::_render_profile(const PrintObject& print_object, // Make the vertical bar a bit wider so the layer height curve does not touch the edge of the bar region. layer_height_max *= 1.12; - double max_z = unscale(print_object.size(2)); - double layer_height = dynamic_cast(print_object.config().option("layer_height"))->value; + // Get global layer height. + double layer_height = dynamic_cast(m_config->option("layer_height"))->value; + // Override the global layer height with object's layer height if set. + const ConfigOption *opt_object_layer_height = m_model_object->config.option("layer_height"); + if (opt_object_layer_height != nullptr) + layer_height = dynamic_cast(opt_object_layer_height)->value; float l = bar_rect.get_left(); float w = bar_rect.get_right() - l; float b = bar_rect.get_bottom(); float t = bar_rect.get_top(); float h = t - b; float scale_x = w / (float)layer_height_max; - float scale_y = h / (float)max_z; + float scale_y = h / m_object_max_z; float x = l + (float)layer_height * scale_x; // Baseline @@ -1105,19 +1111,129 @@ void GLCanvas3D::LayersEditing::_render_profile(const PrintObject& print_object, ::glEnd(); // Curve - const ModelObject* model_object = print_object.model_object(); - if (model_object->layer_height_profile_valid) - { - const std::vector& profile = model_object->layer_height_profile; + ::glColor3f(0.0f, 0.0f, 1.0f); + ::glBegin(GL_LINE_STRIP); + for (unsigned int i = 0; i < m_layer_height_profile.size(); i += 2) + ::glVertex2f(l + (float)m_layer_height_profile[i + 1] * scale_x, b + (float)m_layer_height_profile[i] * scale_y); + ::glEnd(); +} - ::glColor3f(0.0f, 0.0f, 1.0f); - ::glBegin(GL_LINE_STRIP); - for (unsigned int i = 0; i < profile.size(); i += 2) - { - ::glVertex2f(l + (float)profile[i + 1] * scale_x, b + (float)profile[i] * scale_y); +void GLCanvas3D::LayersEditing::render_volumes(const GLCanvas3D& canvas, const GLVolumeCollection &volumes) const +{ + assert(this->is_allowed()); + assert(this->last_object_id != -1); + GLint shader_id = m_shader.get_shader()->shader_program_id; + assert(shader_id > 0); + + GLint current_program_id; + glGetIntegerv(GL_CURRENT_PROGRAM, ¤t_program_id); + if (shader_id > 0 && shader_id != current_program_id) + // The layer editing shader is not yet active. Activate it. + glUseProgram(shader_id); + else + // The layer editing shader was already active. + current_program_id = -1; + + GLint z_to_texture_row_id = glGetUniformLocation(shader_id, "z_to_texture_row"); + GLint z_texture_row_to_normalized_id = glGetUniformLocation(shader_id, "z_texture_row_to_normalized"); + GLint z_cursor_id = glGetUniformLocation(shader_id, "z_cursor"); + GLint z_cursor_band_width_id = glGetUniformLocation(shader_id, "z_cursor_band_width"); + GLint world_matrix_id = glGetUniformLocation(shader_id, "volume_world_matrix"); + + if (z_to_texture_row_id != -1 && z_texture_row_to_normalized_id != -1 && z_cursor_id != -1 && z_cursor_band_width_id != -1 && world_matrix_id != -1) + { + const_cast(this)->generate_layer_height_texture(); + + // Uniforms were resolved, go ahead using the layer editing shader. + glUniform1f(z_to_texture_row_id, GLfloat(m_layers_texture.cells - 1) / (GLfloat(m_layers_texture.width) * GLfloat(m_object_max_z))); + glUniform1f(z_texture_row_to_normalized_id, GLfloat(1.0f / m_layers_texture.height)); + glUniform1f(z_cursor_id, GLfloat(m_object_max_z) * GLfloat(this->get_cursor_z_relative(canvas))); + glUniform1f(z_cursor_band_width_id, GLfloat(this->band_width)); + // Initialize the layer height texture mapping. + GLsizei w = (GLsizei)m_layers_texture.width; + GLsizei h = (GLsizei)m_layers_texture.height; + GLsizei half_w = w / 2; + GLsizei half_h = h / 2; + ::glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glBindTexture(GL_TEXTURE_2D, m_z_texture_id); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); + glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, half_w, half_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, m_layers_texture.data.data()); + glTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, half_w, half_h, GL_RGBA, GL_UNSIGNED_BYTE, m_layers_texture.data.data() + m_layers_texture.width * m_layers_texture.height * 4); + for (const GLVolume *glvolume : volumes.volumes) { + // Render the object using the layer editing shader and texture. + if (! glvolume->is_active || glvolume->composite_id.object_id != this->last_object_id || glvolume->is_modifier) + continue; + ::glUniformMatrix4fv(world_matrix_id, 1, GL_FALSE, (const GLfloat*)glvolume->world_matrix().cast().data()); + glvolume->render(); } - ::glEnd(); + // Revert back to the previous shader. + glBindTexture(GL_TEXTURE_2D, 0); + if (current_program_id > 0) + glUseProgram(current_program_id); + } + else + { + // Something went wrong. Just render the object. + assert(false); + for (const GLVolume *glvolume : volumes.volumes) { + // Render the object using the layer editing shader and texture. + if (!glvolume->is_active || glvolume->composite_id.object_id != this->last_object_id || glvolume->is_modifier) + continue; + ::glUniformMatrix4fv(world_matrix_id, 1, GL_FALSE, (const GLfloat*)glvolume->world_matrix().cast().data()); + glvolume->render(); + } + } +} + +void GLCanvas3D::LayersEditing::adjust_layer_height_profile() +{ + *m_slicing_parameters = PrintObject::slicing_parameters(*m_config, *m_model_object); + PrintObject::update_layer_height_profile(*m_model_object, *m_slicing_parameters, m_layer_height_profile); + Slic3r::adjust_layer_height_profile(*m_slicing_parameters, m_layer_height_profile, this->last_z, this->strength, this->band_width, this->last_action); + m_layer_height_profile_modified = true; + m_layers_texture.valid = false; +} + +void GLCanvas3D::LayersEditing::generate_layer_height_texture() +{ + // Always try to update the layer height profile. + bool update = ! m_layers_texture.valid; + *m_slicing_parameters = PrintObject::slicing_parameters(*m_config, *m_model_object); + if (PrintObject::update_layer_height_profile(*m_model_object, *m_slicing_parameters, m_layer_height_profile)) { + // Initialized to the default value. + m_layer_height_profile_modified = false; + update = true; } + // Update if the layer height profile was changed, or when the texture is not valid. + if (! update && ! m_layers_texture.data.empty() && m_layers_texture.cells > 0) + // Texture is valid, don't update. + return; + + if (m_layers_texture.data.empty()) { + m_layers_texture.width = 1024; + m_layers_texture.height = 1024; + m_layers_texture.levels = 2; + m_layers_texture.data.assign(m_layers_texture.width * m_layers_texture.height * 5, 0); + } + + bool level_of_detail_2nd_level = true; + m_layers_texture.cells = Slic3r::generate_layer_height_texture( + *m_slicing_parameters, + Slic3r::generate_object_layers(*m_slicing_parameters, m_layer_height_profile), + m_layers_texture.data.data(), m_layers_texture.height, m_layers_texture.width, level_of_detail_2nd_level); + m_layers_texture.valid = true; +} + +void GLCanvas3D::LayersEditing::accept_changes(GLCanvas3D& canvas) +{ + if (last_object_id >= 0) { + if (m_layer_height_profile_modified) { + const_cast(m_model_object)->layer_height_profile = m_layer_height_profile; + canvas.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); + } + } + m_layer_height_profile_modified = false; } const Point GLCanvas3D::Mouse::Drag::Invalid_2D_Point(INT_MAX, INT_MAX); @@ -3689,7 +3805,6 @@ wxDEFINE_EVENT(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS, SimpleEvent); wxDEFINE_EVENT(EVT_GLCANVAS_OBJECT_SELECT, SimpleEvent); wxDEFINE_EVENT(EVT_GLCANVAS_VIEWPORT_CHANGED, SimpleEvent); wxDEFINE_EVENT(EVT_GLCANVAS_RIGHT_CLICK, Vec2dEvent); -wxDEFINE_EVENT(EVT_GLCANVAS_MODEL_UPDATE, SimpleEvent); wxDEFINE_EVENT(EVT_GLCANVAS_REMOVE_OBJECT, SimpleEvent); wxDEFINE_EVENT(EVT_GLCANVAS_ARRANGE, SimpleEvent); wxDEFINE_EVENT(EVT_GLCANVAS_QUESTION_MARK, SimpleEvent); @@ -3916,9 +4031,10 @@ int GLCanvas3D::check_volumes_outside_state() const return (int)state; } -void GLCanvas3D::set_config(DynamicPrintConfig* config) +void GLCanvas3D::set_config(const DynamicPrintConfig* config) { m_config = config; + m_layers_editing.set_config(config); } void GLCanvas3D::set_process(BackgroundSlicingProcess *process) @@ -4262,7 +4378,8 @@ void GLCanvas3D::render() _resize_toolbars(); _render_toolbar(); _render_view_toolbar(); - _render_layer_editing_overlay(); + if (m_layers_editing.last_object_id >= 0) + m_layers_editing.render_overlay(*this); #if ENABLE_IMGUI wxGetApp().imgui()->render(); @@ -4502,8 +4619,6 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re m_volumes.volumes = std::move(glvolumes_new); for (unsigned int obj_idx = 0; obj_idx < (unsigned int)m_model->objects.size(); ++ obj_idx) { const ModelObject &model_object = *m_model->objects[obj_idx]; - // Object will share a single common layer height texture between all printable volumes. - std::shared_ptr layer_height_texture; for (int volume_idx = 0; volume_idx < (int)model_object.volumes.size(); ++ volume_idx) { const ModelVolume &model_volume = *model_object.volumes[volume_idx]; for (int instance_idx = 0; instance_idx < (int)model_object.instances.size(); ++ instance_idx) { @@ -4513,33 +4628,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re assert(it != model_volume_state.end() && it->geometry_id == key.geometry_id); if (it->new_geometry()) { // New volume. - if (model_volume.is_model_part() && ! layer_height_texture) { - // New object part needs to have the layer height texture assigned, which is shared with the other volumes of the same part. - // Search for the layer height texture in the other volumes. - for (int iv = volume_idx; iv < (int)model_object.volumes.size(); ++ iv) { - const ModelVolume &mv = *model_object.volumes[iv]; - if (mv.is_model_part()) - for (int ii = instance_idx; ii < (int)model_object.instances.size(); ++ ii) { - const ModelInstance &mi = *model_object.instances[ii]; - ModelVolumeState key(mv.id(), mi.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); - if (! it->new_geometry()) { - // Found an old printable GLVolume (existing before this function was called). - assert(m_volumes.volumes[it->volume_idx]->geometry_id == key.geometry_id); - // Reuse the layer height texture. - const GLVolume *volume = m_volumes.volumes[it->volume_idx]; - assert(volume->layer_height_texture); - layer_height_texture = volume->layer_height_texture; - goto iv_end; - } - } - } - iv_end: - if (! layer_height_texture) - layer_height_texture = std::make_shared(); - } - m_volumes.load_object_volume(&model_object, layer_height_texture, obj_idx, volume_idx, instance_idx, m_color_by, m_use_VBOs && m_initialized); + m_volumes.load_object_volume(&model_object, obj_idx, volume_idx, instance_idx, m_color_by, m_use_VBOs && m_initialized); m_volumes.volumes.back()->geometry_id = key.geometry_id; } else { // Recycling an old GLVolume. @@ -4547,11 +4636,6 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re assert(existing_volume.geometry_id == key.geometry_id); // Update the Object/Volume/Instance indices into the current Model. existing_volume.composite_id = it->composite_id; - if (model_volume.is_model_part() && ! layer_height_texture) { - assert(existing_volume.layer_height_texture); - // cache its layer height texture - layer_height_texture = existing_volume.layer_height_texture; - } } } } @@ -4945,10 +5029,8 @@ void GLCanvas3D::on_mouse_wheel(wxMouseEvent& evt) void GLCanvas3D::on_timer(wxTimerEvent& evt) { - if (m_layers_editing.state != LayersEditing::Editing) - return; - - _perform_layer_editing_action(); + if (m_layers_editing.state == LayersEditing::Editing) + _perform_layer_editing_action(); } void GLCanvas3D::on_mouse(wxMouseEvent& evt) @@ -4967,7 +5049,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) int selected_object_idx = m_selection.get_object_idx(); int layer_editing_object_idx = is_layers_editing_enabled() ? selected_object_idx : -1; - m_layers_editing.last_object_id = layer_editing_object_idx; + m_layers_editing.select_object(*m_model, layer_editing_object_idx); bool gizmos_overlay_contains_mouse = m_gizmos.overlay_contains_mouse(*this, m_mouse.position); int toolbar_contains_mouse = m_toolbar.contains_mouse(m_mouse.position, *this); int view_toolbar_contains_mouse = (m_view_toolbar != nullptr) ? m_view_toolbar->contains_mouse(m_mouse.position, *this) : -1; @@ -5032,10 +5114,8 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) { if (evt.LeftDown()) { - // A volume is selected and the mouse is inside the reset button. - // The PrintObject::adjust_layer_height_profile() call adjusts the profile of its associated ModelObject, it does not modify the profile of the PrintObject itself, - // therefore it is safe to call it while the background processing is running. - const_cast(this->fff_print()->get_object(layer_editing_object_idx))->reset_layer_height_profile(); + // A volume is selected and the mouse is inside the reset button. Reset the ModelObject's layer height profile. + m_model->objects[layer_editing_object_idx]->layer_height_profile.clear(); // Index 2 means no editing, just wait for mouse up event. m_layers_editing.state = LayersEditing::Completed; @@ -5296,9 +5376,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) { m_layers_editing.state = LayersEditing::Unknown; _stop_timer(); - - if (layer_editing_object_idx != -1) - post_event(SimpleEvent(EVT_GLCANVAS_MODEL_UPDATE)); + m_layers_editing.accept_changes(*this); } else if ((m_mouse.drag.move_volume_idx != -1) && m_mouse.dragging) { @@ -6074,28 +6152,6 @@ float GLCanvas3D::_get_zoom_to_bounding_box_factor(const BoundingBoxf3& bbox) co return (float)std::min((double)cnv_size.get_width() / max_x, (double)cnv_size.get_height() / max_y); } -void GLCanvas3D::_mark_volumes_for_layer_height() const -{ - const Print *print = (m_process == nullptr) ? nullptr : m_process->fff_print(); - if (print == nullptr) - return; - - for (GLVolume* vol : m_volumes.volumes) - { - int object_id = vol->object_idx(); - int shader_id = m_layers_editing.get_shader_program_id(); - - if (is_layers_editing_enabled() && (shader_id != -1) && vol->selected && - vol->has_layer_height_texture() && (object_id < (int)print->objects().size())) - { - vol->set_layer_height_texture_data(m_layers_editing.get_z_texture_id(), shader_id, - print->get_object(object_id), _get_layers_editing_cursor_z_relative(), m_layers_editing.band_width); - } - else - vol->reset_layer_height_texture_data(); - } -} - void GLCanvas3D::_refresh_if_shown_on_screen() { if (_is_shown_on_screen()) @@ -6241,7 +6297,8 @@ void GLCanvas3D::_render_objects() const { if (m_picking_enabled) { - _mark_volumes_for_layer_height(); + // Update the layer editing selection to the first object selected, update the current object maximum Z. + const_cast(m_layers_editing).select_object(*m_model, this->is_layers_editing_enabled() ? m_selection.get_object_idx() : -1); if (m_config != nullptr) { @@ -6262,8 +6319,18 @@ void GLCanvas3D::_render_objects() const m_shader.start_using(); #if ENABLE_IMPROVED_TRANSPARENT_VOLUMES_RENDERING - // do not cull backfaces to show broken geometry, if any - m_volumes.render_VBOs(GLVolumeCollection::Opaque, m_picking_enabled); + if (m_picking_enabled && m_layers_editing.is_enabled() && m_layers_editing.last_object_id != -1) { + int object_id = m_layers_editing.last_object_id; + m_volumes.render_VBOs(GLVolumeCollection::Opaque, false, [object_id](const GLVolume &volume) { + // Which volume to paint without the layer height profile shader? + return volume.is_active && (volume.is_modifier || volume.composite_id.object_id != object_id); + }); + // Let LayersEditing handle rendering of the active object using the layer height profile shader. + m_layers_editing.render_volumes(*this, this->m_volumes); + } else { + // do not cull backfaces to show broken geometry, if any + m_volumes.render_VBOs(GLVolumeCollection::Opaque, m_picking_enabled); + } m_volumes.render_VBOs(GLVolumeCollection::Transparent, false); #else m_volumes.render_VBOs(); @@ -6344,39 +6411,6 @@ void GLCanvas3D::_render_legend_texture() const m_legend_texture.render(*this); } -void GLCanvas3D::_render_layer_editing_overlay() const -{ - const Print *print = this->fff_print(); - if ((print == nullptr) || print->objects().empty()) - return; - - GLVolume* volume = nullptr; - - for (GLVolume* vol : m_volumes.volumes) - { - if ((vol != nullptr) && vol->selected && vol->has_layer_height_texture()) - { - volume = vol; - break; - } - } - - if (volume == nullptr) - return; - - // If the active object was not allocated at the Print, go away.This should only be a momentary case between an object addition / deletion - // and an update by Platter::async_apply_config. - int object_idx = volume->object_idx(); - if ((int)print->objects().size() <= object_idx) - return; - - const PrintObject* print_object = print->get_object(object_idx); - if (print_object == nullptr) - return; - - m_layers_editing.render(*this, *print_object, *volume); -} - void GLCanvas3D::_render_volumes(bool fake_colors) const { static const GLfloat INV_255 = 1.0f / 255.0f; @@ -6776,55 +6810,24 @@ void GLCanvas3D::_update_gizmos_data() } } -float GLCanvas3D::_get_layers_editing_cursor_z_relative() const -{ - return m_layers_editing.get_cursor_z_relative(*this); -} - void GLCanvas3D::_perform_layer_editing_action(wxMouseEvent* evt) { int object_idx_selected = m_layers_editing.last_object_id; if (object_idx_selected == -1) return; - const Print *print = this->fff_print(); - if (print == nullptr) - return; - - const PrintObject* selected_obj = print->get_object(object_idx_selected); - if (selected_obj == nullptr) - return; - // A volume is selected. Test, whether hovering over a layer thickness bar. if (evt != nullptr) { const Rect& rect = LayersEditing::get_bar_rect_screen(*this); float b = rect.get_bottom(); - m_layers_editing.last_z = unscale(selected_obj->size(2)) * (b - evt->GetY() - 1.0f) / (b - rect.get_top()); - m_layers_editing.last_action = evt->ShiftDown() ? (evt->RightIsDown() ? 3 : 2) : (evt->RightIsDown() ? 0 : 1); + m_layers_editing.last_z = m_layers_editing.object_max_z() * (b - evt->GetY() - 1.0f) / (b - rect.get_top()); + m_layers_editing.last_action = + evt->ShiftDown() ? (evt->RightIsDown() ? LAYER_HEIGHT_EDIT_ACTION_SMOOTH : LAYER_HEIGHT_EDIT_ACTION_REDUCE) : + (evt->RightIsDown() ? LAYER_HEIGHT_EDIT_ACTION_INCREASE : LAYER_HEIGHT_EDIT_ACTION_DECREASE); } - // Mark the volume as modified, so Print will pick its layer height profile ? Where to mark it ? - // Start a timer to refresh the print ? schedule_background_process() ? - // The PrintObject::adjust_layer_height_profile() call adjusts the profile of its associated ModelObject, it does not modify the profile of the PrintObject itself, - // therefore it is safe to call it while the background processing is running. - const_cast(selected_obj)->adjust_layer_height_profile(m_layers_editing.last_z, m_layers_editing.strength, m_layers_editing.band_width, m_layers_editing.last_action); - - // searches the id of the first volume of the selected object - int volume_idx = 0; - for (int i = 0; i < object_idx_selected; ++i) - { - const PrintObject* obj = print->get_object(i); - if (obj != nullptr) - { - for (int j = 0; j < (int)obj->region_volumes.size(); ++j) - { - volume_idx += (int)obj->region_volumes[j].size(); - } - } - } - - m_volumes.volumes[volume_idx]->generate_layer_height_texture(selected_obj, 1); + m_layers_editing.adjust_layer_height_profile(); _refresh_if_shown_on_screen(); // Automatic action on mouse down with the same coordinate. diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 625c73169..6c6ea9af8 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -29,6 +29,8 @@ class GLShader; class ExPolygon; class BackgroundSlicingProcess; class GCodePreviewData; +struct SlicingParameters; +enum LayerHeightEditActionType : unsigned int; namespace GUI { @@ -101,7 +103,6 @@ wxDECLARE_EVENT(EVT_GLCANVAS_INIT, SimpleEvent); wxDECLARE_EVENT(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS, SimpleEvent); wxDECLARE_EVENT(EVT_GLCANVAS_VIEWPORT_CHANGED, SimpleEvent); wxDECLARE_EVENT(EVT_GLCANVAS_RIGHT_CLICK, Vec2dEvent); -wxDECLARE_EVENT(EVT_GLCANVAS_MODEL_UPDATE, SimpleEvent); wxDECLARE_EVENT(EVT_GLCANVAS_REMOVE_OBJECT, SimpleEvent); wxDECLARE_EVENT(EVT_GLCANVAS_ARRANGE, SimpleEvent); wxDECLARE_EVENT(EVT_GLCANVAS_QUESTION_MARK, SimpleEvent); @@ -293,12 +294,42 @@ class GLCanvas3D }; private: - bool m_use_legacy_opengl; - bool m_enabled; - Shader m_shader; - unsigned int m_z_texture_id; - mutable GLTexture m_tooltip_texture; - mutable GLTexture m_reset_texture; + bool m_use_legacy_opengl; + bool m_enabled; + Shader m_shader; + unsigned int m_z_texture_id; + mutable GLTexture m_tooltip_texture; + mutable GLTexture m_reset_texture; + // Not owned by LayersEditing. + const DynamicPrintConfig *m_config; + // ModelObject for the currently selected object (Model::objects[last_object_id]). + const ModelObject *m_model_object; + // Maximum z of the currently selected object (Model::objects[last_object_id]). + float m_object_max_z; + // Owned by LayersEditing. + SlicingParameters *m_slicing_parameters; + std::vector m_layer_height_profile; + bool m_layer_height_profile_modified; + + class LayersTexture + { + public: + LayersTexture() : width(0), height(0), levels(0), cells(0), valid(false) {} + + // Texture data + std::vector data; + // Width of the texture, top level. + size_t width; + // Height of the texture, top level. + size_t height; + // For how many levels of detail is the data allocated? + size_t levels; + // Number of texture cells allocated for the height texture. + size_t cells; + // Does it need to be refreshed? + bool valid; + }; + LayersTexture m_layers_texture; public: EState state; @@ -306,12 +337,14 @@ class GLCanvas3D float strength; int last_object_id; float last_z; - unsigned int last_action; + LayerHeightEditActionType last_action; LayersEditing(); ~LayersEditing(); bool init(const std::string& vertex_shader_filename, const std::string& fragment_shader_filename); + void set_config(const DynamicPrintConfig* config) { m_config = config; } + void select_object(const Model &model, int object_id); bool is_allowed() const; void set_use_legacy_opengl(bool use_legacy_opengl); @@ -319,11 +352,12 @@ class GLCanvas3D bool is_enabled() const; void set_enabled(bool enabled); - unsigned int get_z_texture_id() const; + void render_overlay(const GLCanvas3D& canvas) const; + void render_volumes(const GLCanvas3D& canvas, const GLVolumeCollection& volumes) const; - void render(const GLCanvas3D& canvas, const PrintObject& print_object, const GLVolume& volume) const; - - int get_shader_program_id() const; + void generate_layer_height_texture(); + void adjust_layer_height_profile(); + void accept_changes(GLCanvas3D& canvas); static float get_cursor_z_relative(const GLCanvas3D& canvas); static bool bar_rect_contains(const GLCanvas3D& canvas, float x, float y); @@ -333,12 +367,14 @@ class GLCanvas3D static Rect get_bar_rect_viewport(const GLCanvas3D& canvas); static Rect get_reset_rect_viewport(const GLCanvas3D& canvas); + float object_max_z() const { return m_object_max_z; } + private: bool _is_initialized() const; void _render_tooltip_texture(const GLCanvas3D& canvas, const Rect& bar_rect, const Rect& reset_rect) const; void _render_reset_texture(const Rect& reset_rect) const; - void _render_active_object_annotations(const GLCanvas3D& canvas, const GLVolume& volume, const PrintObject& print_object, const Rect& bar_rect) const; - void _render_profile(const PrintObject& print_object, const Rect& bar_rect) const; + void _render_active_object_annotations(const GLCanvas3D& canvas, const Rect& bar_rect) const; + void _render_profile(const Rect& bar_rect) const; }; struct Mouse @@ -821,7 +857,7 @@ private: mutable GLVolumeCollection m_volumes; Selection m_selection; - DynamicPrintConfig* m_config; + const DynamicPrintConfig* m_config; Model* m_model; BackgroundSlicingProcess *m_process; @@ -881,7 +917,7 @@ public: void reset_volumes(); int check_volumes_outside_state() const; - void set_config(DynamicPrintConfig* config); + void set_config(const DynamicPrintConfig* config); void set_process(BackgroundSlicingProcess* process); void set_model(Model* model); @@ -1023,7 +1059,6 @@ private: void _zoom_to_bounding_box(const BoundingBoxf3& bbox); float _get_zoom_to_bounding_box_factor(const BoundingBoxf3& bbox) const; - void _mark_volumes_for_layer_height() const; void _refresh_if_shown_on_screen(); void _camera_tranform() const; @@ -1038,7 +1073,6 @@ private: #endif // ENABLE_RENDER_SELECTION_CENTER void _render_warning_texture() const; void _render_legend_texture() const; - void _render_layer_editing_overlay() const; void _render_volumes(bool fake_colors) const; void _render_current_gizmo() const; void _render_gizmos_overlay() const; @@ -1055,7 +1089,6 @@ private: void _update_volumes_hover_state() const; void _update_gizmos_data(); - float _get_layers_editing_cursor_z_relative() const; void _perform_layer_editing_action(wxMouseEvent* evt = nullptr); // Convert the screen space coordinate to an object space coordinate. diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp index ad432c273..53ca52cb6 100644 --- a/src/slic3r/GUI/GUI_Preview.cpp +++ b/src/slic3r/GUI/GUI_Preview.cpp @@ -27,7 +27,7 @@ namespace Slic3r { namespace GUI { - View3D::View3D(wxWindow* parent, Model* model, DynamicPrintConfig* config, BackgroundSlicingProcess* process) +View3D::View3D(wxWindow* parent, Model* model, DynamicPrintConfig* config, BackgroundSlicingProcess* process) : m_canvas_widget(nullptr) , m_canvas(nullptr) #if !ENABLE_IMGUI diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index 2a6003986..15bb2c07b 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -159,6 +159,7 @@ void MainFrame::create_preset_tabs() add_created_tab(new TabSLAPrint(m_tabpanel)); add_created_tab(new TabSLAMaterial(m_tabpanel)); add_created_tab(new TabPrinter(m_tabpanel)); + GUI::wxGetApp().load_current_presets(); } void MainFrame::add_created_tab(Tab* panel) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index ad4472bcf..61918562f 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1088,7 +1088,10 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) "brim_width", "variable_layer_height", "serial_port", "serial_speed", "host_type", "print_host", "printhost_apikey", "printhost_cafile", "nozzle_diameter", "single_extruder_multi_material", "wipe_tower", "wipe_tower_x", "wipe_tower_y", "wipe_tower_width", "wipe_tower_rotation_angle", - "extruder_colour", "filament_colour", "max_print_height", "printer_model", "printer_technology" + "extruder_colour", "filament_colour", "max_print_height", "printer_model", "printer_technology", + // The following three layer height config values are passed here for View3D::m_canvas to receive + // layer height updates for the layer height. + "min_layer_height", "max_layer_height", "layer_height", "first_layer_height" })) , sidebar(new Sidebar(q)) , delayed_scene_refresh(false) @@ -1157,7 +1160,6 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) view3D_canvas->Bind(EVT_GLCANVAS_OBJECT_SELECT, &priv::on_object_select, this); view3D_canvas->Bind(EVT_GLCANVAS_VIEWPORT_CHANGED, &priv::on_viewport_changed, this); view3D_canvas->Bind(EVT_GLCANVAS_RIGHT_CLICK, &priv::on_right_click, this); - view3D_canvas->Bind(EVT_GLCANVAS_MODEL_UPDATE, [this](SimpleEvent&) { this->schedule_background_process(); }); view3D_canvas->Bind(EVT_GLCANVAS_REMOVE_OBJECT, [q](SimpleEvent&) { q->remove_selected(); }); view3D_canvas->Bind(EVT_GLCANVAS_ARRANGE, [this](SimpleEvent&) { arrange(); }); view3D_canvas->Bind(EVT_GLCANVAS_QUESTION_MARK, [this](SimpleEvent&) { wxGetApp().keyboard_shortcuts(); }); @@ -2035,7 +2037,7 @@ void Plater::priv::reload_from_disk() } } - // XXX: Restore more: layer_height_ranges, layer_height_profile, layer_height_profile_valid (?) + // XXX: Restore more: layer_height_ranges, layer_height_profile (?) } remove(obj_orig_idx); @@ -2066,7 +2068,7 @@ void Plater::priv::fix_through_netfabb(const int obj_idx) o->volumes[i]->config.apply(model_object->volumes[i]->config); } } - // FIXME restore volumes and their configs, layer_height_ranges, layer_height_profile, layer_height_profile_valid, + // FIXME restore volumes and their configs, layer_height_ranges, layer_height_profile } remove(obj_idx); diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 02366c721..0b1f1e571 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -245,9 +245,6 @@ void Tab::create_preset_tab() // Initialize the DynamicPrintConfig by default keys/values. build(); rebuild_page_tree(); -// update(); - // Load the currently selected preset into the GUI, update the preset selection box. - load_current_preset(); } void Tab::load_initial_data() From 207c87a3d1aaf94f5b10507fbf27719981eef737 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Mon, 21 Jan 2019 10:34:10 +0100 Subject: [PATCH 17/18] Many comments for maintainability. --- src/libslic3r/ModelArrange.cpp | 84 +++++++++++++++++++++++----------- 1 file changed, 58 insertions(+), 26 deletions(-) diff --git a/src/libslic3r/ModelArrange.cpp b/src/libslic3r/ModelArrange.cpp index 8ed595802..1f517375c 100644 --- a/src/libslic3r/ModelArrange.cpp +++ b/src/libslic3r/ModelArrange.cpp @@ -15,6 +15,7 @@ namespace arr { using namespace libnest2d; +// Only for debugging. Prints the model object vertices on stdout. std::string toString(const Model& model, bool holes = true) { std::stringstream ss; @@ -78,6 +79,7 @@ std::string toString(const Model& model, bool holes = true) { return ss.str(); } +// Debugging: Save model to svg file. void toSVG(SVG& svg, const Model& model) { for(auto objptr : model.objects) { if(!objptr) continue; @@ -121,6 +123,10 @@ Box boundingBox(const Box& pilebb, const Box& ibb ) { return Box(minc, maxc); } +// This is "the" object function which is evaluated many times for each vertex +// (decimated with the accuracy parameter) of each object. Therefore it is +// upmost crucial for this function to be as efficient as it possibly can be but +// at the same time, it has to provide reasonable results. std::tuple objfunc(const PointImpl& bincenter, const shapelike::Shapes& merged_pile, @@ -253,6 +259,8 @@ objfunc(const PointImpl& bincenter, return std::make_tuple(score, fullbb); } +// Fill in the placer algorithm configuration with values carefully chosen for +// Slic3r. template void fillConfig(PConf& pcfg) { @@ -274,13 +282,19 @@ void fillConfig(PConf& pcfg) { pcfg.parallel = true; } +// Type trait for an arranger class for different bin types (box, circle, +// polygon, etc...) template class AutoArranger {}; + +// A class encapsulating the libnest2d Nester class and extending it with other +// management and spatial index structures for acceleration. template class _ArrBase { protected: + // Useful type shortcuts... using Placer = TPacker; using Selector = FirstFitSelection; using Packer = Nester; @@ -289,15 +303,15 @@ protected: using Pile = sl::Shapes; Packer m_pck; - PConfig m_pconf; // Placement configuration + PConfig m_pconf; // Placement configuration double m_bin_area; - SpatIndex m_rtree; - SpatIndex m_smallsrtree; - double m_norm; - Pile m_merged_pile; - Box m_pilebb; - ItemGroup m_remaining; - ItemGroup m_items; + SpatIndex m_rtree; // spatial index for the normal (bigger) objects + SpatIndex m_smallsrtree; // spatial index for only the smaller items + double m_norm; // A coefficient to scale distances + Pile m_merged_pile; // The already merged pile (vector of items) + Box m_pilebb; // The bounding box of the merged pile. + ItemGroup m_remaining; // Remaining items (m_items at the beginning) + ItemGroup m_items; // The items to be packed public: _ArrBase(const TBin& bin, Distance dist, @@ -308,6 +322,8 @@ public: { fillConfig(m_pconf); + // Set up a callback that is called just before arranging starts + // This functionality is provided by the Nester class (m_pack). m_pconf.before_packing = [this](const Pile& merged_pile, // merged pile const ItemGroup& items, // packed items @@ -344,8 +360,8 @@ public: } }; -template<> -class AutoArranger: public _ArrBase { +// Arranger specialization for a Box shaped bin. +template<> class AutoArranger: public _ArrBase { public: AutoArranger(const Box& bin, Distance dist, @@ -354,6 +370,9 @@ public: _ArrBase(bin, dist, progressind, stopcond) { + // Here we set up the actual object function that calls the common + // object function for all bin shapes than does an additional inside + // check for the arranged pile. m_pconf.object_function = [this, bin] (const Item &item) { auto result = objfunc(bin.center(), @@ -387,8 +406,8 @@ inline lnCircle to_lnCircle(const Circle& circ) { return lnCircle({circ.center()(0), circ.center()(1)}, circ.radius()); } -template<> -class AutoArranger: public _ArrBase { +// Arranger specialization for circle shaped bin. +template<> class AutoArranger: public _ArrBase { public: AutoArranger(const lnCircle& bin, Distance dist, @@ -396,6 +415,7 @@ public: std::function stopcond): _ArrBase(bin, dist, progressind, stopcond) { + // As with the box, only the inside check is different. m_pconf.object_function = [this, &bin] (const Item &item) { auto result = objfunc(bin.center(), @@ -431,8 +451,9 @@ public: } }; -template<> -class AutoArranger: public _ArrBase { +// Arranger specialization for a generalized polygon. +// Warning: this is unfinished business. It may or may not work. +template<> class AutoArranger: public _ArrBase { public: AutoArranger(const PolygonImpl& bin, Distance dist, std::function progressind, @@ -461,8 +482,10 @@ public: } }; -template<> // Specialization with no bin -class AutoArranger: public _ArrBase { +// Specialization with no bin. In this case the arranger should just arrange +// all objects into a minimum sized pile but it is not limited by a bin. A +// consequence is that only one pile should be created. +template<> class AutoArranger: public _ArrBase { public: AutoArranger(Distance dist, std::function progressind, @@ -490,14 +513,15 @@ public: // A container which stores a pointer to the 3D object and its projected // 2D shape from top view. -using ShapeData2D = - std::vector>; +using ShapeData2D = std::vector>; ShapeData2D projectModelFromTop(const Slic3r::Model &model) { ShapeData2D ret; - auto s = std::accumulate(model.objects.begin(), model.objects.end(), size_t(0), - [](size_t s, ModelObject* o){ + // Count all the items on the bin (all the object's instances) + auto s = std::accumulate(model.objects.begin(), model.objects.end(), + size_t(0), [](size_t s, ModelObject* o) + { return s + o->instances.size(); }); @@ -517,7 +541,8 @@ ShapeData2D projectModelFromTop(const Slic3r::Model &model) { rmesh.rotate_x(float(finst->get_rotation()(X))); rmesh.rotate_y(float(finst->get_rotation()(Y))); - // TODO export the exact 2D projection + // TODO export the exact 2D projection. Cannot do it as libnest2d + // does not support concave shapes (yet). auto p = rmesh.convex_hull(); p.make_clockwise(); @@ -549,6 +574,8 @@ ShapeData2D projectModelFromTop(const Slic3r::Model &model) { return ret; } +// Apply the calculated translations and rotations (currently disabled) to the +// Model object instances. void applyResult( IndexedPackGroup::value_type& group, Coord batch_offset, @@ -576,6 +603,7 @@ void applyResult( } } +// Get the type of bed geometry from a simple vector of points. BedShapeHint bedShape(const Polyline &bed) { BedShapeHint ret; @@ -654,11 +682,15 @@ BedShapeHint bedShape(const Polyline &bed) { return ret; } -bool arrange(Model &model, - coord_t min_obj_distance, - const Polyline &bed, - BedShapeHint bedhint, - bool first_bin_only, +// The final client function to arrange the Model. A progress indicator and +// a stop predicate can be also be passed to control the process. +bool arrange(Model &model, // The model with the geometries + coord_t min_obj_distance, // Has to be in scaled (clipper) measure + const Polyline &bed, // The bed geometry. + BedShapeHint bedhint, // Hint about the bed geometry type. + bool first_bin_only, // What to do is not all items fit. + + // Controlling callbacks. std::function progressind, std::function stopcondition) { From 528546b6c8a00205344133621bf1ec4e2ce70419 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Mon, 21 Jan 2019 12:53:30 +0100 Subject: [PATCH 18/18] Place on bed should now correctly process instance mirror and respect transformations on subvolumes --- src/slic3r/GUI/GLCanvas3D.cpp | 9 ++++++--- src/slic3r/GUI/GLGizmo.cpp | 11 ++++------- src/slic3r/GUI/GLGizmo.hpp | 1 + 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 24998cd60..cec47c664 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1784,11 +1784,14 @@ void GLCanvas3D::Selection::flattening_rotate(const Vec3d& normal) for (unsigned int i : m_list) { - Transform3d wst = m_cache.volumes_data[i].get_instance_scale_matrix() * m_cache.volumes_data[i].get_volume_scale_matrix(); + Transform3d wst = m_cache.volumes_data[i].get_instance_scale_matrix(); Vec3d scaling_factor = Vec3d(1./wst(0,0), 1./wst(1,1), 1./wst(2,2)); - Vec3d rotation = Geometry::extract_euler_angles(m_cache.volumes_data[i].get_instance_rotation_matrix() * m_cache.volumes_data[i].get_volume_rotation_matrix()); - Vec3d transformed_normal = Geometry::assemble_transform(Vec3d::Zero(), rotation, scaling_factor) * normal; + Transform3d wmt = m_cache.volumes_data[i].get_instance_mirror_matrix(); + Vec3d mirror(wmt(0,0), wmt(1,1), wmt(2,2)); + + Vec3d rotation = Geometry::extract_euler_angles(m_cache.volumes_data[i].get_instance_rotation_matrix()); + Vec3d transformed_normal = Geometry::assemble_transform(Vec3d::Zero(), rotation, scaling_factor, mirror) * normal; transformed_normal.normalize(); Vec3d axis = transformed_normal(2) > 0.999f ? Vec3d(1., 0., 0.) : Vec3d(transformed_normal.cross(Vec3d(0., 0., -1.))); diff --git a/src/slic3r/GUI/GLGizmo.cpp b/src/slic3r/GUI/GLGizmo.cpp index 2ea7e677e..1f37b7aec 100644 --- a/src/slic3r/GUI/GLGizmo.cpp +++ b/src/slic3r/GUI/GLGizmo.cpp @@ -1526,10 +1526,9 @@ void GLGizmoFlatten::update_planes() vol_ch.transform(vol->get_matrix()); ch.merge(vol_ch); } - ch = ch.convex_hull_3d(); m_planes.clear(); - const Transform3d& inst_matrix = m_model_object->instances.front()->get_matrix(); + const Transform3d& inst_matrix = m_model_object->instances.front()->get_matrix(true); // Following constants are used for discarding too small polygons. const float minimal_area = 5.f; // in square mm (world coordinates) @@ -1696,10 +1695,6 @@ void GLGizmoFlatten::update_planes() // Transform back to 3D (and also back to mesh coordinates) polygon = transform(polygon, inst_matrix.inverse() * m.inverse()); - - // make sure the points are in correct order: - if ( ((inst_matrix.inverse() * m.inverse()) * Vec3d(0., 0., 1.)).dot(normal) > 0.) - std::reverse(polygon.begin(),polygon.end()); } // We'll sort the planes by area and only keep the 254 largest ones (because of the picking pass limitations): @@ -1714,6 +1709,7 @@ void GLGizmoFlatten::update_planes() m_volumes_types.push_back(vol->type()); } m_first_instance_scale = m_model_object->instances.front()->get_scaling_factor(); + m_first_instance_mirror = m_model_object->instances.front()->get_mirror(); } @@ -1726,7 +1722,8 @@ bool GLGizmoFlatten::is_plane_update_necessary() const return true; // We want to recalculate when the scale changes - some planes could (dis)appear. - if (! m_model_object->instances.front()->get_scaling_factor().isApprox(m_first_instance_scale)) + if (! m_model_object->instances.front()->get_scaling_factor().isApprox(m_first_instance_scale) + || ! m_model_object->instances.front()->get_mirror().isApprox(m_first_instance_mirror)) return true; for (unsigned int i=0; i < m_model_object->volumes.size(); ++i) diff --git a/src/slic3r/GUI/GLGizmo.hpp b/src/slic3r/GUI/GLGizmo.hpp index ddd57b645..02b637a35 100644 --- a/src/slic3r/GUI/GLGizmo.hpp +++ b/src/slic3r/GUI/GLGizmo.hpp @@ -405,6 +405,7 @@ private: std::vector m_volumes_matrices; std::vector m_volumes_types; Vec3d m_first_instance_scale; + Vec3d m_first_instance_mirror; std::vector m_planes; mutable Vec3d m_starting_center;