From 8c4fa9ba51e93c8e0b9da6671c5c6cedd58b9cc4 Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Wed, 7 Nov 2018 15:23:00 +0100 Subject: [PATCH 01/10] CMake: Add ASan option --- CMakeLists.txt | 8 ++++++++ src/CMakeLists.txt | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0656b824e4..bcdb67684d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,6 +26,7 @@ option(SLIC3R_PROFILE "Compile Slic3r with an invasive Shiny profiler" 0) option(SLIC3R_MSVC_COMPILE_PARALLEL "Compile on Visual Studio in parallel" 1) option(SLIC3R_MSVC_PDB "Generate PDB files on MSVC in Release mode" 1) option(SLIC3R_PERL_XS "Compile XS Perl module and enable Perl unit and integration tests" 0) +option(SLIC3R_ASAN "Enable ASan on Clang and GCC" 0) if (MSVC) if (SLIC3R_MSVC_COMPILE_PARALLEL) @@ -89,6 +90,13 @@ endif() if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") # On GCC and Clang, no return from a non-void function is a warning only. Here, we make it an error. add_compile_options(-Werror=return-type) + + if (SLIC3R_ASAN) + add_compile_options(-fsanitize=address -fno-omit-frame-pointer) + if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lasan") + endif () + endif () endif() # Where all the bundled libraries reside? diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a101fd522d..32d2c5b03f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -78,7 +78,7 @@ if (APPLE) target_link_libraries(slic3r "-liconv -framework IOKit" "-framework CoreFoundation" -lc++) elseif (MSVC) # Manifest is provided through slic3r.rc, don't generate your own. - set(CMAKE_EXE_LINKER_FLAGS /MANIFEST:NO) + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /MANIFEST:NO") else () target_link_libraries(slic3r -ldl -lstdc++) endif () From 2c0b784a2d8db1bf18102c749cf0496bc3ab806e Mon Sep 17 00:00:00 2001 From: YuSanka Date: Wed, 7 Nov 2018 13:40:24 +0100 Subject: [PATCH 02/10] Added(ported) function fix_through_netfabb() + Fixed adding of the instances to the object list --- CMakeLists.txt | 7 +++++ src/slic3r/GUI/GUI_ObjectList.cpp | 8 +++-- src/slic3r/GUI/Plater.cpp | 51 ++++++++++++++++--------------- src/slic3r/GUI/Plater.hpp | 1 + src/slic3r/GUI/wxExtensions.cpp | 2 +- 5 files changed, 41 insertions(+), 28 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bcdb67684d..a0980080ec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -74,6 +74,13 @@ if(WIN32) message("STL fixing by the Netfabb service will not be compiled") unset(WIN10SDK_PATH) endif() + if(WIN10SDK_PATH) + message("Building with Win10 Netfabb STL fixing service support") + add_definitions(-DHAS_WIN10SDK) + include_directories("${WIN10SDK_PATH}/Include") + else() + message("Building without Win10 Netfabb STL fixing service support") + endif() endif() if (CMAKE_SYSTEM_NAME STREQUAL "Linux") diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 63d9740ca3..32742b490c 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -286,8 +286,10 @@ void ObjectList::context_menu() else if (title == _("Name") && pt.x >15 && m_objects_model->GetBitmap(item).GetRefData() == m_bmp_manifold_warning.GetRefData()) { - if (is_windows10()) - /*fix_through_netfabb()*/;// #ys_FIXME + if (is_windows10()) { + const auto obj_idx = m_objects_model->GetIdByItem(m_objects_model->GetTopParent(item)); + wxGetApp().plater()->fix_through_netfabb(obj_idx); + } } #ifndef __WXMSW__ GetMainWindow()->SetToolTip(""); // hide tooltip @@ -1093,7 +1095,7 @@ void ObjectList::add_object_to_list(size_t obj_idx) // add settings to the object, if it has those auto opt_keys = model_object->config.keys(); - if ( !(opt_keys.size() == 1 && opt_keys[0] == "extruder") ) { + if (!opt_keys.empty() && !(opt_keys.size() == 1 && opt_keys[0] == "extruder")) { select_item(m_objects_model->AddSettingsChild(item)); Collapse(item); } diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 0381744dad..7e91276d4d 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -49,7 +49,7 @@ #include "BackgroundSlicingProcess.hpp" #include "ProgressStatusBar.hpp" #include "slic3r/Utils/ASCIIFolding.hpp" -#include "PrintConfig.hpp" +#include "../Utils/FixModelByWin10.hpp" #include // Needs to be last because reasons :-/ #include "WipeTowerDialog.hpp" @@ -898,7 +898,7 @@ struct Plater::priv void start_background_process(); void reload_from_disk(); void export_object_stl(); - void fix_through_netfabb(); + void fix_through_netfabb(const int obj_idx); void on_notebook_changed(wxBookCtrlEvent&); void on_select_preset(wxCommandEvent&); @@ -1578,35 +1578,35 @@ void Plater::priv::export_object_stl() // TODO } -void Plater::priv::fix_through_netfabb() +void Plater::priv::fix_through_netfabb(const int obj_idx) { -/* - my ($self) = @_; - my ($obj_idx, $object) = $self->selected_object; - return if !defined $obj_idx; - my $model_object = $self->{model}->objects->[$obj_idx]; - my $model_fixed = Slic3r::Model->new; - Slic3r::GUI::fix_model_by_win10_sdk_gui($model_object, $self->{print}, $model_fixed); + if (obj_idx < 0) + return; - my @new_obj_idx = $self->load_model_objects(@{$model_fixed->objects}); - return if !@new_obj_idx; + const auto model_object = model.objects[obj_idx]; + Model model_fixed;// = new Model(); + fix_model_by_win10_sdk_gui(*model_object, print, model_fixed); + + auto new_obj_idxs = load_model_objects(model_fixed.objects); + if (new_obj_idxs.empty()) + return; - foreach my $new_obj_idx (@new_obj_idx) { - my $o = $self->{model}->objects->[$new_obj_idx]; - $o->clear_instances; - $o->add_instance($_) for @{$model_object->instances}; - #$o->invalidate_bounding_box; + for(auto new_obj_idx : new_obj_idxs) { + auto o = model.objects[new_obj_idx]; + o->clear_instances(); + for (auto instance: model_object->instances) + o->add_instance(*instance); + // o->invalidate_bounding_box(); - if ($o->volumes_count == $model_object->volumes_count) { - for my $i (0..($o->volumes_count-1)) { - $o->get_volume($i)->config->apply($model_object->get_volume($i)->config); + if (o->volumes.size() == model_object->volumes.size()) { + for (int i = 0; i < o->volumes.size(); i++) { + 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, layer_height_profile_valid, } - $self->remove($obj_idx); -*/ + remove(obj_idx); } void Plater::priv::on_notebook_changed(wxBookCtrlEvent&) @@ -1969,6 +1969,8 @@ void Plater::increase_instances(size_t num) ModelObject* model_object = p->model.objects[obj_idx]; ModelInstance* model_instance = model_object->instances.back(); + bool was_one_instance = model_object->instances.size()==1; + float offset = 10.0; for (size_t i = 0; i < num; i++, offset += 10.0) { Vec3d offset_vec = model_instance->get_offset() + Vec3d(offset, offset, 0.0); @@ -1976,7 +1978,7 @@ void Plater::increase_instances(size_t num) // p->print.get_object(obj_idx)->add_copy(Slic3r::to_2d(offset_vec)); } - sidebar().obj_list()->increase_object_instances(obj_idx, num); + sidebar().obj_list()->increase_object_instances(obj_idx, was_one_instance ? num + 1 : num); if (p->get_config("autocenter") == "1") { p->arrange(); @@ -2286,5 +2288,6 @@ void Plater::changed_object(int obj_idx) } +void Plater::fix_through_netfabb(const int obj_idx) { p->fix_through_netfabb(obj_idx); } }} // namespace Slic3r::GUI diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index 30c14621da..095dde4828 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -125,6 +125,7 @@ public: void export_3mf(); void reslice(); void changed_object(int obj_idx); + void fix_through_netfabb(const int obj_idx); void send_gcode(); void on_extruders_change(int extruders_count); diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index 52b6a01e9e..5c169d7a41 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -532,7 +532,7 @@ wxDataViewItem PrusaObjectDataViewModel::AddInstanceChild(const wxDataViewItem & parent_node->Append(inst_root_node); // notify control ItemAdded(parent_item, inst_root_item); - if (num == 1) num++; +// if (num == 1) num++; } // Add instance nodes From f1224c64ba861e80598917419cf05632b2e23ade Mon Sep 17 00:00:00 2001 From: YuSanka Date: Thu, 8 Nov 2018 09:54:43 +0100 Subject: [PATCH 03/10] Small fix inside fix_model_by_win10_sdk_gui() --- src/slic3r/Utils/FixModelByWin10.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/slic3r/Utils/FixModelByWin10.cpp b/src/slic3r/Utils/FixModelByWin10.cpp index 556035a5b1..eb04b10e0c 100644 --- a/src/slic3r/Utils/FixModelByWin10.cpp +++ b/src/slic3r/Utils/FixModelByWin10.cpp @@ -359,9 +359,9 @@ void fix_model_by_win10_sdk_gui(const ModelObject &model_object, const Print &pr fix_model_by_win10_sdk(path_src.string().c_str(), path_dst.string(), on_progress, [&canceled]() { if (canceled) throw RepairCanceledException(); }); boost::filesystem::remove(path_src); - PresetBundle bundle; + DynamicPrintConfig config;// PresetBundle bundle; on_progress(L("Loading the repaired model"), 80); - bool loaded = Slic3r::load_3mf(path_dst.string().c_str(), &bundle, &result); + bool loaded = Slic3r::load_3mf(path_dst.string().c_str(), &config/*bundle*/, &result); boost::filesystem::remove(path_dst); if (! loaded) throw std::runtime_error(L("Import of the repaired 3mf file failed")); From d590661d400f0f990d12c88f1d49a1594b153e81 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 8 Nov 2018 10:18:19 +0100 Subject: [PATCH 04/10] Fixed objects name after 3mf import --- src/libslic3r/Format/3mf.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp index fc2cf7b893..6e8483949d 100644 --- a/src/libslic3r/Format/3mf.cpp +++ b/src/libslic3r/Format/3mf.cpp @@ -342,6 +342,7 @@ namespace Slic3r { IdToSlaSupportPointsMap m_sla_support_points; std::string m_curr_metadata_name; std::string m_curr_characters; + std::string m_name; public: _3MF_Importer(); @@ -444,6 +445,7 @@ namespace Slic3r { , m_unit_factor(1.0f) , m_curr_metadata_name("") , m_curr_characters("") + , m_name("") { } @@ -505,6 +507,8 @@ namespace Slic3r { mz_zip_archive_file_stat stat; + m_name = boost::filesystem::path(filename).filename().stem().string(); + // we first loop the entries to read from the archive the .model file only, in order to extract the version from it for (mz_uint i = 0; i < num_entries; ++i) { @@ -1051,6 +1055,9 @@ namespace Slic3r { // set object data m_curr_object.object->name = get_attribute_value_string(attributes, num_attributes, NAME_ATTR); + if (m_curr_object.object->name.empty()) + m_curr_object.object->name = m_name + "_" + std::to_string(m_model->objects.size()); + m_curr_object.id = get_attribute_value_int(attributes, num_attributes, ID_ATTR); } From 9e8e5761a9fee8c84e41123ff7d9780a87056fc4 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 8 Nov 2018 12:23:07 +0100 Subject: [PATCH 05/10] Added new query methods to GLCanvas3D::Selection --- src/slic3r/GUI/GLCanvas3D.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index b1b78d3b4b..1a377e7920 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -489,7 +489,10 @@ public: bool is_wipe_tower() const { return m_type == WipeTower; } bool is_modifier() const { return (m_type == SingleModifier) || (m_type == MultipleModifier); } bool is_single_full_instance() const; + bool is_multiple_full_instance() const { return m_type == MultipleFullInstance; } bool is_single_full_object() const { return m_type == SingleFullObject; } + bool is_single_volume() const { return m_type == SingleVolume; } + bool is_multiple_volume() const { return m_type == MultipleVolume; } bool is_mixed() const { return m_type == Mixed; } bool is_from_single_instance() const { return get_instance_idx() != -1; } bool is_from_single_object() const { return get_object_idx() != -1; } From 6d60ecffa0e610d70bef8fa3040147051380db00 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Thu, 8 Nov 2018 12:11:34 +0100 Subject: [PATCH 06/10] Added naming of the new(fixed) object + fixed inconsistency of parameters inside fix_model_by_win10_sdk_gui() --- src/slic3r/Utils/FixModelByWin10.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/slic3r/Utils/FixModelByWin10.cpp b/src/slic3r/Utils/FixModelByWin10.cpp index eb04b10e0c..16787f0f5b 100644 --- a/src/slic3r/Utils/FixModelByWin10.cpp +++ b/src/slic3r/Utils/FixModelByWin10.cpp @@ -347,8 +347,9 @@ void fix_model_by_win10_sdk_gui(const ModelObject &model_object, const Print &pr boost::filesystem::path path_src = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); path_src += ".3mf"; Model model; + DynamicPrintConfig config; model.add_object(model_object); - if (! Slic3r::store_3mf(path_src.string().c_str(), &model, const_cast(&print), false)) { + if (! Slic3r::store_3mf(path_src.string().c_str(), &model, &config/*const_cast(&print), false*/)) { boost::filesystem::remove(path_src); throw std::runtime_error(L("Export of a temporary 3mf file failed")); } @@ -359,10 +360,11 @@ void fix_model_by_win10_sdk_gui(const ModelObject &model_object, const Print &pr fix_model_by_win10_sdk(path_src.string().c_str(), path_dst.string(), on_progress, [&canceled]() { if (canceled) throw RepairCanceledException(); }); boost::filesystem::remove(path_src); - DynamicPrintConfig config;// PresetBundle bundle; + // PresetBundle bundle; on_progress(L("Loading the repaired model"), 80); bool loaded = Slic3r::load_3mf(path_dst.string().c_str(), &config/*bundle*/, &result); - boost::filesystem::remove(path_dst); + result.objects[0]->name = boost::filesystem::path(model_object.name).filename().stem().string() + "_fixed"; + boost::filesystem::remove(path_dst); if (! loaded) throw std::runtime_error(L("Import of the repaired 3mf file failed")); success = true; From c2e46350f28de58b0f0bdd20de0aa04f928a8c62 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Thu, 8 Nov 2018 14:23:17 +0100 Subject: [PATCH 07/10] Separated Print / PrintObject into PrintBase.cpp/h to support SLAPrint --- src/libslic3r/CMakeLists.txt | 2 + src/libslic3r/GCode.cpp | 31 +- src/libslic3r/GCode/ToolOrdering.cpp | 10 +- src/libslic3r/Model.hpp | 5 +- src/libslic3r/Print.cpp | 83 ++---- src/libslic3r/Print.hpp | 280 +++--------------- src/libslic3r/PrintBase.cpp | 16 ++ src/libslic3r/PrintBase.hpp | 297 ++++++++++++++++++++ src/libslic3r/PrintObject.cpp | 80 +----- src/slic3r.cpp | 6 +- src/slic3r/GUI/BackgroundSlicingProcess.cpp | 8 + src/slic3r/GUI/BackgroundSlicingProcess.hpp | 3 + src/slic3r/GUI/Plater.cpp | 7 +- xs/xsp/Model.xsp | 4 - xs/xsp/Print.xsp | 7 - 15 files changed, 433 insertions(+), 406 deletions(-) create mode 100644 src/libslic3r/PrintBase.cpp create mode 100644 src/libslic3r/PrintBase.hpp diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index c9953e38a5..b00000d089 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -127,6 +127,8 @@ add_library(libslic3r STATIC PolylineCollection.hpp Print.cpp Print.hpp + PrintBase.cpp + PrintBase.hpp PrintExport.hpp PrintConfig.cpp PrintConfig.hpp diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index b6752147b0..4f1ec05af0 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -373,11 +373,10 @@ std::vector>> GCode::collec size_t layer_idx; }; - PrintObjectPtrs printable_objects = print.get_printable_objects(); - std::vector> per_object(printable_objects.size(), std::vector()); + std::vector> per_object(print.objects().size(), std::vector()); std::vector ordering; - for (size_t i = 0; i < printable_objects.size(); ++i) { - per_object[i] = collect_layers_to_print(*printable_objects[i]); + for (size_t i = 0; i < print.objects().size(); ++i) { + per_object[i] = collect_layers_to_print(*print.objects()[i]); OrderingItem ordering_item; ordering_item.object_idx = i; ordering.reserve(ordering.size() + per_object[i].size()); @@ -402,7 +401,7 @@ std::vector>> GCode::collec std::pair> merged; // Assign an average print_z to the set of layers with nearly equal print_z. merged.first = 0.5 * (ordering[i].print_z + ordering[j-1].print_z); - merged.second.assign(printable_objects.size(), LayerToPrint()); + merged.second.assign(print.objects().size(), LayerToPrint()); for (; i < j; ++i) { const OrderingItem &oi = ordering[i]; assert(merged.second[oi.object_idx].layer() == nullptr); @@ -569,10 +568,9 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) // How many times will be change_layer() called? // change_layer() in turn increments the progress bar status. m_layer_count = 0; - PrintObjectPtrs printable_objects = print.get_printable_objects(); if (print.config().complete_objects.value) { // Add each of the object's layers separately. - for (auto object : printable_objects) { + for (auto object : print.objects()) { std::vector zs; zs.reserve(object->layers().size() + object->support_layers().size()); for (auto layer : object->layers()) @@ -585,7 +583,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) } else { // Print all objects with the same print_z together. std::vector zs; - for (auto object : printable_objects) { + for (auto object : print.objects()) { zs.reserve(zs.size() + object->layers().size() + object->support_layers().size()); for (auto layer : object->layers()) zs.push_back(layer->print_z); @@ -608,7 +606,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) { // get the minimum cross-section used in the print std::vector mm3_per_mm; - for (auto object : printable_objects) { + for (auto object : print.objects()) { for (size_t region_id = 0; region_id < object->region_volumes.size(); ++ region_id) { const PrintRegion* region = print.regions()[region_id]; for (auto layer : object->layers()) { @@ -673,7 +671,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) print.throw_if_canceled(); // Write some terse information on the slicing parameters. - const PrintObject *first_object = printable_objects.front(); + const PrintObject *first_object = print.objects().front(); const double layer_height = first_object->config().layer_height.value; const double first_layer_height = first_object->config().first_layer_height.get_abs_value(layer_height); for (const PrintRegion* region : print.regions()) { @@ -711,8 +709,8 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) bool has_wipe_tower = false; if (print.config().complete_objects.value) { // Find the 1st printing object, find its tool ordering and the initial extruder ID. - for (; initial_print_object_id < printable_objects.size(); ++initial_print_object_id) { - tool_ordering = ToolOrdering(*printable_objects[initial_print_object_id], initial_extruder_id); + for (; initial_print_object_id < print.objects().size(); ++initial_print_object_id) { + tool_ordering = ToolOrdering(*print.objects()[initial_print_object_id], initial_extruder_id); if ((initial_extruder_id = tool_ordering.first_extruder()) != (unsigned int)-1) break; } @@ -796,7 +794,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) // Collect outer contours of all objects over all layers. // Discard objects only containing thin walls (offset would fail on an empty polygon). Polygons islands; - for (const PrintObject *object : printable_objects) + for (const PrintObject *object : print.objects()) for (const Layer *layer : object->layers()) for (const ExPolygon &expoly : layer->slices.expolygons) for (const Point © : object->copies()) { @@ -849,7 +847,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) if (print.config().complete_objects.value) { // Print objects from the smallest to the tallest to avoid collisions // when moving onto next object starting point. - std::vector objects(printable_objects); + std::vector objects(print.objects()); std::sort(objects.begin(), objects.end(), [](const PrintObject* po1, const PrintObject* po2) { return po1->size(2) < po2->size(2); }); size_t finished_objects = 0; for (size_t object_id = initial_print_object_id; object_id < objects.size(); ++ object_id) { @@ -912,8 +910,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) // Order objects using a nearest neighbor search. std::vector object_indices; Points object_reference_points; - PrintObjectPtrs printable_objects = print.get_printable_objects(); - for (PrintObject *object : printable_objects) + for (PrintObject *object : print.objects()) object_reference_points.push_back(object->copies().front()); Slic3r::Geometry::chained_path(object_reference_points, object_indices); // Sort layers by Z. @@ -928,7 +925,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) // Verify, whether the print overaps the priming extrusions. BoundingBoxf bbox_print(get_print_extrusions_extents(print)); coordf_t twolayers_printz = ((layers_to_print.size() == 1) ? layers_to_print.front() : layers_to_print[1]).first + EPSILON; - for (const PrintObject *print_object : printable_objects) + for (const PrintObject *print_object : print.objects()) bbox_print.merge(get_print_object_extrusions_extents(*print_object, twolayers_printz)); bbox_print.merge(get_wipe_tower_extrusions_extents(print, twolayers_printz)); BoundingBoxf bbox_prime(get_wipe_tower_priming_extrusions_extents(print)); diff --git a/src/libslic3r/GCode/ToolOrdering.cpp b/src/libslic3r/GCode/ToolOrdering.cpp index 3793051f48..e800cd53f7 100644 --- a/src/libslic3r/GCode/ToolOrdering.cpp +++ b/src/libslic3r/GCode/ToolOrdering.cpp @@ -68,12 +68,11 @@ ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder, bool { m_print_config_ptr = &print.config(); - PrintObjectPtrs objects = print.get_printable_objects(); // Initialize the print layers for all objects and all layers. coordf_t object_bottom_z = 0.; { std::vector zs; - for (auto object : objects) { + for (auto object : print.objects()) { zs.reserve(zs.size() + object->layers().size() + object->support_layers().size()); for (auto layer : object->layers()) zs.emplace_back(layer->print_z); @@ -86,7 +85,7 @@ ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder, bool } // Collect extruders reuqired to print the layers. - for (auto object : objects) + for (auto object : print.objects()) this->collect_extruders(*object); // Reorder the extruders to minimize tool switches. @@ -451,7 +450,7 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, unsigned int return volume_to_wipe; // Soluble filament cannot be wiped in a random infill, neither the filament after it // we will sort objects so that dedicated for wiping are at the beginning: - PrintObjectPtrs object_list = print.get_printable_objects(); + PrintObjectPtrs object_list = print.objects(); std::sort(object_list.begin(), object_list.end(), [](const PrintObject* a, const PrintObject* b) { return a->config().wipe_into_objects; }); // We will now iterate through @@ -547,8 +546,7 @@ void WipingExtrusions::ensure_perimeters_infills_order(const Print& print) unsigned int first_nonsoluble_extruder = first_nonsoluble_extruder_on_layer(print.config()); unsigned int last_nonsoluble_extruder = last_nonsoluble_extruder_on_layer(print.config()); - PrintObjectPtrs printable_objects = print.get_printable_objects(); - for (const PrintObject* object : printable_objects) { + for (const PrintObject* object : print.objects()) { // Finds this layer: auto this_layer_it = std::find_if(object->layers().begin(), object->layers().end(), [<](const Layer* lay) { return std::abs(lt.print_z - lay->print_z)layers().end()) diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index b965f09ba7..a40c4e7d61 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -188,8 +188,9 @@ public: when user expects that. */ Vec3d origin_translation; - Model* get_model() const { return m_model; }; - + Model* get_model() { return m_model; }; + const Model* get_model() const { return m_model; }; + ModelVolume* add_volume(const TriangleMesh &mesh); ModelVolume* add_volume(TriangleMesh &&mesh); ModelVolume* add_volume(const ModelVolume &volume); diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 41e5f067d6..7c876d72e3 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -25,33 +25,27 @@ namespace Slic3r { template class PrintState; template class PrintState; -void Print::clear_objects() +void Print::clear() { - tbb::mutex::scoped_lock lock(m_mutex); + tbb::mutex::scoped_lock lock(this->cancel_mutex()); + // The following call should stop background processing if it is running. + this->invalidate_all_steps(); for (PrintObject *object : m_objects) delete object; m_objects.clear(); for (PrintRegion *region : m_regions) delete region; m_regions.clear(); - this->invalidate_all_steps(); -} - -void Print::delete_object(size_t idx) -{ - tbb::mutex::scoped_lock lock(m_mutex); - // destroy object and remove it from our container - delete m_objects[idx]; - m_objects.erase(m_objects.begin() + idx); - this->invalidate_all_steps(); - // TODO: purge unused regions } +// Only used by the Perl test cases. void Print::reload_object(size_t /* idx */) { ModelObjectPtrs model_objects; { - tbb::mutex::scoped_lock lock(m_mutex); + tbb::mutex::scoped_lock lock(this->cancel_mutex()); + // The following call should stop background processing if it is running. + this->invalidate_all_steps(); /* TODO: this method should check whether the per-object config and per-material configs have changed in such a way that regions need to be rearranged or we can just apply the diff and invalidate something. Same logic as apply_config() @@ -68,33 +62,12 @@ void Print::reload_object(size_t /* idx */) for (PrintRegion *region : m_regions) delete region; m_regions.clear(); - this->invalidate_all_steps(); } // re-add model objects for (ModelObject *mo : model_objects) this->add_model_object(mo); } -// Reloads the model instances into the print class. -// The slicing shall not be running as the modified model instances at the print -// are used for the brim & skirt calculation. -// Returns true if the brim or skirt have been invalidated. -bool Print::reload_model_instances() -{ - tbb::mutex::scoped_lock lock(m_mutex); - bool invalidated = false; - for (PrintObject *object : m_objects) - invalidated |= object->reload_model_instances(); - return invalidated; -} - -PrintObjectPtrs Print::get_printable_objects() const -{ - PrintObjectPtrs printable_objects(m_objects); - printable_objects.erase(std::remove_if(printable_objects.begin(), printable_objects.end(), [](PrintObject* o) { return !o->is_printable(); }), printable_objects.end()); - return printable_objects; -} - PrintRegion* Print::add_region() { m_regions.emplace_back(new PrintRegion(this)); @@ -282,11 +255,11 @@ bool Print::invalidate_state_by_config_options(const std::vectorcancel_mutex()); // Initialize a new print object and store it at the given position. - PrintObject *object = new PrintObject(this, model_object, model_object->raw_bounding_box()); + PrintObject *object = new PrintObject(this, model_object); if (idx != -1) { delete m_objects[idx]; m_objects[idx] = object; @@ -460,7 +433,7 @@ void Print::add_model_object(ModelObject* model_object, int idx) bool Print::apply_config(DynamicPrintConfig config) { - tbb::mutex::scoped_lock lock(m_mutex); + tbb::mutex::scoped_lock lock(this->cancel_mutex()); // we get a copy of the config object so we can modify it safely config.normalize(); @@ -560,7 +533,7 @@ exit_for_rearrange_regions: model_objects.reserve(m_objects.size()); for (PrintObject *object : m_objects) model_objects.push_back(object->model_object()); - this->clear_objects(); + this->clear(); for (ModelObject *mo : model_objects) this->add_model_object(mo); invalidated = true; @@ -786,7 +759,7 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co update_apply_status(false); // Grab the lock for the Print / PrintObject milestones. - tbb::mutex::scoped_lock lock(m_mutex); + tbb::mutex::scoped_lock lock(this->cancel_mutex()); // The following call may stop the background processing. update_apply_status(this->invalidate_state_by_config_options(print_diff)); @@ -823,7 +796,7 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co if (model.id() != m_model.id()) { // Kill everything, initialize from scratch. // Stop background processing. - m_cancel_callback(); + this->call_cancell_callback(); update_apply_status(this->invalidate_all_steps()); for (PrintObject *object : m_objects) { model_object_status.emplace(object->model_object()->id(), ModelObjectStatus::Deleted); @@ -854,7 +827,7 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co } else { // Reorder the objects, add new objects. // First stop background processing before shuffling or deleting the PrintObjects in the object list. - m_cancel_callback(); + this->call_cancell_callback(); this->invalidate_step(psGCodeExport); // Second create a new list of objects. std::vector model_objects_old(std::move(m_model.objects)); @@ -964,7 +937,7 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co model_object.assign_copy(model_object_new); } else if (support_blockers_differ || support_enforcers_differ) { // First stop background processing before shuffling or deleting the ModelVolumes in the ModelObject's list. - m_cancel_callback(); + this->call_cancell_callback(); // Invalidate just the supports step. auto range = print_object_status.equal_range(PrintObjectStatus(model_object.id())); for (auto it = range.first; it != range.second; ++ it) @@ -1024,7 +997,7 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co if (old.empty()) { // Simple case, just generate new instances. for (const PrintInstances &print_instances : new_print_instances) { - PrintObject *print_object = new PrintObject(this, model_object, model_object->raw_bounding_box()); + PrintObject *print_object = new PrintObject(this, model_object); print_object->set_trafo(print_instances.trafo); print_object->set_copies(print_instances.copies); print_object->config_apply(config); @@ -1043,7 +1016,7 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co for (; it_old != old.end() && transform3d_lower((*it_old)->trafo, new_instances.trafo); ++ it_old); if (it_old == old.end() || ! transform3d_equal((*it_old)->trafo, new_instances.trafo)) { // This is a new instance (or a set of instances with the same trafo). Just add it. - PrintObject *print_object = new PrintObject(this, model_object, model_object->raw_bounding_box()); + PrintObject *print_object = new PrintObject(this, model_object); print_object->set_trafo(new_instances.trafo); print_object->set_copies(new_instances.copies); print_object->config_apply(config); @@ -1066,7 +1039,7 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co } } if (m_objects != print_objects_new) { - m_cancel_callback(); + this->call_cancell_callback(); m_objects = print_objects_new; // Delete the PrintObjects marked as Unknown or Deleted. bool deleted_objects = false; @@ -1562,7 +1535,7 @@ void Print::process() for (PrintObject *obj : m_objects) obj->generate_support_material(); this->throw_if_canceled(); - if (! m_state.is_done(psSkirt)) { + if (! this->is_step_done(psSkirt)) { this->set_started(psSkirt); m_skirt.clear(); if (this->has_skirt()) { @@ -1572,7 +1545,7 @@ void Print::process() this->set_done(psSkirt); } this->throw_if_canceled(); - if (! m_state.is_done(psBrim)) { + if (! this->is_step_done(psBrim)) { this->set_started(psBrim); m_brim.clear(); if (m_config.brim_width > 0) { @@ -1582,7 +1555,7 @@ void Print::process() this->set_done(psBrim); } this->throw_if_canceled(); - if (! m_state.is_done(psWipeTower)) { + if (! this->is_step_done(psWipeTower)) { this->set_started(psWipeTower); m_wipe_tower_data.clear(); if (this->has_wipe_tower()) { @@ -1631,8 +1604,7 @@ void Print::_make_skirt() // prepended to the first 'n' layers (with 'n' = skirt_height). // $skirt_height_z in this case is the highest possible skirt height for safety. coordf_t skirt_height_z = 0.; - PrintObjectPtrs printable_objects = get_printable_objects(); - for (const PrintObject *object : printable_objects) { + for (const PrintObject *object : m_objects) { size_t skirt_layers = this->has_infinite_skirt() ? object->layer_count() : std::min(size_t(m_config.skirt_height.value), object->layer_count()); @@ -1641,7 +1613,7 @@ void Print::_make_skirt() // Collect points from all layers contained in skirt height. Points points; - for (const PrintObject *object : printable_objects) { + for (const PrintObject *object : m_objects) { Points object_points; // Get object layers up to skirt_height_z. for (const Layer *layer : object->m_layers) { @@ -1756,8 +1728,7 @@ void Print::_make_brim() // Brim is only printed on first layer and uses perimeter extruder. Flow flow = this->brim_flow(); Polygons islands; - PrintObjectPtrs printable_objects = get_printable_objects(); - for (PrintObject *object : printable_objects) { + for (PrintObject *object : m_objects) { Polygons object_islands; for (ExPolygon &expoly : object->m_layers.front()->slices.expolygons) object_islands.push_back(expoly.contour); diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index 705c41458e..dbf07369b2 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -1,15 +1,10 @@ #ifndef slic3r_Print_hpp_ #define slic3r_Print_hpp_ -#include "libslic3r.h" -#include -#include -#include -#include -#include +#include "PrintBase.hpp" + #include "BoundingBox.hpp" #include "Flow.hpp" -#include "PrintConfig.hpp" #include "Point.hpp" #include "Layer.hpp" #include "Model.hpp" @@ -18,13 +13,6 @@ #include "GCode/ToolOrdering.hpp" #include "GCode/WipeTower.hpp" -#include "tbb/atomic.h" -// tbb/mutex.h includes Windows, which in turn defines min/max macros. Convince Windows.h to not define these min/max macros. -#ifndef NOMINMAX - #define NOMINMAX -#endif -#include "tbb/mutex.h" - namespace Slic3r { class Print; @@ -42,116 +30,6 @@ enum PrintObjectStep { posInfill, posSupportMaterial, posCount, }; -class CanceledException : public std::exception { -public: - const char* what() const throw() { return "Background processing has been canceled"; } -}; - -// To be instantiated over PrintStep or PrintObjectStep enums. -template -class PrintState -{ -public: - PrintState() { for (size_t i = 0; i < COUNT; ++ i) m_state[i].store(INVALID, std::memory_order_relaxed); } - - enum State { - INVALID, - STARTED, - DONE, - }; - - // With full memory barrier. - bool is_done(StepType step) const { return m_state[step] == DONE; } - - // Set the step as started. Block on mutex while the Print / PrintObject / PrintRegion objects are being - // modified by the UI thread. - // This is necessary to block until the Print::apply_config() updates its state, which may - // influence the processing step being entered. - void set_started(StepType step, tbb::mutex &mtx) { - mtx.lock(); - m_state[step].store(STARTED, std::memory_order_relaxed); - mtx.unlock(); - } - - // Set the step as done. Block on mutex while the Print / PrintObject / PrintRegion objects are being - // modified by the UI thread. - void set_done(StepType step, tbb::mutex &mtx) { - mtx.lock(); - m_state[step].store(DONE, std::memory_order_relaxed); - mtx.unlock(); - } - - // Make the step invalid. - // The provided mutex should be locked at this point, guarding access to m_state. - // In case the step has already been entered or finished, cancel the background - // processing by calling the cancel callback. - template - bool invalidate(StepType step, tbb::mutex &mtx, CancelationCallback cancel) { - bool invalidated = m_state[step].load(std::memory_order_relaxed) != INVALID; - if (invalidated) { -#if 0 - if (mtx.state != mtx.HELD) { - printf("Not held!\n"); - } -#endif - // Raise the mutex, so that the following cancel() callback could cancel - // the background processing. - mtx.unlock(); - cancel(); - m_state[step] = INVALID; - mtx.lock(); - } - return invalidated; - } - - template - bool invalidate_multiple(StepTypeIterator step_begin, StepTypeIterator step_end, tbb::mutex &mtx, CancelationCallback cancel) { - bool invalidated = false; - for (StepTypeIterator it = step_begin; ! invalidated && it != step_end; ++ it) - invalidated = m_state[*it].load(std::memory_order_relaxed) != INVALID; - if (invalidated) { -#if 0 - if (mtx.state != mtx.HELD) { - printf("Not held!\n"); - } -#endif - // Raise the mutex, so that the following cancel() callback could cancel - // the background processing. - mtx.unlock(); - cancel(); - for (StepTypeIterator it = step_begin; it != step_end; ++ it) - m_state[*it] = INVALID; - mtx.lock(); - } - return invalidated; - } - - // Make all steps invalid. - // The provided mutex should be locked at this point, guarding access to m_state. - // In case any step has already been entered or finished, cancel the background - // processing by calling the cancel callback. - template - bool invalidate_all(tbb::mutex &mtx, CancelationCallback cancel) { - bool invalidated = false; - for (size_t i = 0; i < COUNT; ++ i) - if (m_state[i].load(std::memory_order_relaxed) != INVALID) { - invalidated = true; - break; - } - if (invalidated) { - mtx.unlock(); - cancel(); - for (size_t i = 0; i < COUNT; ++ i) - m_state[i].store(INVALID, std::memory_order_relaxed); - mtx.lock(); - } - return invalidated; - } - -private: - std::atomic m_state[COUNT]; -}; - // A PrintRegion object represents a group of volumes to print // sharing the same config (including the same assigned extruder(s)) class PrintRegion @@ -193,9 +71,10 @@ typedef std::vector LayerPtrs; typedef std::vector SupportLayerPtrs; class BoundingBoxf3; // TODO: for temporary constructor parameter -class PrintObject +class PrintObject : public PrintObjectBaseWithState { - friend class Print; +private: // Prevents erroneous use by other classes. + typedef PrintObjectBaseWithState Inherited; public: // vector of (vectors of volume ids), indexed by region_id @@ -218,25 +97,13 @@ public: Vec3crd size; // XYZ in scaled coordinates - Print* print() { return m_print; } - const Print* print() const { return m_print; } - ModelObject* model_object() { return m_model_object; } const ModelObject* model_object() const { return m_model_object; } + ModelObject* model_object() { return m_model_object; } const PrintObjectConfig& config() const { return m_config; } - void config_apply(const ConfigBase &other, bool ignore_nonexistent = false) { this->m_config.apply(other, ignore_nonexistent); } - void config_apply_only(const ConfigBase &other, const t_config_option_keys &keys, bool ignore_nonexistent = false) { this->m_config.apply_only(other, keys, ignore_nonexistent); } const LayerPtrs& layers() const { return m_layers; } const SupportLayerPtrs& support_layers() const { return m_support_layers; } - const Transform3d& trafo() const { return m_trafo; } - void set_trafo(const Transform3d& trafo) { m_trafo = trafo; } - const Points& copies() const { return m_copies; } - bool add_copy(const Vec2d &point); - bool delete_last_copy(); - bool delete_all_copies() { return this->set_copies(Points()); } - bool set_copies(const Points &points); - bool reload_model_instances(); // since the object is aligned to origin, bounding box coincides with size BoundingBox bounding_box() const { return BoundingBox(Point(0,0), to_2d(this->size)); } @@ -268,12 +135,6 @@ public: // methods for handling state bool invalidate_state_by_config_options(const std::vector &opt_keys); - bool invalidate_step(PrintObjectStep step); - template - bool invalidate_steps(StepTypeIterator step_begin, StepTypeIterator step_end) { return m_state.invalidate_multiple(step_begin, step_end, this->cancel_mutex(), this->cancel_callback()); } - bool invalidate_steps(std::initializer_list il) { return m_state.invalidate_multiple(il.begin(), il.end(), this->cancel_mutex(), this->cancel_callback()); } - bool invalidate_all_steps() { return m_state.invalidate_all(this->cancel_mutex(), this->cancel_callback()); } - bool is_step_done(PrintObjectStep step) const { return m_state.is_done(step); } // To be used over the layer_height_profile of both the PrintObject and ModelObject // to initialize the height profile with the height ranges. @@ -300,6 +161,20 @@ public: std::vector slice_support_enforcers() const; std::vector slice_support_blockers() const; +protected: + // to be called from Print only. + friend class Print; + + PrintObject(Print* print, ModelObject* model_object); + ~PrintObject() {} + + void config_apply(const ConfigBase &other, bool ignore_nonexistent = false) { this->m_config.apply(other, ignore_nonexistent); } + void config_apply_only(const ConfigBase &other, const t_config_option_keys &keys, bool ignore_nonexistent = false) { this->m_config.apply_only(other, keys, ignore_nonexistent); } + void set_trafo(const Transform3d& trafo) { m_trafo = trafo; } + bool set_copies(const Points &points); + // Invalidates the step, and its depending steps in PrintObject and Print. + bool invalidate_step(PrintObjectStep step); + private: void make_perimeters(); void prepare_infill(); @@ -320,12 +195,6 @@ private: void combine_infill(); void _generate_support_material(); - bool is_printable() const { return ! m_copies.empty(); } - // Implemented in cpp due to cyclic dependencies between Print and PrintObject. - tbb::mutex& cancel_mutex(); - std::function cancel_callback(); - - Print *m_print; ModelObject *m_model_object; PrintObjectConfig m_config; // Translation in Z + Rotation + Scaling / Mirroring. @@ -340,15 +209,6 @@ private: LayerPtrs m_layers; SupportLayerPtrs m_support_layers; - PrintState m_state; - - // TODO: call model_object->get_bounding_box() instead of accepting - // parameter - PrintObject(Print* print, ModelObject* model_object, const BoundingBoxf3 &modobj_bbox); - ~PrintObject() {} - - void set_started(PrintObjectStep step); - void set_done(PrintObjectStep step); std::vector _slice_region(size_t region_id, const std::vector &z, bool modifier); std::vector _slice_volumes(const std::vector &z, const std::vector &volumes) const; }; @@ -410,33 +270,30 @@ typedef std::vector PrintObjectPtrs; typedef std::vector PrintRegionPtrs; // The complete print tray with possibly multiple objects. -class Print +class Print : public PrintBaseWithState { +private: // Prevents erroneous use by other classes. + typedef PrintBaseWithState Inherited; + public: - Print() { restart(); } - ~Print() { clear_objects(); } + Print() {} + virtual ~Print() { this->clear(); } + + PrinterTechnology technology() const noexcept { return ptFFF; } // Methods, which change the state of Print / PrintObject / PrintRegion. // The following methods are synchronized with process() and export_gcode(), // so that process() and export_gcode() may be called from a background thread. // In case the following methods need to modify data processed by process() or export_gcode(), // a cancellation callback is executed to stop the background processing before the operation. - void clear_objects(); - void delete_object(size_t idx); + void clear() override; + + ApplyStatus apply(const Model &model, const DynamicPrintConfig &config) override; + + // The following three methods are used by the Perl tests only. Get rid of them! void reload_object(size_t idx); - bool reload_model_instances(); void add_model_object(ModelObject* model_object, int idx = -1); bool apply_config(DynamicPrintConfig config); - enum ApplyStatus { - // No change after the Print::apply() call. - APPLY_STATUS_UNCHANGED, - // Some of the Print / PrintObject / PrintObjectInstance data was changed, - // but no result was invalidated (only data influencing not yet calculated results were changed). - APPLY_STATUS_CHANGED, - // Some data was changed, which in turn invalidated already calculated steps. - APPLY_STATUS_INVALIDATED, - }; - ApplyStatus apply(const Model &model, const DynamicPrintConfig &config); void process(); void export_gcode(const std::string &path_template, GCodePreviewData *preview_data); @@ -444,12 +301,11 @@ public: void export_png(const std::string &dirpath); // methods for handling state - bool is_step_done(PrintStep step) const { return m_state.is_done(step); } + bool is_step_done(PrintStep step) const { return Inherited::is_step_done(step); } bool is_step_done(PrintObjectStep step) const; bool has_infinite_skirt() const; bool has_skirt() const; - PrintObjectPtrs get_printable_objects() const; float get_wipe_tower_depth() const { return m_wipe_tower_data.depth; } // Returns an empty string if valid, otherwise returns an error message. @@ -482,7 +338,7 @@ public: unsigned int num_object_instances() const; // Returns extruder this eec should be printed with, according to PrintRegion config: - static int get_extruder(const ExtrusionEntityCollection& fill, const PrintRegion ®ion); + static int get_extruder(const ExtrusionEntityCollection& fill, const PrintRegion ®ion); const ExtrusionEntityCollection& skirt() const { return m_skirt; } const ExtrusionEntityCollection& brim() const { return m_brim; } @@ -496,69 +352,24 @@ public: std::string output_filename() const; std::string output_filepath(const std::string &path) const; - typedef std::function status_callback_type; - // Default status console print out in the form of percent => message. - void set_status_default() { m_status_callback = nullptr; } - // No status output or callback whatsoever, useful mostly for automatic tests. - void set_status_silent() { m_status_callback = [](int, const std::string&){}; } - // Register a custom status callback. - void set_status_callback(status_callback_type cb) { m_status_callback = cb; } - // Calls a registered callback to update the status, or print out the default message. - void set_status(int percent, const std::string &message) { - if (m_status_callback) m_status_callback(percent, message); - else printf("%d => %s\n", percent, message.c_str()); - } - - typedef std::function cancel_callback_type; - // Various methods will call this callback to stop the background processing (the Print::process() call) - // in case a successive change of the Print / PrintObject / PrintRegion instances changed - // the state of the finished or running calculations. - void set_cancel_callback(cancel_callback_type cancel_callback) { m_cancel_callback = cancel_callback; } - // Has the calculation been canceled? - enum CancelStatus { - // No cancelation, background processing should run. - NOT_CANCELED = 0, - // Canceled by user from the user interface (user pressed the "Cancel" button or user closed the application). - CANCELED_BY_USER = 1, - // Canceled internally from Print::apply() through the Print/PrintObject::invalidate_step() or ::invalidate_all_steps(). - CANCELED_INTERNAL = 2 - }; - CancelStatus cancel_status() const { return m_cancel_status; } - // Has the calculation been canceled? - bool canceled() const { return m_cancel_status != NOT_CANCELED; } - // Cancel the running computation. Stop execution of all the background threads. - void cancel() { m_cancel_status = CANCELED_BY_USER; } - void cancel_internal() { m_cancel_status = CANCELED_INTERNAL; } - // Cancel the running computation. Stop execution of all the background threads. - void restart() { m_cancel_status = NOT_CANCELED; } - // Accessed by SupportMaterial const PrintRegion* get_region(size_t idx) const { return m_regions[idx]; } protected: - void set_started(PrintStep step) { m_state.set_started(step, m_mutex); throw_if_canceled(); } - void set_done(PrintStep step) { m_state.set_done(step, m_mutex); throw_if_canceled(); } - bool invalidate_step(PrintStep step); - template - bool invalidate_steps(StepTypeIterator step_begin, StepTypeIterator step_end) { return m_state.invalidate_multiple(step_begin, step_end, m_mutex, m_cancel_callback); } - bool invalidate_steps(std::initializer_list il) { return m_state.invalidate_multiple(il.begin(), il.end(), m_mutex, m_cancel_callback); } - bool invalidate_all_steps() { return m_state.invalidate_all(m_mutex, m_cancel_callback); } - // methods for handling regions PrintRegion* get_region(size_t idx) { return m_regions[idx]; } PrintRegion* add_region(); PrintRegion* add_region(const PrintRegionConfig &config); + // Invalidates the step, and its depending steps in Print. + bool invalidate_step(PrintStep step); + private: // Update "scale", "input_filename", "input_filename_base" placeholders from the current m_objects. void update_object_placeholders(); bool invalidate_state_by_config_options(const std::vector &opt_keys); - // If the background processing stop was requested, throw CanceledException. - // To be called by the worker thread and its sub-threads (mostly launched on the TBB thread pool) regularly. - void throw_if_canceled() const { if (m_cancel_status) throw CanceledException(); } - void _make_skirt(); void _make_brim(); void _make_wipe_tower(); @@ -567,19 +378,6 @@ private: // Declared here to have access to Model / ModelObject / ModelInstance static void model_volume_list_update_supports(ModelObject &model_object_dst, const ModelObject &model_object_src); - PrintState m_state; - // Mutex used for synchronization of the worker thread with the UI thread: - // The mutex will be used to guard the worker thread against entering a stage - // while the data influencing the stage is modified. - mutable tbb::mutex m_mutex; - - tbb::atomic m_cancel_status; - // Callback to be evoked regularly to update state of the UI thread. - status_callback_type m_status_callback; - - // Callback to be evoked to stop the background processing before a state is updated. - cancel_callback_type m_cancel_callback = [](){}; - Model m_model; PrintConfig m_config; PrintObjectConfig m_default_object_config; @@ -604,6 +402,6 @@ private: friend class PrintObject; }; -} +} /* slic3r_Print_hpp_ */ #endif diff --git a/src/libslic3r/PrintBase.cpp b/src/libslic3r/PrintBase.cpp new file mode 100644 index 0000000000..d4fffca948 --- /dev/null +++ b/src/libslic3r/PrintBase.cpp @@ -0,0 +1,16 @@ +#include "PrintBase.hpp" + +namespace Slic3r +{ + +tbb::mutex& PrintObjectBase::cancel_mutex(PrintBase *print) +{ + return print->cancel_mutex(); +} + +std::function PrintObjectBase::cancel_callback(PrintBase *print) +{ + return print->cancel_callback(); +} + +} // namespace Slic3r diff --git a/src/libslic3r/PrintBase.hpp b/src/libslic3r/PrintBase.hpp new file mode 100644 index 0000000000..47a849e84e --- /dev/null +++ b/src/libslic3r/PrintBase.hpp @@ -0,0 +1,297 @@ +#ifndef slic3r_PrintBase_hpp_ +#define slic3r_PrintBase_hpp_ + +#include "libslic3r.h" +#include +#include +#include +#include +#include + +#include "tbb/atomic.h" +// tbb/mutex.h includes Windows, which in turn defines min/max macros. Convince Windows.h to not define these min/max macros. +#ifndef NOMINMAX + #define NOMINMAX +#endif +#include "tbb/mutex.h" + +#include "Model.hpp" +#include "PrintConfig.hpp" + +namespace Slic3r { + +class CanceledException : public std::exception { +public: + const char* what() const throw() { return "Background processing has been canceled"; } +}; + +// To be instantiated over PrintStep or PrintObjectStep enums. +template +class PrintState +{ +public: + PrintState() { for (size_t i = 0; i < COUNT; ++ i) m_state[i].store(INVALID, std::memory_order_relaxed); } + + enum State { + INVALID, + STARTED, + DONE, + }; + + // With full memory barrier. + bool is_done(StepType step) const { return m_state[step] == DONE; } + + // Set the step as started. Block on mutex while the Print / PrintObject / PrintRegion objects are being + // modified by the UI thread. + // This is necessary to block until the Print::apply_config() updates its state, which may + // influence the processing step being entered. + void set_started(StepType step, tbb::mutex &mtx) { + mtx.lock(); + m_state[step].store(STARTED, std::memory_order_relaxed); + mtx.unlock(); + } + + // Set the step as done. Block on mutex while the Print / PrintObject / PrintRegion objects are being + // modified by the UI thread. + void set_done(StepType step, tbb::mutex &mtx) { + mtx.lock(); + m_state[step].store(DONE, std::memory_order_relaxed); + mtx.unlock(); + } + + // Make the step invalid. + // The provided mutex should be locked at this point, guarding access to m_state. + // In case the step has already been entered or finished, cancel the background + // processing by calling the cancel callback. + template + bool invalidate(StepType step, tbb::mutex &mtx, CancelationCallback cancel) { + bool invalidated = m_state[step].load(std::memory_order_relaxed) != INVALID; + if (invalidated) { +#if 0 + if (mtx.state != mtx.HELD) { + printf("Not held!\n"); + } +#endif + // Raise the mutex, so that the following cancel() callback could cancel + // the background processing. + mtx.unlock(); + cancel(); + m_state[step] = INVALID; + mtx.lock(); + } + return invalidated; + } + + template + bool invalidate_multiple(StepTypeIterator step_begin, StepTypeIterator step_end, tbb::mutex &mtx, CancelationCallback cancel) { + bool invalidated = false; + for (StepTypeIterator it = step_begin; ! invalidated && it != step_end; ++ it) + invalidated = m_state[*it].load(std::memory_order_relaxed) != INVALID; + if (invalidated) { +#if 0 + if (mtx.state != mtx.HELD) { + printf("Not held!\n"); + } +#endif + // Raise the mutex, so that the following cancel() callback could cancel + // the background processing. + mtx.unlock(); + cancel(); + for (StepTypeIterator it = step_begin; it != step_end; ++ it) + m_state[*it] = INVALID; + mtx.lock(); + } + return invalidated; + } + + // Make all steps invalid. + // The provided mutex should be locked at this point, guarding access to m_state. + // In case any step has already been entered or finished, cancel the background + // processing by calling the cancel callback. + template + bool invalidate_all(tbb::mutex &mtx, CancelationCallback cancel) { + bool invalidated = false; + for (size_t i = 0; i < COUNT; ++ i) + if (m_state[i].load(std::memory_order_relaxed) != INVALID) { + invalidated = true; + break; + } + if (invalidated) { + mtx.unlock(); + cancel(); + for (size_t i = 0; i < COUNT; ++ i) + m_state[i].store(INVALID, std::memory_order_relaxed); + mtx.lock(); + } + return invalidated; + } + +private: + std::atomic m_state[COUNT]; +}; + +class PrintBase; + +class PrintObjectBase +{ +protected: + virtual ~PrintObjectBase() {} + // Declared here to allow access from PrintBase through friendship. + static tbb::mutex& cancel_mutex(PrintBase *print); + static std::function cancel_callback(PrintBase *print); +}; + +/** + * @brief Printing involves slicing and export of device dependent instructions. + * + * Every technology has a potentially different set of requirements for + * slicing, support structures and output print instructions. The pipeline + * however remains roughly the same: + * slice -> convert to instructions -> send to printer + * + * The PrintBase class will abstract this flow for different technologies. + * + */ +class PrintBase +{ +public: + PrintBase() { this->restart(); } + inline virtual ~PrintBase() {} + + virtual PrinterTechnology technology() const noexcept = 0; + + // Reset the print status including the copy of the Model / ModelObject hierarchy. + virtual void clear() = 0; + + enum ApplyStatus { + // No change after the Print::apply() call. + APPLY_STATUS_UNCHANGED, + // Some of the Print / PrintObject / PrintObjectInstance data was changed, + // but no result was invalidated (only data influencing not yet calculated results were changed). + APPLY_STATUS_CHANGED, + // Some data was changed, which in turn invalidated already calculated steps. + APPLY_STATUS_INVALIDATED, + }; + virtual ApplyStatus apply(const Model &model, const DynamicPrintConfig &config) = 0; + + virtual void process() = 0; + + typedef std::function status_callback_type; + // Default status console print out in the form of percent => message. + void set_status_default() { m_status_callback = nullptr; } + // No status output or callback whatsoever, useful mostly for automatic tests. + void set_status_silent() { m_status_callback = [](int, const std::string&){}; } + // Register a custom status callback. + void set_status_callback(status_callback_type cb) { m_status_callback = cb; } + // Calls a registered callback to update the status, or print out the default message. + void set_status(int percent, const std::string &message) { + if (m_status_callback) m_status_callback(percent, message); + else printf("%d => %s\n", percent, message.c_str()); + } + + typedef std::function cancel_callback_type; + // Various methods will call this callback to stop the background processing (the Print::process() call) + // in case a successive change of the Print / PrintObject / PrintRegion instances changed + // the state of the finished or running calculations. + void set_cancel_callback(cancel_callback_type cancel_callback) { m_cancel_callback = cancel_callback; } + // Has the calculation been canceled? + enum CancelStatus { + // No cancelation, background processing should run. + NOT_CANCELED = 0, + // Canceled by user from the user interface (user pressed the "Cancel" button or user closed the application). + CANCELED_BY_USER = 1, + // Canceled internally from Print::apply() through the Print/PrintObject::invalidate_step() or ::invalidate_all_steps(). + CANCELED_INTERNAL = 2 + }; + CancelStatus cancel_status() const { return m_cancel_status; } + // Has the calculation been canceled? + bool canceled() const { return m_cancel_status != NOT_CANCELED; } + // Cancel the running computation. Stop execution of all the background threads. + void cancel() { m_cancel_status = CANCELED_BY_USER; } + void cancel_internal() { m_cancel_status = CANCELED_INTERNAL; } + // Cancel the running computation. Stop execution of all the background threads. + void restart() { m_cancel_status = NOT_CANCELED; } + +protected: + friend class PrintObjectBase; + + tbb::mutex& cancel_mutex() { return m_cancel_mutex; } + std::function cancel_callback() { return m_cancel_callback; } + void call_cancell_callback() { m_cancel_callback(); } + + // If the background processing stop was requested, throw CanceledException. + // To be called by the worker thread and its sub-threads (mostly launched on the TBB thread pool) regularly. + void throw_if_canceled() const { if (m_cancel_status) throw CanceledException(); } + +private: + tbb::atomic m_cancel_status; + // Callback to be evoked regularly to update state of the UI thread. + status_callback_type m_status_callback; + + // Callback to be evoked to stop the background processing before a state is updated. + cancel_callback_type m_cancel_callback = [](){}; + + // Mutex used for synchronization of the worker thread with the UI thread: + // The mutex will be used to guard the worker thread against entering a stage + // while the data influencing the stage is modified. + mutable tbb::mutex m_cancel_mutex; +}; + +template +class PrintBaseWithState : public PrintBase +{ +public: + bool is_step_done(PrintStepEnum step) const { return m_state.is_done(step); } + +protected: + void set_started(PrintStepEnum step) { m_state.set_started(step, this->cancel_mutex()); throw_if_canceled(); } + void set_done(PrintStepEnum step) { m_state.set_done(step, this->cancel_mutex()); throw_if_canceled(); } + bool invalidate_step(PrintStepEnum step) + { return m_state.invalidate(step, this->cancel_mutex(), this->cancel_callback()); } + template + bool invalidate_steps(StepTypeIterator step_begin, StepTypeIterator step_end) + { return m_state.invalidate_multiple(step_begin, step_end, this->cancel_mutex(), this->cancel_callback()); } + bool invalidate_steps(std::initializer_list il) + { return m_state.invalidate_multiple(il.begin(), il.end(), this->cancel_mutex(), this->cancel_callback()); } + bool invalidate_all_steps() + { return m_state.invalidate_all(this->cancel_mutex(), this->cancel_callback()); } + +private: + PrintState m_state; +}; + +template +class PrintObjectBaseWithState : public PrintObjectBase +{ +public: + Print* print() { return m_print; } + const Print* print() const { return m_print; } + + bool is_step_done(PrintObjectStepEnum step) const { return m_state.is_done(step); } + +protected: + PrintObjectBaseWithState(PrintType *print) : m_print(print) {} + + void set_started(PrintObjectStepEnum step) { m_state.set_started(step, PrintObjectBase::cancel_mutex(m_print)); } + void set_done(PrintObjectStepEnum step) { m_state.set_done(step, PrintObjectBase::cancel_mutex(m_print)); } + + bool invalidate_step(PrintObjectStepEnum step) + { return m_state.invalidate(step, PrintObjectBase::cancel_mutex(m_print), PrintObjectBase::cancel_callback(m_print)); } + template + bool invalidate_steps(StepTypeIterator step_begin, StepTypeIterator step_end) + { return m_state.invalidate_multiple(step_begin, step_end, PrintObjectBase::cancel_mutex(m_print), PrintObjectBase::cancel_callback(m_print)); } + bool invalidate_steps(std::initializer_list il) + { return m_state.invalidate_multiple(il.begin(), il.end(), PrintObjectBase::cancel_mutex(m_print), PrintObjectBase::cancel_callback(m_print)); } + bool invalidate_all_steps() { return m_state.invalidate_all(PrintObjectBase::cancel_mutex(m_print), PrintObjectBase::cancel_callback(m_print)); } + +protected: + friend typename PrintType; + PrintType *m_print; + +private: + PrintState m_state; +}; + +} // namespace Slic3r + +#endif /* slic3r_PrintBase_hpp_ */ diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 45b2689bbb..f0361ba01d 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -34,9 +34,9 @@ namespace Slic3r { -PrintObject::PrintObject(Print* print, ModelObject* model_object, const BoundingBoxf3 &modobj_bbox) : +PrintObject::PrintObject(Print* print, ModelObject* model_object) : + PrintObjectBaseWithState(print), typed_slices(false), - m_print(print), m_model_object(model_object), size(Vec3crd::Zero()), layer_height_profile_valid(false) @@ -49,42 +49,27 @@ PrintObject::PrintObject(Print* print, ModelObject* model_object, const Bounding // don't assume it's already aligned and we don't alter the original position in model. // We store the XY translation so that we can place copies correctly in the output G-code // (copies are expressed in G-code coordinates and this translation is not publicly exposed). + const BoundingBoxf3 modobj_bbox = model_object->raw_bounding_box(); m_copies_shift = Point::new_scale(modobj_bbox.min(0), modobj_bbox.min(1)); // Scale the object size and store it this->size = (modobj_bbox.size() * (1. / SCALING_FACTOR)).cast(); } - this->reload_model_instances(); + { + Points copies; + copies.reserve(m_model_object->instances.size()); + for (const ModelInstance *mi : m_model_object->instances) { + assert(mi->is_printable()); + const Vec3d& offset = mi->get_offset(); + copies.emplace_back(Point::new_scale(offset(0), offset(1))); + } + this->set_copies(copies); + } + this->layer_height_ranges = model_object->layer_height_ranges; this->layer_height_profile = model_object->layer_height_profile; } -void PrintObject::set_started(PrintObjectStep step) -{ - m_state.set_started(step, m_print->m_mutex); -} - -void PrintObject::set_done(PrintObjectStep step) -{ - m_state.set_done(step, m_print->m_mutex); -} - -bool PrintObject::add_copy(const Vec2d &point) -{ - tbb::mutex::scoped_lock lock(m_print->m_mutex); - Points points = m_copies; - points.push_back(Point::new_scale(point(0), point(1))); - return this->set_copies(points); -} - -bool PrintObject::delete_last_copy() -{ - tbb::mutex::scoped_lock lock(m_print->m_mutex); - Points points = m_copies; - points.pop_back(); - return this->set_copies(points); -} - bool PrintObject::set_copies(const Points &points) { // Order copies with a nearest-neighbor search. @@ -107,21 +92,6 @@ bool PrintObject::set_copies(const Points &points) return invalidated; } -bool PrintObject::reload_model_instances() -{ - Points copies; - copies.reserve(m_model_object->instances.size()); - for (const ModelInstance *mi : m_model_object->instances) - { - if (mi->is_printable()) - { - const Vec3d& offset = mi->get_offset(); - copies.emplace_back(Point::new_scale(offset(0), offset(1))); - } - } - return this->set_copies(copies); -} - // 1) Decides Z positions of the layers, // 2) Initializes layers and their regions // 3) Slices the object meshes @@ -388,9 +358,6 @@ void PrintObject::prepare_infill() void PrintObject::infill() { - if (! this->is_printable()) - return; - // prerequisites this->prepare_infill(); @@ -583,7 +550,7 @@ bool PrintObject::invalidate_state_by_config_options(const std::vectorm_mutex, m_print->m_cancel_callback); + bool invalidated = Inherited::invalidate_step(step); // propagate to dependent steps if (step == posPerimeters) { @@ -1732,9 +1699,6 @@ void PrintObject::_simplify_slices(double distance) void PrintObject::_make_perimeters() { - if (!this->is_printable()) - return; - if (this->is_step_done(posPerimeters)) return; this->set_started(posPerimeters); @@ -2226,9 +2190,6 @@ void PrintObject::combine_infill() void PrintObject::_generate_support_material() { - if (!this->is_printable()) - return; - PrintObjectSupportMaterial support_material(this, PrintObject::slicing_parameters()); support_material.generate(*this); } @@ -2251,15 +2212,4 @@ void PrintObject::adjust_layer_height_profile(coordf_t z, coordf_t layer_thickne layer_height_profile_valid = false; } -tbb::mutex& PrintObject::cancel_mutex() -{ - return m_print->m_mutex; -} - -std::function PrintObject::cancel_callback() -{ - return m_print->m_cancel_callback; -} - - } // namespace Slic3r diff --git a/src/slic3r.cpp b/src/slic3r.cpp index 441a6ab804..e9fa54ce03 100644 --- a/src/slic3r.cpp +++ b/src/slic3r.cpp @@ -216,12 +216,10 @@ int main(int argc, char **argv) } if (outfile.empty()) outfile = model.objects.front()->input_file + ".gcode"; - for (auto* mo : model.objects) { + for (auto* mo : model.objects) print.auto_assign_extruders(mo); - print.add_model_object(mo); - } print_config.normalize(); - print.apply_config(print_config); + print.apply(model, print_config); std::string err = print.validate(); if (err.empty()) print.export_gcode(outfile, nullptr); diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.cpp b/src/slic3r/GUI/BackgroundSlicingProcess.cpp index cd438ebe56..62a6bb8a87 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.cpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.cpp @@ -178,6 +178,14 @@ bool BackgroundSlicingProcess::stop() return true; } +bool BackgroundSlicingProcess::reset() +{ + bool stopped = this->stop(); + this->reset_export(); + m_print->clear(); + return stopped; +} + // To be called by Print::apply() through the Print::m_cancel_callback to stop the background // processing before changing any data of running or finalized milestones. // This function shall not trigger any UI update through the wxWidgets event. diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.hpp b/src/slic3r/GUI/BackgroundSlicingProcess.hpp index 6b92e85167..6b589739ec 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.hpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.hpp @@ -43,6 +43,9 @@ public: // Cancel the background processing. Returns false if the background processing was not running. // A stopped background processing may be restarted with start(). bool stop(); + // Cancel the background processing and reset the print. Returns false if the background processing was not running. + // Useful when the Model or configuration is being changed drastically. + bool reset(); // Apply config over the print. Returns false, if the new config values caused any of the already // processed steps to be invalidated, therefore the task will need to be restarted. diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 7e91276d4d..5927c270d9 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1434,8 +1434,9 @@ void Plater::priv::reset() if (_3DScene::is_layers_editing_enabled(canvas3D)) _3DScene::enable_layers_editing(canvas3D, false); + // Stop and reset the Print content. + this->background_process.reset(); model.clear_objects(); -// print.clear_objects(); // Delete all objects from list on c++ side sidebar->obj_list()->delete_all_objects_from_list(); @@ -2001,10 +2002,8 @@ void Plater::decrease_instances(size_t num) ModelObject* model_object = p->model.objects[obj_idx]; if (model_object->instances.size() > num) { - for (size_t i = 0; i < num; i++) { + for (size_t i = 0; i < num; ++ i) model_object->delete_last_instance(); -// p->print.get_object(obj_idx)->delete_last_copy(); - } sidebar().obj_list()->decrease_object_instances(obj_idx, num); } else { diff --git a/xs/xsp/Model.xsp b/xs/xsp/Model.xsp index 11fa7e9206..ffcb81defc 100644 --- a/xs/xsp/Model.xsp +++ b/xs/xsp/Model.xsp @@ -92,10 +92,6 @@ bool store_stl(char *path, bool binary) %code%{ TriangleMesh mesh = THIS->mesh(); RETVAL = Slic3r::store_stl(path, &mesh, binary); %}; - bool store_amf(char *path, Print* print, bool export_print_config) - %code%{ RETVAL = Slic3r::store_amf(path, THIS, print, export_print_config); %}; - bool store_3mf(char *path, Print* print, bool export_print_config) - %code%{ RETVAL = Slic3r::store_3mf(path, THIS, print, export_print_config); %}; %{ diff --git a/xs/xsp/Print.xsp b/xs/xsp/Print.xsp index cf3b67931f..f6edb5d64c 100644 --- a/xs/xsp/Print.xsp +++ b/xs/xsp/Print.xsp @@ -58,10 +58,6 @@ _constant() Points _shifted_copies() %code%{ RETVAL = THIS->copies(); %}; - bool add_copy(Vec2d* point) - %code%{ RETVAL = THIS->add_copy(*point); %}; - bool delete_last_copy(); - bool reload_model_instances(); void set_layer_height_ranges(t_layer_height_ranges layer_height_ranges) %code%{ THIS->layer_height_ranges = layer_height_ranges; %}; @@ -109,12 +105,9 @@ _constant() %code%{ RETVAL = THIS->wipe_tower_data().number_of_toolchanges; %}; PrintObjectPtrs* objects() %code%{ RETVAL = const_cast(&THIS->objects()); %}; - void clear_objects(); Ref get_object(int idx) %code%{ RETVAL = THIS->objects()[idx]; %}; - void delete_object(int idx); void reload_object(int idx); - bool reload_model_instances(); size_t object_count() %code%{ RETVAL = THIS->objects().size(); %}; From 71c2d343082eef881d599fcceccde7e4a72f6c4f Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 8 Nov 2018 14:55:25 +0100 Subject: [PATCH 08/10] Fixed crash in void GLGizmoSlaSupports::update_mesh() --- src/slic3r/GUI/GLGizmo.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/GLGizmo.cpp b/src/slic3r/GUI/GLGizmo.cpp index 7ff0cdfd89..afab8d6297 100644 --- a/src/slic3r/GUI/GLGizmo.cpp +++ b/src/slic3r/GUI/GLGizmo.cpp @@ -1596,8 +1596,9 @@ void GLGizmoSlaSupports::update_mesh() { Eigen::MatrixXf& V = m_V; Eigen::MatrixXi& F = m_F; - const stl_file& stl = m_model_object->mesh().stl; - V.resize(3*stl.stats.number_of_facets, 3); + TriangleMesh mesh(m_model_object->mesh()); + const stl_file& stl = mesh.stl; + V.resize(3 * stl.stats.number_of_facets, 3); F.resize(stl.stats.number_of_facets, 3); for (unsigned int i=0; i Date: Thu, 8 Nov 2018 14:57:42 +0100 Subject: [PATCH 09/10] Fix of friend declaration on a template parameter, according to C++11 --- src/libslic3r/PrintBase.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libslic3r/PrintBase.hpp b/src/libslic3r/PrintBase.hpp index 47a849e84e..52e5c89898 100644 --- a/src/libslic3r/PrintBase.hpp +++ b/src/libslic3r/PrintBase.hpp @@ -285,7 +285,7 @@ protected: bool invalidate_all_steps() { return m_state.invalidate_all(PrintObjectBase::cancel_mutex(m_print), PrintObjectBase::cancel_callback(m_print)); } protected: - friend typename PrintType; + friend PrintType; PrintType *m_print; private: From 05b1ed3c2a3198419a06f75ee2220719ee5d7fcf Mon Sep 17 00:00:00 2001 From: bubnikv Date: Thu, 8 Nov 2018 15:02:47 +0100 Subject: [PATCH 10/10] Fixed a compilation issue on OSX --- src/libslic3r/Config.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libslic3r/Config.hpp b/src/libslic3r/Config.hpp index 2d8d049bae..0a2fbcb5f5 100644 --- a/src/libslic3r/Config.hpp +++ b/src/libslic3r/Config.hpp @@ -13,6 +13,7 @@ #include "libslic3r.h" #include "Point.hpp" +#include #include namespace Slic3r {