From 198600543dd707a51f29660c2583459ae2b34933 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Mon, 24 Jun 2019 15:27:32 +0200 Subject: [PATCH 01/12] Fix of incorrect color print preview due to the tbb::parallel_for not respecting the grain size exactly. Also the tool path generation has been optimized to launch less threads and to produce larger vertex buffers. --- src/slic3r/GUI/GLCanvas3D.cpp | 102 +++++++++++++++++++--------------- 1 file changed, 57 insertions(+), 45 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 19d1bc0edc..3d9b24c11a 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -4627,17 +4627,12 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c bool color_by_tool() const { return tool_colors != nullptr; } size_t number_tools() const { return this->color_by_tool() ? tool_colors->size() / 4 : 0; } const float* color_tool(size_t tool) const { return tool_colors->data() + tool * 4; } - int volume_idx(int extruder, int feature) const - { - return this->color_by_color_print() ? 0 : this->color_by_tool() ? std::min(this->number_tools() - 1, std::max(extruder - 1, 0)) : feature; - } // For coloring by a color_print(M600), return a parsed color. bool color_by_color_print() const { return color_print_values!=nullptr; } - const float* color_print_by_layer_idx(const size_t layer_idx) const - { + const size_t color_print_color_idx_by_layer_idx(const size_t layer_idx) const { auto it = std::lower_bound(color_print_values->begin(), color_print_values->end(), layers[layer_idx]->print_z + EPSILON); - return color_tool((it - color_print_values->begin()) % number_tools()); + return (it - color_print_values->begin()) % number_tools(); } } ctxt; @@ -4670,7 +4665,7 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c BOOST_LOG_TRIVIAL(debug) << "Loading print object toolpaths in parallel - start"; //FIXME Improve the heuristics for a grain size. - size_t grain_size = ctxt.color_by_color_print() ? size_t(1) : std::max(ctxt.layers.size() / 16, size_t(1)); + size_t grain_size = std::max(ctxt.layers.size() / 16, size_t(1)); tbb::spin_mutex new_volume_mutex; auto new_volume = [this, &new_volume_mutex](const float *color) -> GLVolume* { auto *volume = new GLVolume(color); @@ -4679,14 +4674,34 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c new_volume_mutex.unlock(); return volume; }; - const size_t volumes_cnt_initial = m_volumes.volumes.size(); - std::vector volumes_per_thread(ctxt.layers.size()); + const size_t volumes_cnt_initial = m_volumes.volumes.size(); tbb::parallel_for( tbb::blocked_range(0, ctxt.layers.size(), grain_size), [&ctxt, &new_volume](const tbb::blocked_range& range) { - GLVolumePtrs vols; - if (ctxt.color_by_color_print()) - vols.emplace_back(new_volume(ctxt.color_print_by_layer_idx(range.begin()))); + GLVolumePtrs vols; + std::vector color_print_layer_to_glvolume; + auto volume = [&ctxt, &vols, &color_print_layer_to_glvolume, &range](size_t layer_idx, int extruder, int feature) -> GLVolume& { + return *vols[ctxt.color_by_color_print() ? + color_print_layer_to_glvolume[layer_idx - range.begin()] : + ctxt.color_by_tool() ? + std::min(ctxt.number_tools() - 1, std::max(extruder - 1, 0)) : + feature + ]; + }; + if (ctxt.color_by_color_print()) { + // Create a map from the layer index to a GLVolume, which is initialized with the correct layer span color. + std::vector color_print_tool_to_glvolume(ctxt.number_tools(), -1); + color_print_layer_to_glvolume.reserve(range.end() - range.begin()); + vols.reserve(ctxt.number_tools()); + for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++ idx_layer) { + int idx_tool = (int)ctxt.color_print_color_idx_by_layer_idx(idx_layer); + if (color_print_tool_to_glvolume[idx_tool] == -1) { + color_print_tool_to_glvolume[idx_tool] = (int)vols.size(); + vols.emplace_back(new_volume(ctxt.color_tool(idx_tool))); + } + color_print_layer_to_glvolume.emplace_back(color_print_tool_to_glvolume[idx_tool]); + } + } else if (ctxt.color_by_tool()) { for (size_t i = 0; i < ctxt.number_tools(); ++i) vols.emplace_back(new_volume(ctxt.color_tool(i))); @@ -4694,33 +4709,31 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c else vols = { new_volume(ctxt.color_perimeters()), new_volume(ctxt.color_infill()), new_volume(ctxt.color_support()) }; for (GLVolume *vol : vols) - vol->indexed_vertex_array.reserve(ctxt.alloc_size_reserve()); - for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++idx_layer) { + vol->indexed_vertex_array.reserve(ctxt.alloc_size_reserve()); + for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++ idx_layer) { const Layer *layer = ctxt.layers[idx_layer]; - for (size_t i = 0; i < vols.size(); ++i) { - GLVolume &vol = *vols[i]; - if (vol.print_zs.empty() || vol.print_zs.back() != layer->print_z) { - vol.print_zs.push_back(layer->print_z); - vol.offsets.push_back(vol.indexed_vertex_array.quad_indices.size()); - vol.offsets.push_back(vol.indexed_vertex_array.triangle_indices.size()); + for (GLVolume *vol : vols) + if (vol->print_zs.empty() || vol->print_zs.back() != layer->print_z) { + vol->print_zs.push_back(layer->print_z); + vol->offsets.push_back(vol->indexed_vertex_array.quad_indices.size()); + vol->offsets.push_back(vol->indexed_vertex_array.triangle_indices.size()); } - } for (const Point © : *ctxt.shifted_copies) { for (const LayerRegion *layerm : layer->regions()) { if (ctxt.has_perimeters) _3DScene::extrusionentity_to_verts(layerm->perimeters, float(layer->print_z), copy, - *vols[ctxt.volume_idx(layerm->region()->config().perimeter_extruder.value, 0)]); + volume(idx_layer, layerm->region()->config().perimeter_extruder.value, 0)); if (ctxt.has_infill) { for (const ExtrusionEntity *ee : layerm->fills.entities) { // fill represents infill extrusions of a single island. const auto *fill = dynamic_cast(ee); - if (!fill->entities.empty()) + if (! fill->entities.empty()) _3DScene::extrusionentity_to_verts(*fill, float(layer->print_z), copy, - *vols[ctxt.volume_idx( - is_solid_infill(fill->entities.front()->role()) ? - layerm->region()->config().solid_infill_extruder : - layerm->region()->config().infill_extruder, - 1)]); + volume(idx_layer, + is_solid_infill(fill->entities.front()->role()) ? + layerm->region()->config().solid_infill_extruder : + layerm->region()->config().infill_extruder, + 1)); } } } @@ -4729,36 +4742,35 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c if (support_layer) { for (const ExtrusionEntity *extrusion_entity : support_layer->support_fills.entities) _3DScene::extrusionentity_to_verts(extrusion_entity, float(layer->print_z), copy, - *vols[ctxt.volume_idx( - (extrusion_entity->role() == erSupportMaterial) ? - support_layer->object()->config().support_material_extruder : - support_layer->object()->config().support_material_interface_extruder, - 2)]); + volume(idx_layer, + (extrusion_entity->role() == erSupportMaterial) ? + support_layer->object()->config().support_material_extruder : + support_layer->object()->config().support_material_interface_extruder, + 2)); } } } - for (size_t i = 0; i < vols.size(); ++i) { - GLVolume &vol = *vols[i]; - if (vol.indexed_vertex_array.vertices_and_normals_interleaved.size() / 6 > ctxt.alloc_size_max()) { + // Ensure that no volume grows over the limits. If the volume is too large, allocate a new one. + for (GLVolume *&vol : vols) + if (vol->indexed_vertex_array.vertices_and_normals_interleaved.size() / 6 > ctxt.alloc_size_max()) { // Store the vertex arrays and restart their containers, - vols[i] = new_volume(vol.color); - GLVolume &vol_new = *vols[i]; + vol = new_volume(vol->color); + GLVolume &vol_new = *vol; // Assign the large pre-allocated buffers to the new GLVolume. - vol_new.indexed_vertex_array = std::move(vol.indexed_vertex_array); + vol_new.indexed_vertex_array = std::move(vol->indexed_vertex_array); // Copy the content back to the old GLVolume. - vol.indexed_vertex_array = vol_new.indexed_vertex_array; + vol->indexed_vertex_array = vol_new.indexed_vertex_array; // Finalize a bounding box of the old GLVolume. - vol.bounding_box = vol.indexed_vertex_array.bounding_box(); + vol->bounding_box = vol->indexed_vertex_array.bounding_box(); // Clear the buffers, but keep them pre-allocated. vol_new.indexed_vertex_array.clear(); // Just make sure that clear did not clear the reserved memory. vol_new.indexed_vertex_array.reserve(ctxt.alloc_size_reserve()); } - } } for (GLVolume *vol : vols) { - vol->bounding_box = vol->indexed_vertex_array.bounding_box(); - vol->indexed_vertex_array.shrink_to_fit(); + vol->bounding_box = vol->indexed_vertex_array.bounding_box(); + vol->indexed_vertex_array.shrink_to_fit(); } }); From 992170c5f66e1bc823c03a26ad43af8b03d188d3 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Mon, 24 Jun 2019 15:55:14 +0200 Subject: [PATCH 02/12] 1) Perspective camera set as default camera type 2) Camera type selection added to Preferences dialog --- src/slic3r/GUI/AppConfig.cpp | 4 ++-- src/slic3r/GUI/Camera.cpp | 15 ++++++--------- src/slic3r/GUI/Camera.hpp | 1 + src/slic3r/GUI/GLCanvas3D.cpp | 3 +++ src/slic3r/GUI/GUI_Preview.cpp | 6 ++++++ src/slic3r/GUI/GUI_Preview.hpp | 2 ++ src/slic3r/GUI/Plater.cpp | 4 +--- src/slic3r/GUI/Preferences.cpp | 11 +++++++++-- 8 files changed, 30 insertions(+), 16 deletions(-) diff --git a/src/slic3r/GUI/AppConfig.cpp b/src/slic3r/GUI/AppConfig.cpp index edc9845a13..51bee9e756 100644 --- a/src/slic3r/GUI/AppConfig.cpp +++ b/src/slic3r/GUI/AppConfig.cpp @@ -73,8 +73,8 @@ void AppConfig::set_defaults() if (get("custom_toolbar_size").empty()) set("custom_toolbar_size", "100"); - if (get("camera_type").empty()) - set("camera_type", "1"); + if (get("use_perspective_camera").empty()) + set("use_perspective_camera", "1"); // Remove legacy window positions/sizes erase("", "main_frame_maximized"); diff --git a/src/slic3r/GUI/Camera.cpp b/src/slic3r/GUI/Camera.cpp index 1f8513ac29..6cb8ff5201 100644 --- a/src/slic3r/GUI/Camera.cpp +++ b/src/slic3r/GUI/Camera.cpp @@ -31,7 +31,7 @@ Camera::Camera() : phi(45.0f) , requires_zoom_to_bed(false) , inverted_phi(false) - , m_type(Ortho) + , m_type(Perspective) , m_target(Vec3d::Zero()) , m_theta(45.0f) , m_zoom(1.0) @@ -61,20 +61,17 @@ void Camera::set_type(EType type) if (m_type != type) { m_type = type; - - wxGetApp().app_config->set("camera_type", std::to_string(m_type)); + wxGetApp().app_config->set("use_perspective_camera", (m_type == Perspective) ? "1" : "0"); wxGetApp().app_config->save(); } } void Camera::set_type(const std::string& type) { - if (!type.empty() && (type != "1")) - { - unsigned char type_id = atoi(type.c_str()); - if (((unsigned char)Ortho < type_id) && (type_id < (unsigned char)Num_types)) - set_type((Camera::EType)type_id); - } + if (type == "1") + set_type(Perspective); + else + set_type(Ortho); } void Camera::select_next_type() diff --git a/src/slic3r/GUI/Camera.hpp b/src/slic3r/GUI/Camera.hpp index bd2541ce2f..79e87c7264 100644 --- a/src/slic3r/GUI/Camera.hpp +++ b/src/slic3r/GUI/Camera.hpp @@ -49,6 +49,7 @@ public: EType get_type() const { return m_type; } std::string get_type_as_string() const; void set_type(EType type); + // valid values for type: "0" -> ortho, "1" -> perspective void set_type(const std::string& type); void select_next_type(); diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 25319e9ce2..2f265eb928 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -3312,6 +3312,9 @@ void GLCanvas3D::handle_sidebar_focus_event(const std::string& opt_key, bool foc void GLCanvas3D::update_ui_from_settings() { + m_camera.set_type(wxGetApp().app_config->get("use_perspective_camera")); + m_dirty = true; + #if ENABLE_RETINA_GL const float orig_scaling = m_retina_helper->get_scale_factor(); diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp index 2f5e10962e..671c49eefa 100644 --- a/src/slic3r/GUI/GUI_Preview.cpp +++ b/src/slic3r/GUI/GUI_Preview.cpp @@ -313,6 +313,12 @@ Preview::~Preview() } } +void Preview::set_as_dirty() +{ + if (m_canvas != nullptr) + m_canvas->set_as_dirty(); +} + void Preview::set_number_extruders(unsigned int number_extruders) { if (m_number_extruders != number_extruders) diff --git a/src/slic3r/GUI/GUI_Preview.hpp b/src/slic3r/GUI/GUI_Preview.hpp index 93038b0e56..993e260e41 100644 --- a/src/slic3r/GUI/GUI_Preview.hpp +++ b/src/slic3r/GUI/GUI_Preview.hpp @@ -110,6 +110,8 @@ public: wxGLCanvas* get_wxglcanvas() { return m_canvas_widget; } GLCanvas3D* get_canvas3d() { return m_canvas; } + void set_as_dirty(); + void set_number_extruders(unsigned int number_extruders); void set_canvas_as_dirty(); void set_enabled(bool enabled); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index f68267cef0..9d0c979b66 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1774,7 +1774,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) set_current_panel(view3D); // updates camera type from .ini file - camera.set_type(get_config("camera_type")); + camera.set_type(get_config("use_perspective_camera")); } void Plater::priv::update(bool force_full_scene_refresh) @@ -1842,10 +1842,8 @@ void Plater::priv::update_ui_from_settings() // $self->{buttons_sizer}->Layout; // } -#if ENABLE_RETINA_GL view3D->get_canvas3d()->update_ui_from_settings(); preview->get_canvas3d()->update_ui_from_settings(); -#endif } ProgressStatusBar* Plater::priv::statusbar() diff --git a/src/slic3r/GUI/Preferences.cpp b/src/slic3r/GUI/Preferences.cpp index 52cbdbb1d9..7b31870127 100644 --- a/src/slic3r/GUI/Preferences.cpp +++ b/src/slic3r/GUI/Preferences.cpp @@ -28,7 +28,7 @@ void PreferencesDialog::build() m_icon_size_sizer->ShowItems(boost::any_cast(value)); this->layout(); } - }; + }; // TODO // $optgroup->append_single_option_line(Slic3r::GUI::OptionsGroup::Option->new( @@ -97,7 +97,7 @@ void PreferencesDialog::build() option = Option (def,"show_incompatible_presets"); m_optgroup->append_single_option_line(option); - // TODO: remove? + // TODO: remove? def.label = L("Use legacy OpenGL 1.1 rendering"); def.type = coBool; def.tooltip = L("If you have rendering issues caused by a buggy OpenGL 2.0 driver, " @@ -117,6 +117,13 @@ void PreferencesDialog::build() m_optgroup->append_single_option_line(option); #endif + def.label = L("Use perspective camera"); + def.type = coBool; + def.tooltip = L("If enabled, use perspective camera. If not enabled, use orthographic camera."); + def.set_default_value(new ConfigOptionBool{ app_config->get("use_perspective_camera") == "1" }); + option = Option(def, "use_perspective_camera"); + m_optgroup->append_single_option_line(option); + def.label = L("Use custom size for toolbar icons"); def.type = coBool; def.tooltip = L("If enabled, you can change size of toolbar icons manually."); From d689195bda8fe9d0618b97685858dbc2b263bf24 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Tue, 25 Jun 2019 08:56:53 +0200 Subject: [PATCH 03/12] Fix of the previous commit on color change fix. --- src/slic3r/GUI/GLCanvas3D.cpp | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 25319e9ce2..1aa542d0cf 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -4646,22 +4646,24 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c } } // Ensure that no volume grows over the limits. If the volume is too large, allocate a new one. - for (GLVolume *&vol : vols) - if (vol->indexed_vertex_array.vertices_and_normals_interleaved.size() / 6 > ctxt.alloc_size_max()) { - // Store the vertex arrays and restart their containers, - vol = new_volume(vol->color); - GLVolume &vol_new = *vol; - // Assign the large pre-allocated buffers to the new GLVolume. - vol_new.indexed_vertex_array = std::move(vol->indexed_vertex_array); - // Copy the content back to the old GLVolume. - vol->indexed_vertex_array = vol_new.indexed_vertex_array; - // Finalize a bounding box of the old GLVolume. - vol->bounding_box = vol->indexed_vertex_array.bounding_box(); - // Clear the buffers, but keep them pre-allocated. - vol_new.indexed_vertex_array.clear(); - // Just make sure that clear did not clear the reserved memory. - vol_new.indexed_vertex_array.reserve(ctxt.alloc_size_reserve()); - } + for (size_t i = 0; i < vols.size(); ++i) { + GLVolume &vol = *vols[i]; + if (vol.indexed_vertex_array.vertices_and_normals_interleaved.size() / 6 > ctxt.alloc_size_max()) { + // Store the vertex arrays and restart their containers, + vols[i] = new_volume(vol.color); + GLVolume &vol_new = *vols[i]; + // Assign the large pre-allocated buffers to the new GLVolume. + vol_new.indexed_vertex_array = std::move(vol.indexed_vertex_array); + // Copy the content back to the old GLVolume. + vol.indexed_vertex_array = vol_new.indexed_vertex_array; + // Finalize a bounding box of the old GLVolume. + vol.bounding_box = vol.indexed_vertex_array.bounding_box(); + // Clear the buffers, but keep them pre-allocated. + vol_new.indexed_vertex_array.clear(); + // Just make sure that clear did not clear the reserved memory. + vol_new.indexed_vertex_array.reserve(ctxt.alloc_size_reserve()); + } + } } for (GLVolume *vol : vols) { vol->bounding_box = vol->indexed_vertex_array.bounding_box(); From 3d755e1bbe642becb73c9f64910616787eade373 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Tue, 25 Jun 2019 09:20:58 +0200 Subject: [PATCH 04/12] Removed 'Use legacy OpenGL 1.1 rendering' option --- src/slic3r/GUI/AppConfig.cpp | 7 +++---- src/slic3r/GUI/GLCanvas3D.cpp | 13 +++---------- src/slic3r/GUI/GLCanvas3D.hpp | 4 +--- src/slic3r/GUI/GLCanvas3DManager.cpp | 10 +++------- src/slic3r/GUI/GLCanvas3DManager.hpp | 1 - src/slic3r/GUI/Preferences.cpp | 13 +------------ 6 files changed, 11 insertions(+), 37 deletions(-) diff --git a/src/slic3r/GUI/AppConfig.cpp b/src/slic3r/GUI/AppConfig.cpp index 51bee9e756..3b62100582 100644 --- a/src/slic3r/GUI/AppConfig.cpp +++ b/src/slic3r/GUI/AppConfig.cpp @@ -54,10 +54,9 @@ void AppConfig::set_defaults() if (get("preset_update").empty()) set("preset_update", "1"); - // Use OpenGL 1.1 even if OpenGL 2.0 is available. This is mainly to support some buggy Intel HD Graphics drivers. - // github.com/prusa3d/PrusaSlicer/issues/233 - if (get("use_legacy_opengl").empty()) - set("use_legacy_opengl", "0"); + // remove old 'use_legacy_opengl' parameter from this config, if present + if (!get("use_legacy_opengl").empty()) + erase("", "use_legacy_opengl"); #if __APPLE__ if (get("use_retina_opengl").empty()) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index cf8a49ea22..c828e0ec66 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -198,8 +198,7 @@ void GLCanvas3D::Shader::_reset() #endif // !ENABLE_TEXTURES_FROM_SVG GLCanvas3D::LayersEditing::LayersEditing() - : m_use_legacy_opengl(false) - , m_enabled(false) + : m_enabled(false) , m_z_texture_id(0) , m_model_object(nullptr) , m_object_max_z(0.f) @@ -274,12 +273,7 @@ void GLCanvas3D::LayersEditing::select_object(const Model &model, int object_id) bool GLCanvas3D::LayersEditing::is_allowed() const { - 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) -{ - m_use_legacy_opengl = use_legacy_opengl; + return m_shader.is_initialized() && m_shader.get_shader()->shader_program_id > 0 && m_z_texture_id > 0; } bool GLCanvas3D::LayersEditing::is_enabled() const @@ -1253,7 +1247,7 @@ void GLCanvas3D::post_event(wxEvent &&event) wxPostEvent(m_canvas, event); } -bool GLCanvas3D::init(bool useVBOs, bool use_legacy_opengl) +bool GLCanvas3D::init(bool useVBOs) { if (m_initialized) return true; @@ -1311,7 +1305,6 @@ bool GLCanvas3D::init(bool useVBOs, bool use_legacy_opengl) return false; m_use_VBOs = useVBOs; - m_layers_editing.set_use_legacy_opengl(use_legacy_opengl); // on linux the gl context is not valid until the canvas is not shown on screen // we defer the geometry finalization of volumes until the first call to render() diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index d39a910b3b..5a42879039 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -197,7 +197,6 @@ class GLCanvas3D static const float THICKNESS_BAR_WIDTH; static const float THICKNESS_RESET_BUTTON_HEIGHT; - bool m_use_legacy_opengl; bool m_enabled; Shader m_shader; unsigned int m_z_texture_id; @@ -250,7 +249,6 @@ class GLCanvas3D void select_object(const Model &model, int object_id); bool is_allowed() const; - void set_use_legacy_opengl(bool use_legacy_opengl); bool is_enabled() const; void set_enabled(bool enabled); @@ -492,7 +490,7 @@ public: wxGLCanvas* get_wxglcanvas() { return m_canvas; } const wxGLCanvas* get_wxglcanvas() const { return m_canvas; } - bool init(bool useVBOs, bool use_legacy_opengl); + bool init(bool useVBOs); void post_event(wxEvent &&event); void set_as_dirty(); diff --git a/src/slic3r/GUI/GLCanvas3DManager.cpp b/src/slic3r/GUI/GLCanvas3DManager.cpp index 4f64b4e877..a1430ef22b 100644 --- a/src/slic3r/GUI/GLCanvas3DManager.cpp +++ b/src/slic3r/GUI/GLCanvas3DManager.cpp @@ -192,7 +192,6 @@ GLCanvas3DManager::GLInfo GLCanvas3DManager::s_gl_info; GLCanvas3DManager::GLCanvas3DManager() : m_context(nullptr) , m_gl_initialized(false) - , m_use_legacy_opengl(false) , m_use_VBOs(false) { } @@ -268,8 +267,7 @@ void GLCanvas3DManager::init_gl() { glewInit(); const AppConfig* config = GUI::get_app_config(); - m_use_legacy_opengl = (config == nullptr) || (config->get("use_legacy_opengl") == "1"); - m_use_VBOs = !m_use_legacy_opengl && s_gl_info.is_version_greater_or_equal_to(2, 0); + m_use_VBOs = s_gl_info.is_version_greater_or_equal_to(2, 0); m_gl_initialized = true; if (GLEW_EXT_texture_compression_s3tc) s_compressed_textures_supported = true; @@ -325,16 +323,14 @@ bool GLCanvas3DManager::init(GLCanvas3D& canvas) if (!m_gl_initialized) init_gl(); - return canvas.init(m_use_VBOs, m_use_legacy_opengl); + return canvas.init(m_use_VBOs); } void GLCanvas3DManager::detect_multisample(int* attribList) { int wxVersion = wxMAJOR_VERSION * 10000 + wxMINOR_VERSION * 100 + wxRELEASE_NUMBER; const AppConfig* app_config = GUI::get_app_config(); - bool enable_multisample = app_config != nullptr - && app_config->get("use_legacy_opengl") != "1" - && wxVersion >= 30003; + bool enable_multisample = wxVersion >= 30003; s_multisample = (enable_multisample && wxGLCanvas::IsDisplaySupported(attribList)) ? MS_Enabled : MS_Disabled; // Alternative method: it was working on previous version of wxWidgets but not with the latest, at least on Windows diff --git a/src/slic3r/GUI/GLCanvas3DManager.hpp b/src/slic3r/GUI/GLCanvas3DManager.hpp index 26c2558d07..7a600dcbdb 100644 --- a/src/slic3r/GUI/GLCanvas3DManager.hpp +++ b/src/slic3r/GUI/GLCanvas3DManager.hpp @@ -75,7 +75,6 @@ private: wxGLContext* m_context; static GLInfo s_gl_info; bool m_gl_initialized; - bool m_use_legacy_opengl; bool m_use_VBOs; static EMultisampleState s_multisample; static bool s_compressed_textures_supported; diff --git a/src/slic3r/GUI/Preferences.cpp b/src/slic3r/GUI/Preferences.cpp index 7b31870127..827d1f4e05 100644 --- a/src/slic3r/GUI/Preferences.cpp +++ b/src/slic3r/GUI/Preferences.cpp @@ -97,16 +97,6 @@ void PreferencesDialog::build() option = Option (def,"show_incompatible_presets"); m_optgroup->append_single_option_line(option); - // TODO: remove? - def.label = L("Use legacy OpenGL 1.1 rendering"); - def.type = coBool; - def.tooltip = L("If you have rendering issues caused by a buggy OpenGL 2.0 driver, " - "you may try to check this checkbox. This will disable the layer height " - "editing and anti aliasing, so it is likely better to upgrade your graphics driver."); - def.set_default_value(new ConfigOptionBool{ app_config->get("use_legacy_opengl") == "1" }); - option = Option (def,"use_legacy_opengl"); - m_optgroup->append_single_option_line(option); - #if __APPLE__ def.label = L("Use Retina resolution for the 3D scene"); def.type = coBool; @@ -150,8 +140,7 @@ void PreferencesDialog::build() void PreferencesDialog::accept() { - if (m_values.find("no_defaults") != m_values.end() || - m_values.find("use_legacy_opengl") != m_values.end()) { + if (m_values.find("no_defaults") != m_values.end()) { warning_catcher(this, wxString::Format(_(L("You need to restart %s to make the changes effective.")), SLIC3R_APP_NAME)); } From 2f806dedc762c1ee810be44820aaff8de8cb5d07 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Tue, 25 Jun 2019 09:51:43 +0200 Subject: [PATCH 05/12] Fixed rendering of selection rectangle with perspective camera --- src/slic3r/GUI/GLSelectionRectangle.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/GLSelectionRectangle.cpp b/src/slic3r/GUI/GLSelectionRectangle.cpp index 327cb1fde8..684563bff3 100644 --- a/src/slic3r/GUI/GLSelectionRectangle.cpp +++ b/src/slic3r/GUI/GLSelectionRectangle.cpp @@ -68,7 +68,8 @@ namespace GUI { if (!is_dragging()) return; - float zoom = (float)canvas.get_camera().get_zoom(); + const Camera& camera = canvas.get_camera(); + float zoom = (float)camera.get_zoom(); float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; Size cnv_size = canvas.get_canvas_size(); @@ -96,6 +97,11 @@ namespace GUI { glsafe(::glPushMatrix()); glsafe(::glLoadIdentity()); + // ensure that the rectangle is renderered inside the frustrum + glsafe(::glTranslated(0.0, 0.0, -(camera.get_near_z() + 0.5))); + // ensure that the overlay fits the frustrum near z plane + double gui_scale = camera.get_gui_scale(); + glsafe(::glScaled(gui_scale, gui_scale, 1.0)); glsafe(::glPushAttrib(GL_ENABLE_BIT)); glsafe(::glLineStipple(4, 0xAAAA)); From ac82cbe0cc6d9123611e24a5aabbad1a1bb4c9de Mon Sep 17 00:00:00 2001 From: YuSanka Date: Wed, 26 Jun 2019 09:48:52 +0200 Subject: [PATCH 06/12] Fix of #2548 --- src/slic3r/GUI/Plater.cpp | 38 +++++++++++++++++++++++++++++++++++--- src/slic3r/GUI/Plater.hpp | 14 +++++++++++++- src/slic3r/GUI/Tab.cpp | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 82 insertions(+), 4 deletions(-) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index f68267cef0..ceedece607 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1260,6 +1260,7 @@ struct Plater::priv Preview *preview; BackgroundSlicingProcess background_process; + bool suppressed_backround_processing_update { false }; // A class to handle UI jobs like arranging and optimizing rotation. // These are not instant jobs, the user has to be informed about their @@ -1694,7 +1695,11 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) panels.push_back(preview); this->background_process_timer.SetOwner(this->q, 0); - this->q->Bind(wxEVT_TIMER, [this](wxTimerEvent &evt) { this->update_restart_background_process(false, false); }); + this->q->Bind(wxEVT_TIMER, [this](wxTimerEvent &evt) + { + if (!this->suppressed_backround_processing_update) + this->update_restart_background_process(false, false); + }); update(); @@ -4176,9 +4181,25 @@ void Plater::changed_objects(const std::vector& object_idxs) this->p->schedule_background_process(); } -void Plater::schedule_background_process() +void Plater::schedule_background_process(bool schedule/* = true*/) { - this->p->schedule_background_process(); + if (schedule) + this->p->schedule_background_process(); + + this->p->suppressed_backround_processing_update = false; +} + +bool Plater::is_background_process_running() const +{ + return this->p->background_process_timer.IsRunning(); +} + +void Plater::suppress_background_process(const bool stop_background_process) +{ + if (stop_background_process) + this->p->background_process_timer.Stop(); + + this->p->suppressed_backround_processing_update = true; } void Plater::fix_through_netfabb(const int obj_idx, const int vol_idx/* = -1*/) { p->fix_through_netfabb(obj_idx, vol_idx); } @@ -4254,4 +4275,15 @@ bool Plater::can_copy_to_clipboard() const return true; } +SuppressBackgroundProcessingUpdate::SuppressBackgroundProcessingUpdate() : + m_was_running(wxGetApp().plater()->is_background_process_running()) +{ + wxGetApp().plater()->suppress_background_process(m_was_running); +} + +SuppressBackgroundProcessingUpdate::~SuppressBackgroundProcessingUpdate() +{ + wxGetApp().plater()->schedule_background_process(m_was_running); +} + }} // namespace Slic3r::GUI diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index 2851af6544..5b1347891e 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -175,7 +175,9 @@ public: void reslice_SLA_supports(const ModelObject &object); void changed_object(int obj_idx); void changed_objects(const std::vector& object_idxs); - void schedule_background_process(); + void schedule_background_process(bool schedule = true); + bool is_background_process_running() const; + void suppress_background_process(const bool stop_background_process) ; void fix_through_netfabb(const int obj_idx, const int vol_idx = -1); void send_gcode(); @@ -219,8 +221,18 @@ public: private: struct priv; std::unique_ptr p; + + friend class SuppressBackgroundProcessingUpdate; }; +class SuppressBackgroundProcessingUpdate +{ +public: + SuppressBackgroundProcessingUpdate(); + ~SuppressBackgroundProcessingUpdate(); +private: + bool m_was_running; +}; }} diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 22aecf38d8..6e8b8a471e 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -2314,6 +2314,40 @@ void TabPrinter::build_unregular_pages() auto optgroup = page->new_optgroup(_(L("Size"))); optgroup->append_single_option_line("nozzle_diameter", extruder_idx); + + optgroup->m_on_change = [this, extruder_idx](const t_config_option_key& opt_key, boost::any value) + { + if (m_extruders_count > 1 && opt_key.find_first_of("nozzle_diameter") != std::string::npos) + { + SuppressBackgroundProcessingUpdate sbpu; + const double new_nd = boost::any_cast(value); + std::vector nozzle_diameters = static_cast(m_config->option("nozzle_diameter"))->values; + + // if value was changed + if (fabs(nozzle_diameters[extruder_idx == 0 ? 1 : 0] - new_nd) > EPSILON) + { + const wxString msg_text = _(L("Do you want to change the diameter for all extruders?")); + auto dialog = new wxMessageDialog(parent(), msg_text, _(L("Nozzle diameter")), wxICON_WARNING | wxYES_NO); + + DynamicPrintConfig new_conf = *m_config; + if (dialog->ShowModal() == wxID_YES) { + for (size_t i = 0; i < nozzle_diameters.size(); i++) { + if (i==extruder_idx) + continue; + nozzle_diameters[i] = new_nd; + } + } + else + nozzle_diameters[extruder_idx] = nozzle_diameters[extruder_idx == 0 ? 1 : 0]; + + new_conf.set_key_value("nozzle_diameter", new ConfigOptionFloats(nozzle_diameters)); + load_config(new_conf); + } + } + + update_dirty(); + update(); + }; optgroup = page->new_optgroup(_(L("Layer height limits"))); optgroup->append_single_option_line("min_layer_height", extruder_idx); From 14b32c4f166f094bc10fae06c88c5234cd94b292 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Wed, 26 Jun 2019 10:33:42 +0200 Subject: [PATCH 07/12] Make an order in using scale and unscale, remove some warnings. --- src/libnest2d/tests/test.cpp | 552 +++++++++++++-------------- src/libslic3r/MTUtils.hpp | 91 +++++ src/libslic3r/MinAreaBoundingBox.cpp | 68 ++-- src/libslic3r/ModelArrange.cpp | 2 +- src/libslic3r/SLA/SLABasePool.cpp | 15 +- src/libslic3r/SLAPrint.cpp | 34 +- src/libslic3r/libslic3r.h | 14 - 7 files changed, 408 insertions(+), 368 deletions(-) diff --git a/src/libnest2d/tests/test.cpp b/src/libnest2d/tests/test.cpp index 5741e87b4f..363a3930ce 100644 --- a/src/libnest2d/tests/test.cpp +++ b/src/libnest2d/tests/test.cpp @@ -10,10 +10,6 @@ #include "boost/multiprecision/integer.hpp" #include "boost/rational.hpp" -//#include "../tools/Int128.hpp" - -//#include "gte/Mathematics/GteMinimumAreaBox2.h" - //#include "../tools/libnfpglue.hpp" //#include "../tools/nfp_svgnest_glue.hpp" @@ -42,151 +38,151 @@ struct NfpImpl std::vector& prusaParts() { static std::vector ret; - + if(ret.empty()) { ret.reserve(PRINTER_PART_POLYGONS.size()); for(auto& inp : PRINTER_PART_POLYGONS) ret.emplace_back(inp); } - + return ret; } TEST(BasicFunctionality, Angles) { - + using namespace libnest2d; - + Degrees deg(180); Radians rad(deg); Degrees deg2(rad); - + ASSERT_DOUBLE_EQ(rad, Pi); ASSERT_DOUBLE_EQ(deg, 180); ASSERT_DOUBLE_EQ(deg2, 180); ASSERT_DOUBLE_EQ(rad, Radians(deg)); ASSERT_DOUBLE_EQ( Degrees(rad), deg); - + ASSERT_TRUE(rad == deg); - + Segment seg = {{0, 0}, {12, -10}}; - + ASSERT_TRUE(Degrees(seg.angleToXaxis()) > 270 && Degrees(seg.angleToXaxis()) < 360); - + seg = {{0, 0}, {12, 10}}; - + ASSERT_TRUE(Degrees(seg.angleToXaxis()) > 0 && Degrees(seg.angleToXaxis()) < 90); - + seg = {{0, 0}, {-12, 10}}; - + ASSERT_TRUE(Degrees(seg.angleToXaxis()) > 90 && Degrees(seg.angleToXaxis()) < 180); - + seg = {{0, 0}, {-12, -10}}; - + ASSERT_TRUE(Degrees(seg.angleToXaxis()) > 180 && Degrees(seg.angleToXaxis()) < 270); - + seg = {{0, 0}, {1, 0}}; - + ASSERT_DOUBLE_EQ(Degrees(seg.angleToXaxis()), 0); - + seg = {{0, 0}, {0, 1}}; - + ASSERT_DOUBLE_EQ(Degrees(seg.angleToXaxis()), 90); - - + + seg = {{0, 0}, {-1, 0}}; - + ASSERT_DOUBLE_EQ(Degrees(seg.angleToXaxis()), 180); - - + + seg = {{0, 0}, {0, -1}}; - + ASSERT_DOUBLE_EQ(Degrees(seg.angleToXaxis()), 270); - + } // Simple test, does not use gmock TEST(BasicFunctionality, creationAndDestruction) { using namespace libnest2d; - + Item sh = { {0, 0}, {1, 0}, {1, 1}, {0, 1} }; - + ASSERT_EQ(sh.vertexCount(), 4u); - + Item sh2 ({ {0, 0}, {1, 0}, {1, 1}, {0, 1} }); - + ASSERT_EQ(sh2.vertexCount(), 4u); - + // copy Item sh3 = sh2; - + ASSERT_EQ(sh3.vertexCount(), 4u); - + sh2 = {}; - + ASSERT_EQ(sh2.vertexCount(), 0u); ASSERT_EQ(sh3.vertexCount(), 4u); - + } TEST(GeometryAlgorithms, boundingCircle) { using namespace libnest2d; using placers::boundingCircle; - + PolygonImpl p = {{{0, 10}, {10, 0}, {0, -10}, {0, 10}}, {}}; Circle c = boundingCircle(p); - + ASSERT_EQ(c.center().X, 0); ASSERT_EQ(c.center().Y, 0); ASSERT_DOUBLE_EQ(c.radius(), 10); - + shapelike::translate(p, PointImpl{10, 10}); c = boundingCircle(p); - + ASSERT_EQ(c.center().X, 10); ASSERT_EQ(c.center().Y, 10); ASSERT_DOUBLE_EQ(c.radius(), 10); - + auto parts = prusaParts(); - + int i = 0; for(auto& part : parts) { c = boundingCircle(part.transformedShape()); if(std::isnan(c.radius())) std::cout << "fail: radius is nan" << std::endl; - + else for(auto v : shapelike::contour(part.transformedShape()) ) { - auto d = pointlike::distance(v, c.center()); - if(d > c.radius() ) { - auto e = std::abs( 1.0 - d/c.radius()); - ASSERT_LE(e, 1e-3); + auto d = pointlike::distance(v, c.center()); + if(d > c.radius() ) { + auto e = std::abs( 1.0 - d/c.radius()); + ASSERT_LE(e, 1e-3); + } } - } i++; } - + } TEST(GeometryAlgorithms, Distance) { using namespace libnest2d; - + Point p1 = {0, 0}; - + Point p2 = {10, 0}; Point p3 = {10, 10}; - + ASSERT_DOUBLE_EQ(pointlike::distance(p1, p2), 10); ASSERT_DOUBLE_EQ(pointlike::distance(p1, p3), sqrt(200)); - + Segment seg(p1, p3); - -// ASSERT_DOUBLE_EQ(pointlike::distance(p2, seg), 7.0710678118654755); - + + // ASSERT_DOUBLE_EQ(pointlike::distance(p2, seg), 7.0710678118654755); + auto result = pointlike::horizontalDistance(p2, seg); - + auto check = [](TCompute val, TCompute expected) { if(std::is_floating_point>::value) ASSERT_DOUBLE_EQ(static_cast(val), @@ -194,44 +190,44 @@ TEST(GeometryAlgorithms, Distance) { else ASSERT_EQ(val, expected); }; - + ASSERT_TRUE(result.second); check(result.first, 10); - + result = pointlike::verticalDistance(p2, seg); ASSERT_TRUE(result.second); check(result.first, -10); - + result = pointlike::verticalDistance(Point{10, 20}, seg); ASSERT_TRUE(result.second); check(result.first, 10); - - + + Point p4 = {80, 0}; Segment seg2 = { {0, 0}, {0, 40} }; - + result = pointlike::horizontalDistance(p4, seg2); - + ASSERT_TRUE(result.second); check(result.first, 80); - + result = pointlike::verticalDistance(p4, seg2); // Point should not be related to the segment ASSERT_FALSE(result.second); - + } TEST(GeometryAlgorithms, Area) { using namespace libnest2d; - + Rectangle rect(10, 10); - + ASSERT_EQ(rect.area(), 100); - + Rectangle rect2 = {100, 100}; - + ASSERT_EQ(rect2.area(), 10000); - + Item item = { {61, 97}, {70, 151}, @@ -242,33 +238,33 @@ TEST(GeometryAlgorithms, Area) { {61, 77}, {61, 97} }; - + ASSERT_TRUE(shapelike::area(item.transformedShape()) > 0 ); } TEST(GeometryAlgorithms, IsPointInsidePolygon) { using namespace libnest2d; - + Rectangle rect(10, 10); - + Point p = {1, 1}; - + ASSERT_TRUE(rect.isInside(p)); - + p = {11, 11}; - + ASSERT_FALSE(rect.isInside(p)); - - + + p = {11, 12}; - + ASSERT_FALSE(rect.isInside(p)); - - + + p = {3, 3}; - + ASSERT_TRUE(rect.isInside(p)); - + } //TEST(GeometryAlgorithms, Intersections) { @@ -294,21 +290,21 @@ TEST(GeometryAlgorithms, LeftAndDownPolygon) { using namespace libnest2d; using namespace libnest2d; - + Box bin(100, 100); BottomLeftPlacer placer(bin); - + Item item = {{70, 75}, {88, 60}, {65, 50}, {60, 30}, {80, 20}, {42, 20}, {35, 35}, {35, 55}, {40, 75}, {70, 75}}; - + Item leftControl = { {40, 75}, - {35, 55}, - {35, 35}, - {42, 20}, - {0, 20}, - {0, 75}, - {40, 75}}; - + {35, 55}, + {35, 35}, + {42, 20}, + {0, 20}, + {0, 75}, + {40, 75}}; + Item downControl = {{88, 60}, {88, 0}, {35, 0}, @@ -318,22 +314,22 @@ TEST(GeometryAlgorithms, LeftAndDownPolygon) {60, 30}, {65, 50}, {88, 60}}; - + Item leftp(placer.leftPoly(item)); - + ASSERT_TRUE(shapelike::isValid(leftp.rawShape()).first); ASSERT_EQ(leftp.vertexCount(), leftControl.vertexCount()); - + for(unsigned long i = 0; i < leftControl.vertexCount(); i++) { ASSERT_EQ(getX(leftp.vertex(i)), getX(leftControl.vertex(i))); ASSERT_EQ(getY(leftp.vertex(i)), getY(leftControl.vertex(i))); } - + Item downp(placer.downPoly(item)); - + ASSERT_TRUE(shapelike::isValid(downp.rawShape()).first); ASSERT_EQ(downp.vertexCount(), downControl.vertexCount()); - + for(unsigned long i = 0; i < downControl.vertexCount(); i++) { ASSERT_EQ(getX(downp.vertex(i)), getX(downControl.vertex(i))); ASSERT_EQ(getY(downp.vertex(i)), getY(downControl.vertex(i))); @@ -344,7 +340,7 @@ TEST(GeometryAlgorithms, LeftAndDownPolygon) TEST(GeometryAlgorithms, ArrangeRectanglesTight) { using namespace libnest2d; - + std::vector rects = { {80, 80}, {60, 90}, @@ -366,17 +362,17 @@ TEST(GeometryAlgorithms, ArrangeRectanglesTight) {5, 5}, {5, 5}, {20, 20} }; - - + + Nester arrange(Box(210, 250)); - + auto groups = arrange(rects.begin(), rects.end()); - + ASSERT_EQ(groups.size(), 1u); ASSERT_EQ(groups[0].size(), rects.size()); - + // check for no intersections, no containment: - + for(auto result : groups) { bool valid = true; for(Item& r1 : result) { @@ -389,14 +385,14 @@ TEST(GeometryAlgorithms, ArrangeRectanglesTight) } } } - + } TEST(GeometryAlgorithms, ArrangeRectanglesLoose) { using namespace libnest2d; - -// std::vector rects = { {40, 40}, {10, 10}, {20, 20} }; + + // std::vector rects = { {40, 40}, {10, 10}, {20, 20} }; std::vector rects = { {80, 80}, {60, 90}, @@ -418,17 +414,17 @@ TEST(GeometryAlgorithms, ArrangeRectanglesLoose) {5, 5}, {5, 5}, {20, 20} }; - + Coord min_obj_distance = 5; - + Nester arrange(Box(210, 250), - min_obj_distance); - + min_obj_distance); + auto groups = arrange(rects.begin(), rects.end()); - + ASSERT_EQ(groups.size(), 1u); ASSERT_EQ(groups[0].size(), rects.size()); - + // check for no intersections, no containment: auto result = groups[0]; bool valid = true; @@ -441,7 +437,7 @@ TEST(GeometryAlgorithms, ArrangeRectanglesLoose) } } } - + } namespace { @@ -449,68 +445,68 @@ using namespace libnest2d; template void exportSVG(std::vector>& result, const Bin& bin, int idx = 0) { - - + + std::string loc = "out"; - + static std::string svg_header = -R"raw( + R"raw( )raw"; - + int i = idx; auto r = result; -// for(auto r : result) { - std::fstream out(loc + std::to_string(i) + ".svg", std::fstream::out); - if(out.is_open()) { - out << svg_header; - Item rbin( Rectangle(bin.width(), bin.height()) ); - for(unsigned i = 0; i < rbin.vertexCount(); i++) { - auto v = rbin.vertex(i); - setY(v, -getY(v)/SCALE + 500 ); - setX(v, getX(v)/SCALE); - rbin.setVertex(i, v); - } - out << shapelike::serialize(rbin.rawShape()) << std::endl; - for(Item& sh : r) { - Item tsh(sh.transformedShape()); - for(unsigned i = 0; i < tsh.vertexCount(); i++) { - auto v = tsh.vertex(i); - setY(v, -getY(v)/SCALE + 500); - setX(v, getX(v)/SCALE); - tsh.setVertex(i, v); - } - out << shapelike::serialize(tsh.rawShape()) << std::endl; - } - out << "\n" << std::endl; + // for(auto r : result) { + std::fstream out(loc + std::to_string(i) + ".svg", std::fstream::out); + if(out.is_open()) { + out << svg_header; + Item rbin( Rectangle(bin.width(), bin.height()) ); + for(unsigned i = 0; i < rbin.vertexCount(); i++) { + auto v = rbin.vertex(i); + setY(v, -getY(v)/SCALE + 500 ); + setX(v, getX(v)/SCALE); + rbin.setVertex(i, v); } - out.close(); - -// i++; -// } + out << shapelike::serialize(rbin.rawShape()) << std::endl; + for(Item& sh : r) { + Item tsh(sh.transformedShape()); + for(unsigned i = 0; i < tsh.vertexCount(); i++) { + auto v = tsh.vertex(i); + setY(v, -getY(v)/SCALE + 500); + setX(v, getX(v)/SCALE); + tsh.setVertex(i, v); + } + out << shapelike::serialize(tsh.rawShape()) << std::endl; + } + out << "\n" << std::endl; + } + out.close(); + + // i++; + // } } } TEST(GeometryAlgorithms, BottomLeftStressTest) { using namespace libnest2d; - + const Coord SCALE = 1000000; auto& input = prusaParts(); - + Box bin(210*SCALE, 250*SCALE); BottomLeftPlacer placer(bin); - + auto it = input.begin(); auto next = it; int i = 0; while(it != input.end() && ++next != input.end()) { placer.pack(*it); placer.pack(*next); - + auto result = placer.getItems(); bool valid = true; - + if(result.size() == 2) { Item& r1 = result[0]; Item& r2 = result[1]; @@ -525,7 +521,7 @@ TEST(GeometryAlgorithms, BottomLeftStressTest) { std::cout << "something went terribly wrong!" << std::endl; FAIL(); } - + placer.clearItems(); it++; i++; @@ -534,9 +530,9 @@ TEST(GeometryAlgorithms, BottomLeftStressTest) { TEST(GeometryAlgorithms, convexHull) { using namespace libnest2d; - + ClipperLib::Path poly = PRINTER_PART_POLYGONS[0]; - + auto chull = sl::convexHull(poly); ASSERT_EQ(chull.size(), poly.size()); @@ -545,7 +541,7 @@ TEST(GeometryAlgorithms, convexHull) { TEST(GeometryAlgorithms, NestTest) { std::vector input = prusaParts(); - + PackGroup result = libnest2d::nest(input, Box(250000000, 210000000), [](unsigned cnt) { @@ -553,16 +549,17 @@ TEST(GeometryAlgorithms, NestTest) { << "parts left: " << cnt << std::endl; }); - + ASSERT_LE(result.size(), 2); - - int partsum = std::accumulate(result.begin(), - result.end(), - 0, - [](int s, - const decltype(result)::value_type &bin) { - return s += bin.size(); - }); + + size_t partsum = std::accumulate(result.begin(), + result.end(), + size_t(0), + [](int s, + const decltype( + result)::value_type &bin) { + return s += bin.size(); + }); ASSERT_EQ(input.size(), partsum); } @@ -647,7 +644,7 @@ std::vector nfp_testdata = { {118, 101}, {117, 103}, {117, 107} - }, + }, { {102, 116}, {111, 126}, @@ -658,7 +655,7 @@ std::vector nfp_testdata = { {147, 84}, {102, 84}, {102, 116}, - } + } }, { { @@ -674,7 +671,7 @@ std::vector nfp_testdata = { {108, 70}, {99, 102}, {99, 122}, - }, + }, { {107, 124}, {128, 125}, @@ -691,7 +688,7 @@ std::vector nfp_testdata = { {108, 85}, {107, 86}, {107, 124}, - } + } }, { { @@ -706,7 +703,7 @@ std::vector nfp_testdata = { {132, 57}, {91, 98}, {91, 100}, - }, + }, { {101, 90}, {103, 98}, @@ -724,74 +721,74 @@ std::vector nfp_testdata = { {102, 87}, {101, 89}, {101, 90}, - } + } } }; -std::vector nfp_concave_testdata = { - { // ItemPair - { - { - {533726, 142141}, - {532359, 143386}, - {530141, 142155}, - {528649, 160091}, - {533659, 157607}, - {538669, 160091}, - {537178, 142155}, - {534959, 143386}, - {533726, 142141}, - } - }, - { - { - {118305, 11603}, - {118311, 26616}, - {113311, 26611}, - {109311, 29604}, - {109300, 44608}, - {109311, 49631}, - {113300, 52636}, - {118311, 52636}, - {118308, 103636}, - {223830, 103636}, - {236845, 90642}, - {236832, 11630}, - {232825, 11616}, - {210149, 11616}, - {211308, 13625}, - {209315, 17080}, - {205326, 17080}, - {203334, 13629}, - {204493, 11616}, - {118305, 11603}, - } - }, - } + std::vector nfp_concave_testdata = { + { // ItemPair + { + { + {533726, 142141}, + {532359, 143386}, + {530141, 142155}, + {528649, 160091}, + {533659, 157607}, + {538669, 160091}, + {537178, 142155}, + {534959, 143386}, + {533726, 142141}, + } + }, + { + { + {118305, 11603}, + {118311, 26616}, + {113311, 26611}, + {109311, 29604}, + {109300, 44608}, + {109311, 49631}, + {113300, 52636}, + {118311, 52636}, + {118308, 103636}, + {223830, 103636}, + {236845, 90642}, + {236832, 11630}, + {232825, 11616}, + {210149, 11616}, + {211308, 13625}, + {209315, 17080}, + {205326, 17080}, + {203334, 13629}, + {204493, 11616}, + {118305, 11603}, + } + }, + } }; template void testNfp(const std::vector& testdata) { using namespace libnest2d; - + Box bin(210*SCALE, 250*SCALE); - + int testcase = 0; - + auto& exportfun = exportSVG; - + auto onetest = [&](Item& orbiter, Item& stationary, unsigned /*testidx*/){ testcase++; - + orbiter.translate({210*SCALE, 0}); - + auto&& nfp = nfp::noFitPolygon(stationary.rawShape(), orbiter.transformedShape()); - + placers::correctNfpPosition(nfp, stationary, orbiter); - + auto valid = shapelike::isValid(nfp.first); - + /*Item infp(nfp.first); if(!valid.first) { std::cout << "test instance: " << testidx << " " @@ -799,46 +796,46 @@ void testNfp(const std::vector& testdata) { std::vector> inp = {std::ref(infp)}; exportfun(inp, bin, testidx); }*/ - + ASSERT_TRUE(valid.first); - + Item infp(nfp.first); - + int i = 0; auto rorbiter = orbiter.transformedShape(); auto vo = nfp::referenceVertex(rorbiter); - + ASSERT_TRUE(stationary.isInside(infp)); - + for(auto v : infp) { auto dx = getX(v) - getX(vo); auto dy = getY(v) - getY(vo); - + Item tmp = orbiter; - + tmp.translate({dx, dy}); - + bool touching = Item::touches(tmp, stationary); - + if(!touching || !valid.first) { std::vector> inp = { std::ref(stationary), std::ref(tmp), std::ref(infp) }; - + exportfun(inp, bin, testcase*i++); } - + ASSERT_TRUE(touching); } }; - + unsigned tidx = 0; for(auto& td : testdata) { auto orbiter = td.orbiter; auto stationary = td.stationary; onetest(orbiter, stationary, tidx++); } - + tidx = 0; for(auto& td : testdata) { auto orbiter = td.stationary; @@ -858,19 +855,19 @@ TEST(GeometryAlgorithms, nfpConvexConvex) { TEST(GeometryAlgorithms, pointOnPolygonContour) { using namespace libnest2d; - + Rectangle input(10, 10); - + placers::EdgeCache ecache(input); - + auto first = *input.begin(); ASSERT_TRUE(getX(first) == getX(ecache.coords(0))); ASSERT_TRUE(getY(first) == getY(ecache.coords(0))); - + auto last = *std::prev(input.end()); ASSERT_TRUE(getX(last) == getX(ecache.coords(1.0))); ASSERT_TRUE(getY(last) == getY(ecache.coords(1.0))); - + for(int i = 0; i <= 100; i++) { auto v = ecache.coords(i*(0.01)); ASSERT_TRUE(shapelike::touches(v, input.transformedShape())); @@ -879,24 +876,24 @@ TEST(GeometryAlgorithms, pointOnPolygonContour) { TEST(GeometryAlgorithms, mergePileWithPolygon) { using namespace libnest2d; - + Rectangle rect1(10, 15); Rectangle rect2(15, 15); Rectangle rect3(20, 15); - + rect2.translate({10, 0}); rect3.translate({25, 0}); - + TMultiShape pile; pile.push_back(rect1.transformedShape()); pile.push_back(rect2.transformedShape()); - + auto result = nfp::merge(pile, rect3.transformedShape()); - + ASSERT_EQ(result.size(), 1); - + Rectangle ref(45, 15); - + ASSERT_EQ(shapelike::area(result.front()), ref.area()); } @@ -908,7 +905,7 @@ long double refMinAreaBox(const PolygonImpl& p) { long double min_area = std::numeric_limits::max(); - + auto update_min = [&min_area, &it, &itx, &p]() { Segment s(*it, *itx); @@ -935,67 +932,39 @@ template struct BoostGCD { }; using Unit = int64_t; -using Ratio = boost::rational;// Rational; - -//double gteMinAreaBox(const PolygonImpl& p) { - -// using GteCoord = ClipperLib::cInt; -// using GtePoint = gte::Vector2; - -// gte::MinimumAreaBox2 mb; - -// std::vector points; -// points.reserve(p.Contour.size()); - -// for(auto& pt : p.Contour) points.emplace_back(GtePoint{GteCoord(pt.X), GteCoord(pt.Y)}); - -// mb(int(points.size()), points.data(), 0, nullptr, true); - -// auto min_area = double(mb.GetArea()); - -// return min_area; -//} +using Ratio = boost::rational; } TEST(RotatingCalipers, MinAreaBBCClk) { -// PolygonImpl poly({{-50, 30}, {-50, -50}, {50, -50}, {50, 50}, {-40, 50}}); - -// PolygonImpl poly({{-50, 0}, {50, 0}, {0, 100}}); - auto u = [](ClipperLib::cInt n) { return n*1000000; }; PolygonImpl poly({ {u(0), u(0)}, {u(4), u(1)}, {u(2), u(4)}}); - long double arearef = refMinAreaBox(poly); long double area = minAreaBoundingBox(poly).area(); -// double gtearea = gteMinAreaBox(poly); ASSERT_LE(std::abs(area - arearef), 500e6 ); -// ASSERT_LE(std::abs(gtearea - arearef), 500 ); -// ASSERT_DOUBLE_EQ(gtearea, arearef); } TEST(RotatingCalipers, AllPrusaMinBB) { - size_t idx = 0; + // /size_t idx = 0; long double err_epsilon = 500e6l; for(ClipperLib::Path rinput : PRINTER_PART_POLYGONS) { -// ClipperLib::Path rinput = PRINTER_PART_POLYGONS[idx]; -// rinput.pop_back(); -// std::reverse(rinput.begin(), rinput.end()); + // ClipperLib::Path rinput = PRINTER_PART_POLYGONS[idx]; + // rinput.pop_back(); + // std::reverse(rinput.begin(), rinput.end()); -// PolygonImpl poly(removeCollinearPoints(rinput, 1000000)); + // PolygonImpl poly(removeCollinearPoints(rinput, 1000000)); PolygonImpl poly(rinput); long double arearef = refMinAreaBox(poly); auto bb = minAreaBoundingBox(rinput); long double area = cast(bb.area()); -// double area = gteMinAreaBox(poly); bool succ = std::abs(arearef - area) < err_epsilon; - std::cout << idx++ << " " << (succ? "ok" : "failed") << " ref: " - << arearef << " actual: " << area << std::endl; + // std::cout << idx++ << " " << (succ? "ok" : "failed") << " ref: " +// << arearef << " actual: " << area << std::endl; ASSERT_TRUE(succ); } @@ -1006,21 +975,20 @@ TEST(RotatingCalipers, AllPrusaMinBB) { PolygonImpl poly(removeCollinearPoints(rinput, 1000000)); - long double arearef = refMinAreaBox(poly); auto bb = minAreaBoundingBox(poly); long double area = cast(bb.area()); -// double area = gteMinAreaBox(poly); + bool succ = std::abs(arearef - area) < err_epsilon; - std::cout << idx++ << " " << (succ? "ok" : "failed") << " ref: " - << arearef << " actual: " << area << std::endl; + // std::cout << idx++ << " " << (succ? "ok" : "failed") << " ref: " +// << arearef << " actual: " << area << std::endl; ASSERT_TRUE(succ); } } int main(int argc, char **argv) { - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); } diff --git a/src/libslic3r/MTUtils.hpp b/src/libslic3r/MTUtils.hpp index b261a79be8..df248ca5d9 100644 --- a/src/libslic3r/MTUtils.hpp +++ b/src/libslic3r/MTUtils.hpp @@ -7,6 +7,9 @@ #include // for std::forward #include +#include "libslic3r.h" +#include "Point.hpp" + namespace Slic3r { /// Handy little spin mutex for the cached meshes. @@ -248,6 +251,94 @@ template inline X ceil_i(X x, Y y) return (x % y) ? x / y + 1 : x / y; } +// A shorter C++14 style form of the enable_if metafunction +template +using enable_if_t = typename std::enable_if::type; + +// ///////////////////////////////////////////////////////////////////////////// +// Type safe conversions to and from scaled and unscaled coordinates +// ///////////////////////////////////////////////////////////////////////////// + +// A meta-predicate which is true for integers wider than or equal to coord_t +template struct is_scaled_coord +{ + static const SLIC3R_CONSTEXPR bool value = + std::is_integral::value && + std::numeric_limits::digits >= + std::numeric_limits::digits; +}; + +// Meta predicates for floating, 'scaled coord' and generic arithmetic types +template +using FloatingOnly = enable_if_t::value, T>; + +template +using ScaledCoordOnly = enable_if_t::value, T>; + +template +using ArithmeticOnly = enable_if_t::value, T>; + +// A shorter form for a generic Eigen vector which is widely used in PrusaSlicer +template +using EigenVec = Eigen::Matrix; + +// Semantics are the following: +// Upscaling (scaled()): only from floating point types (or Vec) to either +// floating point or integer 'scaled coord' coordinates. +// Downscaling (unscaled()): from arithmetic types (or Vec) to either +// floating point only + +// Conversion definition from unscaled to floating point scaled +template, + class = FloatingOnly> +inline SLIC3R_CONSTEXPR Tout scaled(const Tin &v) SLIC3R_NOEXCEPT +{ + return static_cast(v / static_cast(SCALING_FACTOR)); +} + +// Conversion definition from unscaled to integer 'scaled coord'. +// TODO: is the rounding necessary ? Here it is to show that it can be different +// but it does not have to be. Using std::round means loosing noexcept and +// constexpr modifiers +template> +inline SLIC3R_CONSTEXPR ScaledCoordOnly scaled(const Tin &v) SLIC3R_NOEXCEPT +{ + //return static_cast(std::round(v / SCALING_FACTOR)); + return static_cast(v / static_cast(SCALING_FACTOR)); +} + +// Conversion for Eigen vectors (N dimensional points) +template> +inline EigenVec, N> scaled(const EigenVec &v) +{ + return v.template cast() / SCALING_FACTOR; +} + +// Conversion from arithmetic scaled type to floating point unscaled +template, + class = FloatingOnly> +inline SLIC3R_CONSTEXPR Tout unscaled(const Tin &v) SLIC3R_NOEXCEPT +{ + return static_cast(v * static_cast(SCALING_FACTOR)); +} + +// Unscaling for Eigen vectors. Input base type can be arithmetic, output base +// type can only be floating point. +template, + class = FloatingOnly> +inline SLIC3R_CONSTEXPR EigenVec unscaled( + const EigenVec &v) SLIC3R_NOEXCEPT +{ + return v.template cast() * SCALING_FACTOR; +} + } // namespace Slic3r #endif // MTUTILS_HPP diff --git a/src/libslic3r/MinAreaBoundingBox.cpp b/src/libslic3r/MinAreaBoundingBox.cpp index 6fc1b3327a..fafb54a585 100644 --- a/src/libslic3r/MinAreaBoundingBox.cpp +++ b/src/libslic3r/MinAreaBoundingBox.cpp @@ -39,7 +39,7 @@ template<> inline Slic3r::Points& contour(Slic3r::Polygon& sh) { return sh.point template<> inline const Slic3r::Points& contour(const Slic3r::Polygon& sh) { return sh.points; } template<> Slic3r::Points::iterator begin(Slic3r::Points& pts, const PathTag&) { return pts.begin();} -template<> Slic3r::Points::const_iterator cbegin(const Slic3r::Points& pts, const PathTag&) { return pts.begin(); } +template<> Slic3r::Points::const_iterator cbegin(const Slic3r::Points& pts, const PathTag&) { return pts.cbegin(); } template<> Slic3r::Points::iterator end(Slic3r::Points& pts, const PathTag&) { return pts.end();} template<> Slic3r::Points::const_iterator cend(const Slic3r::Points& pts, const PathTag&) { return pts.cend(); } @@ -71,62 +71,67 @@ using Rational = boost::rational<__int128>; MinAreaBoundigBox::MinAreaBoundigBox(const Polygon &p, PolygonLevel pc) { - const Polygon& chull = pc == pcConvex ? p : libnest2d::sl::convexHull(p); - - libnest2d::RotatedBox box = - libnest2d::minAreaBoundingBox(chull); - - m_right = box.right_extent(); - m_bottom = box.bottom_extent(); - m_axis = box.axis(); + const Polygon &chull = pc == pcConvex ? p : + libnest2d::sl::convexHull(p); + + libnest2d::RotatedBox box = + libnest2d::minAreaBoundingBox(chull); + + m_right = libnest2d::cast(box.right_extent()); + m_bottom = libnest2d::cast(box.bottom_extent()); + m_axis = box.axis(); } MinAreaBoundigBox::MinAreaBoundigBox(const ExPolygon &p, PolygonLevel pc) { - const ExPolygon& chull = pc == pcConvex ? p : libnest2d::sl::convexHull(p); - - libnest2d::RotatedBox box = - libnest2d::minAreaBoundingBox(chull); - - m_right = box.right_extent(); - m_bottom = box.bottom_extent(); - m_axis = box.axis(); + const ExPolygon &chull = pc == pcConvex ? p : + libnest2d::sl::convexHull(p); + + libnest2d::RotatedBox box = + libnest2d::minAreaBoundingBox(chull); + + m_right = libnest2d::cast(box.right_extent()); + m_bottom = libnest2d::cast(box.bottom_extent()); + m_axis = box.axis(); } MinAreaBoundigBox::MinAreaBoundigBox(const Points &pts, PolygonLevel pc) { - const Points& chull = pc == pcConvex ? pts : libnest2d::sl::convexHull(pts); - - libnest2d::RotatedBox box = - libnest2d::minAreaBoundingBox(chull); - - m_right = box.right_extent(); - m_bottom = box.bottom_extent(); - m_axis = box.axis(); + const Points &chull = pc == pcConvex ? pts : + libnest2d::sl::convexHull(pts); + + libnest2d::RotatedBox box = + libnest2d::minAreaBoundingBox(chull); + + m_right = libnest2d::cast(box.right_extent()); + m_bottom = libnest2d::cast(box.bottom_extent()); + m_axis = box.axis(); } double MinAreaBoundigBox::angle_to_X() const { double ret = std::atan2(m_axis.y(), m_axis.x()); - auto s = std::signbit(ret); - if(s) ret += 2 * PI; + auto s = std::signbit(ret); + if (s) ret += 2 * PI; return -ret; } long double MinAreaBoundigBox::width() const { - return std::abs(m_bottom) / std::sqrt(libnest2d::pl::magnsq(m_axis)); + return std::abs(m_bottom) / + std::sqrt(libnest2d::pl::magnsq(m_axis)); } long double MinAreaBoundigBox::height() const { - return std::abs(m_right) / std::sqrt(libnest2d::pl::magnsq(m_axis)); + return std::abs(m_right) / + std::sqrt(libnest2d::pl::magnsq(m_axis)); } long double MinAreaBoundigBox::area() const { long double asq = libnest2d::pl::magnsq(m_axis); - return m_bottom * m_right / asq; + return m_bottom * m_right / asq; } void remove_collinear_points(Polygon &p) @@ -138,5 +143,4 @@ void remove_collinear_points(ExPolygon &p) { p = libnest2d::removeCollinearPoints(p, Unit(0)); } - -} +} // namespace Slic3r diff --git a/src/libslic3r/ModelArrange.cpp b/src/libslic3r/ModelArrange.cpp index 36f7e39710..bc0f933d1d 100644 --- a/src/libslic3r/ModelArrange.cpp +++ b/src/libslic3r/ModelArrange.cpp @@ -610,7 +610,7 @@ ShapeData2D projectModelFromTop(const Slic3r::Model &model, if(tolerance > EPSILON) { Polygons pp { p }; - pp = p.simplify(double(scaled(tolerance))); + pp = p.simplify(scaled(tolerance)); if (!pp.empty()) p = pp.front(); } diff --git a/src/libslic3r/SLA/SLABasePool.cpp b/src/libslic3r/SLA/SLABasePool.cpp index 3b199c4ebb..04cbd78243 100644 --- a/src/libslic3r/SLA/SLABasePool.cpp +++ b/src/libslic3r/SLA/SLABasePool.cpp @@ -5,6 +5,7 @@ #include "SLABoostAdapter.hpp" #include "ClipperUtils.hpp" #include "Tesselate.hpp" +#include "MTUtils.hpp" // For debugging: //#include @@ -203,7 +204,7 @@ void offset(ExPolygon& sh, coord_t distance) { } ClipperOffset offs; - offs.ArcTolerance = 0.01*scaled(1.0); + offs.ArcTolerance = scaled(0.01); Paths result; offs.AddPath(ctour, jtRound, etClosedPolygon); offs.AddPaths(holes, jtRound, etClosedPolygon); @@ -351,7 +352,7 @@ Contour3D round_edges(const ExPolygon& base_plate, double x2 = xx*xx; double stepy = std::sqrt(r2 - x2); - offset(ob, s*scaled(xx)); + offset(ob, s * scaled(xx)); wh = ceilheight_mm - radius_mm + stepy; Contour3D pwalls; @@ -375,7 +376,7 @@ Contour3D round_edges(const ExPolygon& base_plate, double xx = radius_mm - i*stepx; double x2 = xx*xx; double stepy = std::sqrt(r2 - x2); - offset(ob, s*scaled(xx)); + offset(ob, s * scaled(xx)); wh = ceilheight_mm - radius_mm - stepy; Contour3D pwalls; @@ -476,7 +477,7 @@ ExPolygons concave_hull(const ExPolygons& polys, double max_dist_mm = 50, double dx = x(c) - x(cc), dy = y(c) - y(cc); double l = std::sqrt(dx * dx + dy * dy); double nx = dx / l, ny = dy / l; - double max_dist = scaled(max_dist_mm); + double max_dist = scaled(max_dist_mm); ExPolygon& expo = punion[idx++]; BoundingBox querybb(expo); @@ -492,7 +493,7 @@ ExPolygons concave_hull(const ExPolygons& polys, double max_dist_mm = 50, ctour.reserve(3); ctour.emplace_back(cc); - Point d(coord_t(scaled(1.)*nx), coord_t(scaled(1.)*ny)); + Point d(scaled(nx), scaled(ny)); ctour.emplace_back(c + Point( -y(d), x(d) )); ctour.emplace_back(c + Point( y(d), -x(d) )); offset(r, scaled(1.)); @@ -529,14 +530,14 @@ void base_plate(const TriangleMesh &mesh, ExPolygons &output, float h, ExPolygons tmp; tmp.reserve(count); for(ExPolygons& o : out) for(ExPolygon& e : o) { - auto&& exss = e.simplify(scaled(0.1)); + auto&& exss = e.simplify(scaled(0.1)); for(ExPolygon& ep : exss) tmp.emplace_back(std::move(ep)); } ExPolygons utmp = unify(tmp); for(auto& o : utmp) { - auto&& smp = o.simplify(scaled(0.1)); + auto&& smp = o.simplify(scaled(0.1)); output.insert(output.end(), smp.begin(), smp.end()); } } diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index c73ae5650d..7ae481ffbf 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -668,7 +668,7 @@ void SLAPrint::process() double ilhd = m_material_config.initial_layer_height.getFloat(); auto ilh = float(ilhd); - auto ilhs = scaled(ilhd); + coord_t ilhs = scaled(ilhd); const size_t objcount = m_objects.size(); static const unsigned min_objstatus = 0; // where the per object operations start @@ -694,17 +694,15 @@ void SLAPrint::process() // We need to prepare the slice index... - double lhd = m_objects.front()->m_config.layer_height.getFloat(); - float lh = float(lhd); - auto lhs = scaled(lhd); - - auto &&bb3d = mesh.bounding_box(); - double minZ = bb3d.min(Z) - po.get_elevation(); - double maxZ = bb3d.max(Z); - auto minZf = float(minZ); - - auto minZs = scaled(minZ); - auto maxZs = scaled(maxZ); + double lhd = m_objects.front()->m_config.layer_height.getFloat(); + float lh = float(lhd); + coord_t lhs = scaled(lhd); + auto && bb3d = mesh.bounding_box(); + double minZ = bb3d.min(Z) - po.get_elevation(); + double maxZ = bb3d.max(Z); + auto minZf = float(minZ); + coord_t minZs = scaled(minZ); + coord_t maxZs = scaled(maxZ); po.m_slice_index.clear(); @@ -1013,9 +1011,6 @@ void SLAPrint::process() using ClipperPolygons = std::vector; namespace sl = libnest2d::shapelike; // For algorithms - // If the raster has vertical orientation, we will flip the coordinates -// bool flpXY = m_printer_config.display_orientation.getInt() == SLADisplayOrientation::sladoPortrait; - // Set up custom union and diff functions for clipper polygons auto polyunion = [] (const ClipperPolygons& subjects) { @@ -1066,8 +1061,8 @@ void SLAPrint::process() const int fade_layers_cnt = m_default_object_config.faded_layers.getInt();// 10 // [3;20] - const double width = scaled(m_printer_config.display_width.getFloat()); - const double height = scaled(m_printer_config.display_height.getFloat()); + const auto width = scaled(m_printer_config.display_width.getFloat()); + const auto height = scaled(m_printer_config.display_height.getFloat()); const double display_area = width*height; // get polygons for all instances in the object @@ -1123,11 +1118,6 @@ void SLAPrint::process() sl::translate(poly, ClipperPoint{instances[i].shift(X), instances[i].shift(Y)}); -// if (flpXY) { -// for(auto& p : poly.Contour) std::swap(p.X, p.Y); -// for(auto& h : poly.Holes) for(auto& p : h) std::swap(p.X, p.Y); -// } - polygons.emplace_back(std::move(poly)); } } diff --git a/src/libslic3r/libslic3r.h b/src/libslic3r/libslic3r.h index 8cafae17cf..dc2b6a4ec0 100644 --- a/src/libslic3r/libslic3r.h +++ b/src/libslic3r/libslic3r.h @@ -61,20 +61,6 @@ typedef double coordf_t; #define SLIC3R_NOEXCEPT noexcept #endif -template inline SLIC3R_CONSTEXPR coord_t scaled(Tf val) -{ - static_assert (std::is_floating_point::value, "Floating point only"); - return coord_t(val / Tf(SCALING_FACTOR)); -} - -template inline SLIC3R_CONSTEXPR Tf unscaled(coord_t val) -{ - static_assert (std::is_floating_point::value, "Floating point only"); - return Tf(val * Tf(SCALING_FACTOR)); -} - -inline SLIC3R_CONSTEXPR float unscaledf(coord_t val) { return unscaled(val); } - inline std::string debug_out_path(const char *name, ...) { char buffer[2048]; From 6ff434aba3367e2111b1ff809ea744ca39347a56 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Wed, 26 Jun 2019 11:10:41 +0200 Subject: [PATCH 08/12] Fixes some ModelArrange warnings --- src/libslic3r/MTUtils.hpp | 9 --------- src/libslic3r/ModelArrange.cpp | 18 ++++++++++-------- 2 files changed, 10 insertions(+), 17 deletions(-) diff --git a/src/libslic3r/MTUtils.hpp b/src/libslic3r/MTUtils.hpp index df248ca5d9..70603cd15f 100644 --- a/src/libslic3r/MTUtils.hpp +++ b/src/libslic3r/MTUtils.hpp @@ -242,15 +242,6 @@ template bool all_of(const C &container) }); } -template inline X ceil_i(X x, Y y) -{ - static_assert(std::is_integral::value && - std::is_integral::value && sizeof(X) >= sizeof(Y), - ""); - - return (x % y) ? x / y + 1 : x / y; -} - // A shorter C++14 style form of the enable_if metafunction template using enable_if_t = typename std::enable_if::type; diff --git a/src/libslic3r/ModelArrange.cpp b/src/libslic3r/ModelArrange.cpp index bc0f933d1d..db36653b0f 100644 --- a/src/libslic3r/ModelArrange.cpp +++ b/src/libslic3r/ModelArrange.cpp @@ -62,10 +62,10 @@ std::string toString(const Model& model, bool holes = true) { objinst->transform_mesh(&tmpmesh); ExPolygons expolys = tmpmesh.horizontal_projection(); for(auto& expoly_complex : expolys) { - - auto tmp = expoly_complex.simplify(1.0/SCALING_FACTOR); + + ExPolygons tmp = expoly_complex.simplify(scaled(1.)); if(tmp.empty()) continue; - auto expoly = tmp.front(); + ExPolygon expoly = tmp.front(); expoly.contour.make_clockwise(); for(auto& h : expoly.holes) h.make_counter_clockwise(); @@ -633,8 +633,8 @@ ShapeData2D projectModelFromTop(const Slic3r::Model &model, if(item.vertexCount() > 3) { item.rotation(Geometry::rotation_diff_z(rotation0, objinst->get_rotation())); item.translation({ - ClipperLib::cInt(objinst->get_offset(X)/SCALING_FACTOR), - ClipperLib::cInt(objinst->get_offset(Y)/SCALING_FACTOR) + scaled(objinst->get_offset(X)), + scaled(objinst->get_offset(Y)) }); ret.emplace_back(objinst, item); } @@ -658,8 +658,8 @@ ShapeData2D projectModelFromTop(const Slic3r::Model &model, Item item(std::move(pn)); item.rotation(wti.rotation), item.translation({ - ClipperLib::cInt(wti.pos(0)/SCALING_FACTOR), - ClipperLib::cInt(wti.pos(1)/SCALING_FACTOR) + scaled(wti.pos(0)), + scaled(wti.pos(1)) }); ret.emplace_back(nullptr, item); } @@ -822,7 +822,9 @@ bool arrange(Model &model, // The model with the geometries auto& cfn = stopcondition; - coord_t md = ceil_i(min_obj_distance, 2) - SCALED_EPSILON; + // Integer ceiling the min distance from the bed perimeters + coord_t md = min_obj_distance - SCALED_EPSILON; + md = (md % 2) ? md / 2 + 1 : md / 2; auto binbb = Box({libnest2d::Coord{bbb.min(0)} - md, libnest2d::Coord{bbb.min(1)} - md}, From d845332de1e393e7a0d7f37379f6de0a31b4ee82 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 26 Jun 2019 11:49:02 +0200 Subject: [PATCH 09/12] Fixed a crash when using place to bed function with the layer editing active This was caused by trying to render a deleted layer height profile. Other gizmos were not affected because they are not dragging at the time of their action, so the profile was correctly recalculated for them. --- src/slic3r/GUI/GLCanvas3D.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index c828e0ec66..bed3b754b3 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -457,8 +457,10 @@ void GLCanvas3D::LayersEditing::_render_profile(const Rect& bar_rect) const { //FIXME show some kind of legend. + if (!m_slicing_parameters) + return; + // Make the vertical bar a bit wider so the layer height curve does not touch the edge of the bar region. - assert(m_slicing_parameters != nullptr); float scale_x = bar_rect.get_width() / (float)(1.12 * m_slicing_parameters->max_layer_height); float scale_y = bar_rect.get_height() / m_object_max_z; float x = bar_rect.get_left() + (float)m_slicing_parameters->layer_height * scale_x; From d2136ab6253ced47b6ccca2a9256fb265083d734 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 26 Jun 2019 13:12:25 +0200 Subject: [PATCH 10/12] ObjectList no longer caps number of extruders to 9 (fixes https://github.com/prusa3d/PrusaSlicer/issues/2558) --- src/slic3r/GUI/GUI_ObjectList.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index d7d1a1af7b..e926dcf978 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -460,7 +460,7 @@ void ObjectList::update_extruder_in_config(const wxDataViewItem& item) if (!m_config || selection.empty()) return; - const int extruder = selection.size() > 1 ? 0 : atoi(selection.c_str()); + const int extruder = /*selection.size() > 1 ? 0 : */atoi(selection.c_str()); m_config->set_key_value("extruder", new ConfigOptionInt(extruder)); // update scene From 7e52edb88c411339a0203df3049029f4394b8d7d Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Wed, 26 Jun 2019 13:23:08 +0200 Subject: [PATCH 11/12] Try to supress warnings from bundled IGL under Windows. --- src/libigl/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libigl/CMakeLists.txt b/src/libigl/CMakeLists.txt index 0852fad729..3daac757b1 100644 --- a/src/libigl/CMakeLists.txt +++ b/src/libigl/CMakeLists.txt @@ -10,5 +10,5 @@ if(libigl_FOUND) target_link_libraries(libigl INTERFACE igl::core) else() message(STATUS "IGL NOT found, using bundled version...") - target_include_directories(libigl INTERFACE SYSTEM ${LIBDIR}/libigl) + target_include_directories(libigl SYSTEM BEFORE INTERFACE ${LIBDIR}/libigl) endif() From 624a6aefb4b9dc73aae2e5e95cecd62fc1a78f56 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Wed, 26 Jun 2019 13:29:49 +0200 Subject: [PATCH 12/12] Fixed crashes after loading some AMFs. --- src/libslic3r/Model.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 596f806710..9d68f7141d 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -1564,8 +1564,10 @@ void ModelVolume::center_geometry_after_creation() Vec3d shift = this->mesh().bounding_box().center(); if (!shift.isApprox(Vec3d::Zero())) { - m_mesh->translate(-(float)shift(0), -(float)shift(1), -(float)shift(2)); - m_convex_hull->translate(-(float)shift(0), -(float)shift(1), -(float)shift(2)); + if (m_mesh) + m_mesh->translate(-(float)shift(0), -(float)shift(1), -(float)shift(2)); + if (m_convex_hull) + m_convex_hull->translate(-(float)shift(0), -(float)shift(1), -(float)shift(2)); translate(shift); } }