diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 335e034c4..c9a097aea 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -1244,16 +1244,26 @@ size_t ModelVolume::split(unsigned int max_extruders) std::string name = this->name; Model::reset_auto_extruder_id(); +#if ENABLE_MODELVOLUME_TRANSFORM + Vec3d offset = this->get_offset(); +#endif // ENABLE_MODELVOLUME_TRANSFORM for (TriangleMesh *mesh : meshptrs) { mesh->repair(); if (idx == 0) + { this->mesh = std::move(*mesh); + this->calculate_convex_hull(); + } else - this->object->volumes.insert(this->object->volumes.begin() + (++ ivolume), new ModelVolume(object, *this, std::move(*mesh))); - char str_idx[64]; - sprintf(str_idx, "_%d", idx + 1); - this->object->volumes[ivolume]->name = name + str_idx; + this->object->volumes.insert(this->object->volumes.begin() + (++ivolume), new ModelVolume(object, *this, std::move(*mesh))); + +#if ENABLE_MODELVOLUME_TRANSFORM + this->object->volumes[ivolume]->set_offset(Vec3d::Zero()); + this->object->volumes[ivolume]->center_geometry(); + this->object->volumes[ivolume]->translate(offset); +#endif // ENABLE_MODELVOLUME_TRANSFORM + this->object->volumes[ivolume]->name = name + "_" + std::to_string(idx + 1); this->object->volumes[ivolume]->config.set_deserialize("extruder", Model::get_auto_extruder_id_as_string(max_extruders)); delete mesh; ++ idx; diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index 7d363b63d..7448c85cd 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -371,4 +371,14 @@ SLAPrintObject::SLAPrintObject(SLAPrint *print, ModelObject *model_object): SLAPrintObject::~SLAPrintObject() {} +TriangleMesh SLAPrintObject::support_mesh() const +{ + return make_cube(10., 10., 10.); +} + +TriangleMesh SLAPrintObject::pad_mesh() const +{ + return make_cube(10., 10., 10.); +} + } // namespace Slic3r diff --git a/src/libslic3r/SLAPrint.hpp b/src/libslic3r/SLAPrint.hpp index 7a3af4b76..b2f2ba206 100644 --- a/src/libslic3r/SLAPrint.hpp +++ b/src/libslic3r/SLAPrint.hpp @@ -37,7 +37,23 @@ private: // Prevents erroneous use by other classes. public: const ModelObject* model_object() const { return m_model_object; } ModelObject* model_object() { return m_model_object; } + const Transform3d& trafo() const { return m_trafo; } + + struct Instance { + ModelID instance_id; + // Slic3r::Point objects in scaled G-code coordinates + Point shift; + // Rotation along the Z axis, in radians. + float rotation; + }; + const std::vector& instances() const { return m_instances; } + + // Get a support mesh centered around origin in XY, and with zero rotation around Z applied. + // Support mesh is only valid if this->is_step_done(slaposSupportTree) is true. TriangleMesh support_mesh() const; + // Get a pad mesh centered around origin in XY, and with zero rotation around Z applied. + // Support mesh is only valid if this->is_step_done(slaposPad) is true. + TriangleMesh pad_mesh() const; // I refuse to grantee copying (Tamas) SLAPrintObject(const SLAPrintObject&) = delete; @@ -55,14 +71,6 @@ protected: { this->m_config.apply_only(other, keys, ignore_nonexistent); } void set_trafo(const Transform3d& trafo) { m_trafo = trafo; } - struct Instance { - // Slic3r::Point objects in scaled G-code coordinates - Point shift; - // Rotation along the Z axis, in radians. - float rotation; - Instance(const Point& tr, float rotZ): shift(tr), rotation(rotZ) {} - }; - bool set_instances(const std::vector &instances); // Invalidates the step, and its depending steps in SLAPrintObject and SLAPrint. bool invalidate_step(SLAPrintObjectStep step); @@ -152,6 +160,7 @@ public: if(m_printer) m_printer->save(fname); std::cout << "Would export the SLA raster" << std::endl; } + const PrintObjects& objects() const { return m_objects; } private: using SLAPrinter = FilePrinter; diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 565ef94fb..e381cb854 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -2,13 +2,14 @@ #include "3DScene.hpp" -#include "../../libslic3r/ExtrusionEntity.hpp" -#include "../../libslic3r/ExtrusionEntityCollection.hpp" -#include "../../libslic3r/Geometry.hpp" -#include "../../libslic3r/GCode/PreviewData.hpp" -#include "../../libslic3r/Print.hpp" -#include "../../libslic3r/Slicing.hpp" -#include "../../slic3r/GUI/PresetBundle.hpp" +#include "libslic3r/ExtrusionEntity.hpp" +#include "libslic3r/ExtrusionEntityCollection.hpp" +#include "libslic3r/Geometry.hpp" +#include "libslic3r/GCode/PreviewData.hpp" +#include "libslic3r/Print.hpp" +#include "libslic3r/SLAPrint.hpp" +#include "libslic3r/Slicing.hpp" +#include "slic3r/GUI/PresetBundle.hpp" #include "GCode/Analyzer.hpp" #include @@ -209,7 +210,9 @@ GLVolume::GLVolume(float r, float g, float b, float a) #endif // ENABLE_MODELVOLUME_TRANSFORM , m_transformed_convex_hull_bounding_box_dirty(true) , m_convex_hull(nullptr) - , composite_id(-1) + , object_id(-1) + , volume_id(-1) + , instance_id(-1) , extruder_id(0) , selected(false) , disabled(false) @@ -755,7 +758,9 @@ std::vector GLVolumeCollection::load_object( // finalize_geometry() clears the vertex arrays, therefore the bounding box has to be computed before finalize_geometry(). v.bounding_box = v.indexed_vertex_array.bounding_box(); v.indexed_vertex_array.finalize_geometry(use_VBOs); - v.composite_id = obj_idx * 1000000 + volume_idx * 1000 + instance_idx; + v.object_id = obj_idx; + v.volume_id = volume_idx; + v.instance_id = instance_idx; if (model_volume->is_model_part()) { v.set_convex_hull(model_volume->get_convex_hull()); @@ -780,6 +785,61 @@ std::vector GLVolumeCollection::load_object( return volumes_idx; } +// Load SLA auxiliary GLVolumes (for support trees or pad). +std::vector GLVolumeCollection::load_object_auxiliary( + const ModelObject *model_object, + const SLAPrintObject *print_object, + int obj_idx, + SLAPrintObjectStep milestone, + bool use_VBOs) +{ + std::vector volumes_idx; + // Find the SLAPrintObject's instance to it. + if (print_object->is_step_done(milestone)) { + // Get the support mesh. + TriangleMesh mesh; + switch (milestone) { + case slaposSupportTree: mesh = print_object->support_mesh(); break; + case slaposBasePool: mesh = print_object->pad_mesh(); break; + default: + assert(false); + } + // Convex hull is required for out of print bed detection. + TriangleMesh convex_hull = mesh.convex_hull_3d(); + const std::vector &instances = print_object->instances(); + std::map map_instances; + for (int i = 0; i < (int)model_object->instances.size(); ++ i) + map_instances[model_object->instances[i]->id()] = i; + for (const SLAPrintObject::Instance &instance : instances) { + auto model_instance_it = map_instances.find(instance.instance_id); + assert(model_instance_it != map_instances.end()); + const int instance_idx = model_instance_it->second; + const ModelInstance *model_instance = model_object->instances[instance_idx]; + volumes_idx.push_back(int(this->volumes.size())); + float color[4] { 0.f, 0.f, 1.f, 1.f }; + this->volumes.emplace_back(new GLVolume(color)); + GLVolume &v = *this->volumes.back(); + if (use_VBOs) + v.indexed_vertex_array.load_mesh_full_shading(mesh); + else + v.indexed_vertex_array.load_mesh_flat_shading(mesh); + // finalize_geometry() clears the vertex arrays, therefore the bounding box has to be computed before finalize_geometry(). + v.bounding_box = v.indexed_vertex_array.bounding_box(); + v.indexed_vertex_array.finalize_geometry(use_VBOs); + v.object_id = obj_idx; + v.volume_id = -1; // SLA supports + v.instance_id = instance_idx; + v.set_convex_hull(convex_hull); + v.is_modifier = false; + v.shader_outside_printer_detection_enabled = true; + v.set_instance_transformation(model_instance->get_transformation()); + // Leave the volume transformation at identity. + // v.set_volume_transformation(model_volume->get_transformation()); + } + } + + return volumes_idx; +} int GLVolumeCollection::load_wipe_tower_preview( int obj_idx, float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool use_VBOs, bool size_unknown, float brim_width) @@ -851,7 +911,9 @@ int GLVolumeCollection::load_wipe_tower_preview( // finalize_geometry() clears the vertex arrays, therefore the bounding box has to be computed before finalize_geometry(). v.bounding_box = v.indexed_vertex_array.bounding_box(); v.indexed_vertex_array.finalize_geometry(use_VBOs); - v.composite_id = obj_idx * 1000000; + v.object_id = obj_idx; + v.volume_id = 0; + v.instance_id = 0; v.is_wipe_tower = true; v.shader_outside_printer_detection_enabled = ! size_unknown; return int(this->volumes.size() - 1); @@ -1848,6 +1910,11 @@ void _3DScene::set_print(wxGLCanvas* canvas, Print* print) s_canvas_mgr.set_print(canvas, print); } +void _3DScene::set_SLA_print(wxGLCanvas* canvas, SLAPrint* print) +{ + s_canvas_mgr.set_SLA_print(canvas, print); +} + void _3DScene::set_model(wxGLCanvas* canvas, Model* model) { s_canvas_mgr.set_model(canvas, model); diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index 87c9df385..e611e7f54 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -1,13 +1,13 @@ #ifndef slic3r_3DScene_hpp_ #define slic3r_3DScene_hpp_ -#include "../../libslic3r/libslic3r.h" -#include "../../libslic3r/Point.hpp" -#include "../../libslic3r/Line.hpp" -#include "../../libslic3r/TriangleMesh.hpp" -#include "../../libslic3r/Utils.hpp" -#include "../../libslic3r/Model.hpp" -#include "../../slic3r/GUI/GLCanvas3DManager.hpp" +#include "libslic3r/libslic3r.h" +#include "libslic3r/Point.hpp" +#include "libslic3r/Line.hpp" +#include "libslic3r/TriangleMesh.hpp" +#include "libslic3r/Utils.hpp" +#include "libslic3r/Model.hpp" +#include "slic3r/GUI/GLCanvas3DManager.hpp" class wxBitmap; class wxWindow; @@ -16,6 +16,9 @@ namespace Slic3r { class Print; class PrintObject; +class SLAPrint; +class SLAPrintObject; +enum SLAPrintObjectStep; class Model; class ModelObject; class GCodePreviewData; @@ -290,8 +293,15 @@ public: float color[4]; // Color used to render this volume. float render_color[4]; - // An ID containing the object ID, volume ID and instance ID. - int composite_id; + // Object ID, which is equal to the index of the respective ModelObject in Model.objects array. + int object_id; + // Volume ID, which is equal to the index of the respective ModelVolume in ModelObject.volumes array. + // If negative, it is an index of a geometry produced by the PrintObject for the respective ModelObject, + // and which has no associated ModelVolume in ModelObject.volumes. For example, SLA supports. + // Volume with a negative volume_id cannot be picked independently, it will pick the associated instance. + int volume_id; + // Instance ID, which is equal to the index of the respective ModelInstance in ModelObject.instances array. + int instance_id; // An ID containing the extruder ID (used to select color). int extruder_id; // Is this object selected? @@ -404,9 +414,9 @@ public: void set_convex_hull(const TriangleMesh& convex_hull); - int object_idx() const { return this->composite_id / 1000000; } - int volume_idx() const { return (this->composite_id / 1000) % 1000; } - int instance_idx() const { return this->composite_id % 1000; } + int object_idx() const { return this->object_id; } + int volume_idx() const { return this->volume_id; } + int instance_idx() const { return this->instance_id; } #if ENABLE_MODELVOLUME_TRANSFORM Transform3d world_matrix() const { return m_instance_transformation.get_matrix() * m_volume_transformation.get_matrix(); } @@ -489,6 +499,14 @@ public: const std::string &color_by, bool use_VBOs); + // Load SLA auxiliary GLVolumes (for support trees or pad). + std::vector load_object_auxiliary( + const ModelObject *model_object, + const SLAPrintObject *print_object, + int obj_idx, + SLAPrintObjectStep milestone, + bool use_VBOs); + int load_wipe_tower_preview( int obj_idx, float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool use_VBOs, bool size_unknown, float brim_width); @@ -556,6 +574,7 @@ public: static void set_config(wxGLCanvas* canvas, DynamicPrintConfig* config); static void set_print(wxGLCanvas* canvas, Print* print); + static void set_SLA_print(wxGLCanvas* canvas, SLAPrint* print); static void set_model(wxGLCanvas* canvas, Model* model); static void set_bed_shape(wxGLCanvas* canvas, const Pointfs& shape); diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.cpp b/src/slic3r/GUI/BackgroundSlicingProcess.cpp index b914e0af6..5dcef44a1 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.cpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.cpp @@ -294,6 +294,12 @@ void BackgroundSlicingProcess::stop_internal() m_print->set_cancel_callback([](){}); } +bool BackgroundSlicingProcess::empty() const +{ + assert(m_print != nullptr); + return m_print->empty(); +} + std::string BackgroundSlicingProcess::validate() { assert(m_print != nullptr); diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.hpp b/src/slic3r/GUI/BackgroundSlicingProcess.hpp index 28f8e67ab..92bc512d7 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.hpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.hpp @@ -51,11 +51,15 @@ public: // Useful when the Model or configuration is being changed drastically. bool reset(); - // Validate the print. Returns an empty string if valid, returns an error message if invalid. - std::string validate(); // 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. Print::ApplyStatus apply(const Model &model, const DynamicPrintConfig &config); + // After calling apply, the empty() call will report whether there is anything to slice. + bool empty() const; + // Validate the print. Returns an empty string if valid, returns an error message if invalid. + // Call validate before calling start(). + std::string validate(); + // Set the export path of the G-code. // Once the path is set, the G-code void schedule_export(const std::string &path); diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 707359f3e..f9daa36d0 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1,16 +1,16 @@ #include "GLCanvas3D.hpp" -#include "../../admesh/stl.h" -#include "../../libslic3r/libslic3r.h" -#include "../../slic3r/GUI/3DScene.hpp" -#include "../../slic3r/GUI/GLShader.hpp" -#include "../../slic3r/GUI/GUI.hpp" -#include "../../slic3r/GUI/PresetBundle.hpp" -#include "../../slic3r/GUI/GLGizmo.hpp" -#include "../../libslic3r/ClipperUtils.hpp" -#include "../../libslic3r/PrintConfig.hpp" -#include "../../libslic3r/GCode/PreviewData.hpp" -#include "../../libslic3r/Geometry.hpp" +#include "admesh/stl.h" +#include "libslic3r/libslic3r.h" +#include "slic3r/GUI/3DScene.hpp" +#include "slic3r/GUI/GLShader.hpp" +#include "slic3r/GUI/GUI.hpp" +#include "slic3r/GUI/PresetBundle.hpp" +#include "slic3r/GUI/GLGizmo.hpp" +#include "libslic3r/ClipperUtils.hpp" +#include "libslic3r/PrintConfig.hpp" +#include "libslic3r/GCode/PreviewData.hpp" +#include "libslic3r/Geometry.hpp" #include "GUI_App.hpp" #include "GUI_ObjectList.hpp" #include "GUI_ObjectManipulation.hpp" @@ -25,7 +25,8 @@ #include // Print now includes tbb, and tbb includes Windows. This breaks compilation of wxWidgets if included before wx. -#include "../../libslic3r/Print.hpp" +#include "libslic3r/Print.hpp" +#include "libslic3r/SLAPrint.hpp" #include #include @@ -3065,6 +3066,7 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas) , m_toolbar(*this) , m_config(nullptr) , m_print(nullptr) + , m_sla_print(nullptr) , m_model(nullptr) , m_dirty(true) , m_initialized(false) @@ -3247,7 +3249,11 @@ bool GLCanvas3D::move_volume_up(unsigned int id) if ((id > 0) && (id < (unsigned int)m_volumes.volumes.size())) { std::swap(m_volumes.volumes[id - 1], m_volumes.volumes[id]); - std::swap(m_volumes.volumes[id - 1]->composite_id, m_volumes.volumes[id]->composite_id); + GLVolume &v1 = *m_volumes.volumes[id - 1]; + GLVolume &v2 = *m_volumes.volumes[id]; + std::swap(v1.object_id, v2.object_id); + std::swap(v1.volume_id, v2.volume_id); + std::swap(v1.instance_id, v2.instance_id); return true; } @@ -3259,7 +3265,11 @@ bool GLCanvas3D::move_volume_down(unsigned int id) if ((id >= 0) && (id + 1 < (unsigned int)m_volumes.volumes.size())) { std::swap(m_volumes.volumes[id + 1], m_volumes.volumes[id]); - std::swap(m_volumes.volumes[id + 1]->composite_id, m_volumes.volumes[id]->composite_id); + GLVolume &v1 = *m_volumes.volumes[id + 1]; + GLVolume &v2 = *m_volumes.volumes[id]; + std::swap(v1.object_id, v2.object_id); + std::swap(v1.volume_id, v2.volume_id); + std::swap(v1.instance_id, v2.instance_id); return true; } @@ -3276,6 +3286,11 @@ void GLCanvas3D::set_print(Print* print) m_print = print; } +void GLCanvas3D::set_SLA_print(SLAPrint* print) +{ + m_sla_print = print; +} + void GLCanvas3D::set_model(Model* model) { m_model = model; @@ -3631,6 +3646,13 @@ std::vector GLCanvas3D::load_object(const Model& model, int obj_idx) return std::vector(); } +std::vector GLCanvas3D::load_support_meshes(const Model& model, int obj_idx) +{ + std::vector volumes = m_volumes.load_object_auxiliary(model.objects[obj_idx], m_sla_print->objects()[obj_idx], obj_idx, slaposSupportTree, m_use_VBOs && m_initialized); + append(volumes, m_volumes.load_object_auxiliary(model.objects[obj_idx], m_sla_print->objects()[obj_idx], obj_idx, slaposBasePool, m_use_VBOs && m_initialized)); + return volumes; +} + int GLCanvas3D::get_first_volume_id(int obj_idx) const { for (int i = 0; i < (int)m_volumes.volumes.size(); ++i) @@ -3682,11 +3704,14 @@ void GLCanvas3D::reload_scene(bool force) m_reload_delayed = false; + PrinterTechnology printer_technology = wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology(); if (m_regenerate_volumes) { for (unsigned int obj_idx = 0; obj_idx < (unsigned int)m_model->objects.size(); ++obj_idx) { load_object(*m_model, obj_idx); + if (printer_technology == ptSLA) + load_support_meshes(*m_model, obj_idx); } } @@ -3694,7 +3719,8 @@ void GLCanvas3D::reload_scene(bool force) if (m_regenerate_volumes) { - if (m_config->has("nozzle_diameter") && wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptFFF) + PrinterTechnology printer_technology = wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology(); + if (printer_technology == ptFFF && m_config->has("nozzle_diameter")) { // Should the wipe tower be visualized ? unsigned int extruders_count = (unsigned int)dynamic_cast(m_config->option("nozzle_diameter"))->values.size(); diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index f182f2c37..eb45bddb5 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -22,6 +22,7 @@ namespace Slic3r { class GLShader; class ExPolygon; +class SLAPrint; namespace GUI { @@ -447,17 +448,25 @@ public: struct Cache { + // Cache of GLVolume derived transformation matrices, valid during mouse dragging. VolumesCache volumes_data; + // Center of the dragged selection, valid during mouse dragging. Vec3d dragging_center; + // Map from indices of ModelObject instances in Model::objects + // to a set of indices of ModelVolume instances in ModelObject::instances + // Here the index means a position inside the respective std::vector, not ModelID. ObjectIdxsToInstanceIdxsMap content; }; + // Volumes owned by GLCanvas3D. GLVolumePtrs* m_volumes; + // Model, not owned. Model* m_model; bool m_valid; EMode m_mode; EType m_type; + // set of indices to m_volumes IndicesList m_list; Cache m_cache; mutable BoundingBoxf3 m_bounding_box; @@ -692,6 +701,7 @@ private: Selection m_selection; DynamicPrintConfig* m_config; Print* m_print; + SLAPrint* m_sla_print; Model* m_model; bool m_dirty; @@ -745,6 +755,7 @@ public: void set_config(DynamicPrintConfig* config); void set_print(Print* print); + void set_SLA_print(SLAPrint* print); void set_model(Model* model); const Selection& get_selection() const { return m_selection; } @@ -810,6 +821,9 @@ public: std::vector load_object(const ModelObject& model_object, int obj_idx, std::vector instance_idxs); std::vector load_object(const Model& model, int obj_idx); + // Load SLA support tree and SLA pad meshes into the scene, if available at the respective SLAPrintObject instances. + std::vector load_support_meshes(const Model& model, int obj_idx); + int get_first_volume_id(int obj_idx) const; int get_in_object_volume_id(int scene_vol_idx) const; diff --git a/src/slic3r/GUI/GLCanvas3DManager.cpp b/src/slic3r/GUI/GLCanvas3DManager.cpp index d8ff798ed..d38b2f193 100644 --- a/src/slic3r/GUI/GLCanvas3DManager.cpp +++ b/src/slic3r/GUI/GLCanvas3DManager.cpp @@ -284,6 +284,14 @@ void GLCanvas3DManager::set_print(wxGLCanvas* canvas, Print* print) it->second->set_print(print); } + +void GLCanvas3DManager::set_SLA_print(wxGLCanvas* canvas, SLAPrint* print) +{ + CanvasesMap::iterator it = _get_canvas(canvas); + if (it != m_canvases.end()) + it->second->set_SLA_print(print); +} + void GLCanvas3DManager::set_model(wxGLCanvas* canvas, Model* model) { CanvasesMap::iterator it = _get_canvas(canvas); diff --git a/src/slic3r/GUI/GLCanvas3DManager.hpp b/src/slic3r/GUI/GLCanvas3DManager.hpp index 917b4a4e8..232c928f3 100644 --- a/src/slic3r/GUI/GLCanvas3DManager.hpp +++ b/src/slic3r/GUI/GLCanvas3DManager.hpp @@ -14,6 +14,7 @@ namespace Slic3r { class DynamicPrintConfig; class Print; +class SLAPrint; class Model; class ExPolygon; typedef std::vector ExPolygons; @@ -95,6 +96,7 @@ public: void set_config(wxGLCanvas* canvas, DynamicPrintConfig* config); void set_print(wxGLCanvas* canvas, Print* print); + void set_SLA_print(wxGLCanvas* canvas, SLAPrint* print); void set_model(wxGLCanvas* canvas, Model* model); void set_bed_shape(wxGLCanvas* canvas, const Pointfs& shape); diff --git a/src/slic3r/GUI/GLGizmo.cpp b/src/slic3r/GUI/GLGizmo.cpp index 920e79913..11e7bfe23 100644 --- a/src/slic3r/GUI/GLGizmo.cpp +++ b/src/slic3r/GUI/GLGizmo.cpp @@ -494,7 +494,7 @@ void GLGizmoRotate::render_angle() const void GLGizmoRotate::render_grabber(const BoundingBoxf3& box) const { - double grabber_radius = (double)m_radius * (1.0 + (double)GrabberOffset); + double grabber_radius = (double)m_radius * (1.0 + (double)GrabberOffset) + 2.0 * (double)m_axis * box.max_size() * (double)Grabber::SizeFactor; m_grabbers[0].center = Vec3d(::cos(m_angle) * grabber_radius, ::sin(m_angle) * grabber_radius, 0.0); m_grabbers[0].angles(2) = m_angle; diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index bcd2623e2..66ac7a979 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -482,18 +482,16 @@ ConfigMenuIDs GUI_App::get_view_mode() // Update view mode according to selected menu void GUI_App::update_mode() { - wxWindowUpdateLocker noUpdates(mainframe->m_plater); + wxWindowUpdateLocker noUpdates(&sidebar()); ConfigMenuIDs mode = wxGetApp().get_view_mode(); obj_list()->get_sizer()->Show(mode == ConfigMenuModeExpert); - sidebar().show_info_sizer(mode == ConfigMenuModeExpert); + sidebar().set_mode_value(mode); sidebar().show_buttons(mode == ConfigMenuModeExpert); - obj_manipul()->show_object_name(mode == ConfigMenuModeSimple); - obj_list()->update_manipulation_sizer(mode == ConfigMenuModeSimple); + obj_list()->update_selections(); sidebar().Layout(); - mainframe->m_plater->Layout(); ConfigOptionMode opt_mode = mode == ConfigMenuModeSimple ? comSimple : mode == ConfigMenuModeExpert ? comExpert : comAdvanced; diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index a088e13e5..77cd1c440 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -823,9 +823,12 @@ void ObjectList::load_generic_subobject(const std::string& type_name, const int #endif //no __WXOSX__ //__WXMSW__ } +void ObjectList::del_object(const int obj_idx) +{ + wxGetApp().plater()->delete_object_from_model(obj_idx); +} // Delete subobject - void ObjectList::del_subobject_item(wxDataViewItem& item) { if (!item) return; @@ -1016,7 +1019,6 @@ void ObjectList::part_selection_changed() bool update_and_show_manipulations = false; bool update_and_show_settings = false; - bool show_info_sizer = false; if (multiple_selection()) { og_name = _(L("Group manipulation")); @@ -1033,7 +1035,6 @@ void ObjectList::part_selection_changed() og_name = _(L("Object manipulation")); m_config = &(*m_objects)[obj_idx]->config; update_and_show_manipulations = true; - show_info_sizer = true; } else { auto parent = m_objects_model->GetParent(item); @@ -1082,25 +1083,15 @@ void ObjectList::part_selection_changed() if (update_and_show_settings) wxGetApp().obj_settings()->get_og()->set_name(" " + og_name + " "); - auto panel = wxGetApp().sidebar().scrolled_panel(); - panel->Freeze(); + Sidebar& panel = wxGetApp().sidebar(); + panel.Freeze(); wxGetApp().obj_manipul() ->UpdateAndShow(update_and_show_manipulations); wxGetApp().obj_settings()->UpdateAndShow(update_and_show_settings); - show_info_sizer ? wxGetApp().sidebar().update_info_sizer() : wxGetApp().sidebar().show_info_sizer(false); + wxGetApp().sidebar().show_info_sizer(); - panel->Thaw(); -} - -void ObjectList::update_manipulation_sizer(const bool is_simple_mode) -{ - auto item = GetSelection(); /// #ys_FIXME_to_multi_sel - if (!item || !is_simple_mode) - return; - - if (m_objects_model->IsSettingsItem(item)) { - select_item(m_objects_model->GetParent(item)); - } + panel.Layout(); + panel.Thaw(); } void ObjectList::add_object_to_list(size_t obj_idx) @@ -1167,6 +1158,49 @@ void ObjectList::delete_volume_from_list(const size_t obj_idx, const size_t vol_ select_item(m_objects_model->Delete(m_objects_model->GetItemByVolumeId(obj_idx, vol_idx))); } +void ObjectList::delete_instance_from_list(const size_t obj_idx, const size_t inst_idx) +{ + select_item(m_objects_model->Delete(m_objects_model->GetItemByInstanceId(obj_idx, inst_idx))); +} + +void ObjectList::delete_from_model_and_list(const ItemType type, const int obj_idx, const int sub_obj_idx) +{ + if ( !(type&(itObject|itVolume|itInstance)) ) + return; + + if (type&itObject) { + del_object(obj_idx); + delete_object_from_list(obj_idx); + } + else { + del_subobject_from_object(obj_idx, sub_obj_idx, type); + + type == itVolume ? delete_volume_from_list(obj_idx, sub_obj_idx) : + delete_instance_from_list(obj_idx, sub_obj_idx); + } +} + +void ObjectList::delete_from_model_and_list(const std::vector * items_for_delete) +{ + for (auto& item : *items_for_delete) + { + if ( !(item.type&(itObject|itVolume|itInstance)) ) + continue; + if (item.type&itObject) { + del_object(item.obj_idx); + m_objects_model->Delete(m_objects_model->GetItemById(item.obj_idx)); + } + else { + del_subobject_from_object(item.obj_idx, item.sub_obj_idx, item.type); + if (item.type&itVolume) + m_objects_model->Delete(m_objects_model->GetItemByVolumeId(item.obj_idx, item.sub_obj_idx)); + else + m_objects_model->Delete(m_objects_model->GetItemByInstanceId(item.obj_idx, item.sub_obj_idx)); + } + } + part_selection_changed(); +} + void ObjectList::delete_all_objects_from_list() { m_objects_model->DeleteAll(); diff --git a/src/slic3r/GUI/GUI_ObjectList.hpp b/src/slic3r/GUI/GUI_ObjectList.hpp index dd0b27bd7..c06cf6e51 100644 --- a/src/slic3r/GUI/GUI_ObjectList.hpp +++ b/src/slic3r/GUI/GUI_ObjectList.hpp @@ -5,7 +5,9 @@ #include #include #include + #include "Event.hpp" +#include "wxExtensions.hpp" class wxBoxSizer; class PrusaObjectDataViewModel; @@ -20,6 +22,13 @@ namespace GUI { wxDECLARE_EVENT(EVT_OBJ_LIST_OBJECT_SELECT, SimpleEvent); +struct ItemForDelete +{ + ItemType type; + int obj_idx; + int sub_obj_idx; +}; + class ObjectList : public wxDataViewCtrl { wxBoxSizer *m_sizer {nullptr}; @@ -92,6 +101,7 @@ public: void load_subobject(int type); void load_part(ModelObject* model_object, wxArrayString& part_names, int type); void load_generic_subobject(const std::string& type_name, const int type); + void del_object(const int obj_idx); void del_subobject_item(wxDataViewItem& item); void del_settings_from_config(); void del_instances_from_object(const int obj_idx); @@ -110,14 +120,15 @@ public: void parts_changed(int obj_idx); void part_selection_changed(); - void update_manipulation_sizer(const bool is_simple_mode); - // Add object to the list void add_object_to_list(size_t obj_idx); // Delete object from the list void delete_object_from_list(); void delete_object_from_list(const size_t obj_idx); void delete_volume_from_list(const size_t obj_idx, const size_t vol_idx); + void delete_instance_from_list(const size_t obj_idx, const size_t inst_idx); + void delete_from_model_and_list(const ItemType type, const int obj_idx, const int sub_obj_idx); + void delete_from_model_and_list(const std::vector * items_for_delete); // Delete all objects from the list void delete_all_objects_from_list(); // Increase instances count diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp index ee35af642..5993eb1e1 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp @@ -87,7 +87,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent): if (option_name == "Rotation") def.min = -360; else - def.min == -1000; + def.min = -1000; const std::string lower_name = boost::algorithm::to_lower_copy(option_name); diff --git a/src/slic3r/GUI/GUI_ObjectSettings.cpp b/src/slic3r/GUI/GUI_ObjectSettings.cpp index 50274ec99..ec463dfb5 100644 --- a/src/slic3r/GUI/GUI_ObjectSettings.cpp +++ b/src/slic3r/GUI/GUI_ObjectSettings.cpp @@ -38,7 +38,7 @@ void OG_Settings::Hide() void OG_Settings::UpdateAndShow(const bool show) { Show(show); - m_parent->Layout(); +// m_parent->Layout(); } wxSizer* OG_Settings::get_sizer() diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 08b368031..6e30c6794 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -447,7 +447,7 @@ struct Sidebar::priv void Sidebar::priv::show_preset_comboboxes() { - const bool showSLA = wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA; + const bool showSLA = plater->printer_technology() == ptSLA; wxWindowUpdateLocker noUpdates_scrolled(scrolled); // scrolled->Freeze(); @@ -630,9 +630,8 @@ void Sidebar::update_presets(Preset::Type preset_type) case Preset::TYPE_PRINTER: { - PrinterTechnology printer_technology = preset_bundle.printers.get_edited_preset().printer_technology(); // Update the print choosers to only contain the compatible presets, update the dirty flags. - if (printer_technology == ptFFF) + if (p->plater->printer_technology() == ptFFF) preset_bundle.prints.update_platter_ui(p->combo_print); else preset_bundle.sla_materials.update_platter_ui(p->combo_sla_material); @@ -640,7 +639,7 @@ void Sidebar::update_presets(Preset::Type preset_type) preset_bundle.printers.update_platter_ui(p->combo_printer); // Update the filament choosers to only contain the compatible presets, update the color preview, // update the dirty flags. - if (printer_technology == ptFFF) { + if (p->plater->printer_technology() == ptFFF) { for (size_t i = 0; i < p->combos_filament.size(); ++ i) preset_bundle.update_platter_filament_ui(i, p->combos_filament[i]); } @@ -690,32 +689,31 @@ void Sidebar::update_objects_list_extruder_column(int extruders_count) p->object_list->update_objects_list_extruder_column(extruders_count); } -void Sidebar::show_info_sizer(const bool show) +void Sidebar::show_info_sizer() { - p->object_info->show_sizer(show); - p->scrolled->Layout(); -} - -void Sidebar::update_info_sizer() -{ - wxWindowUpdateLocker freeze_guard(p->scrolled); - - if (/*obj_idx < 0 || */!p->plater->is_single_full_object_selection()) { + if (!p->plater->is_single_full_object_selection() || + m_mode < ConfigMenuModeExpert ) { p->object_info->Show(false); - p->scrolled->Layout(); return; } int obj_idx = p->plater->get_selected_object_idx(); const ModelObject* model_object = (*wxGetApp().model_objects())[obj_idx]; + // hack to avoid crash when deleting the last object on the bed + if (model_object->volumes.empty()) + { + p->object_info->Show(false); + return; + } + const ModelInstance* model_instance = !model_object->instances.empty() ? model_object->instances.front() : nullptr; auto size = model_object->instance_bounding_box(0).size(); p->object_info->info_size->SetLabel(wxString::Format("%.2f x %.2f x %.2f",size(0), size(1), size(2))); p->object_info->info_materials->SetLabel(wxString::Format("%d", static_cast(model_object->materials_count()))); - auto& stats = model_object->volumes[0]->mesh.stl.stats; + auto& stats = model_object->volumes.front()->mesh.stl.stats; auto sf = model_instance->get_scaling_factor(); p->object_info->info_volume->SetLabel(wxString::Format("%.2f", stats.volume * sf(0) * sf(1) * sf(2))); p->object_info->info_facets->SetLabel(wxString::Format(_(L("%d (%d shells)")), static_cast(model_object->facets_count()), stats.number_of_parts)); @@ -743,12 +741,11 @@ void Sidebar::update_info_sizer() } p->object_info->show_sizer(true); - p->scrolled->Layout(); } void Sidebar::show_sliced_info_sizer(const bool show) { - wxWindowUpdateLocker freeze_guard(p->scrolled); + wxWindowUpdateLocker freeze_guard(this); p->sliced_info->Show(show); if (show) { @@ -777,7 +774,7 @@ void Sidebar::show_sliced_info_sizer(const bool show) p->sliced_info->SetTextAndShow(siWTNumbetOfToolchanges, is_wipe_tower ? wxString::Format("%.d", p->plater->print().wipe_tower_data().number_of_toolchanges) : "N/A"); } - p->scrolled->Layout(); + Layout(); } void Sidebar::show_buttons(const bool show) @@ -787,7 +784,7 @@ void Sidebar::show_buttons(const bool show) TabPrinter *tab = dynamic_cast(wxGetApp().tab_panel()->GetPage(i)); if (!tab) continue; - if (wxGetApp().preset_bundle->printers.get_selected_preset().printer_technology() == ptFFF) { + if (p->plater->printer_technology() == ptFFF) { p->btn_send_gcode->Show(show && !tab->m_config->opt_string("print_host").empty()); } break; @@ -877,10 +874,11 @@ struct Plater::priv // Data Slic3r::DynamicPrintConfig *config; - Slic3r::Print print; - Slic3r::SLAPrint sla_print; - Slic3r::Model model; - Slic3r::GCodePreviewData gcode_preview_data; + Slic3r::Print print; + Slic3r::SLAPrint sla_print; + Slic3r::Model model; + PrinterTechnology printer_technology = ptFFF; + Slic3r::GCodePreviewData gcode_preview_data; // GUI elements wxNotebook *notebook; @@ -916,14 +914,28 @@ struct Plater::priv void object_list_changed(); void remove(size_t obj_idx); + void delete_object_from_model(size_t obj_idx); void reset(); void mirror(Axis axis); void arrange(); void split_object(); void split_volume(); void schedule_background_process(); + // Update background processing thread from the current config and Model. + enum UpdateBackgroundProcessReturnState { + // update_background_process() reports, that the Print / SLAPrint was updated in a way, + // that the background process was invalidated and it needs to be re-run. + UPDATE_BACKGROUND_PROCESS_RESTART = 1, + // update_background_process() reports, that the Print / SLAPrint was updated in a way, + // that a scene needs to be refreshed (you should call _3DScene::reload_scene(canvas3D, false)) + UPDATE_BACKGROUND_PROCESS_REFRESH_SCENE = 2, + // update_background_process() reports, that the Print / SLAPrint is invalid, and the error message + // was sent to the status line. + UPDATE_BACKGROUND_PROCESS_INVALID = 4, + }; + // returns bit mask of UpdateBackgroundProcessReturnState + unsigned int update_background_process(); void async_apply_config(); - void start_background_process(); void reload_from_disk(); void export_object_stl(); void fix_through_netfabb(const int obj_idx); @@ -989,7 +1001,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) : background_process.set_sliced_event(EVT_SLICING_COMPLETED); background_process.set_finished_event(EVT_PROCESS_COMPLETED); // Default printer technology for default config. - background_process.select_technology(q->printer_technology()); + background_process.select_technology(this->printer_technology); // Register progress callback from the Print class to the Platter. auto statuscb = [this](int percent, const std::string &message) { @@ -1013,6 +1025,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) : // XXX: more config from 3D.pm _3DScene::set_model(canvas3D, &model); _3DScene::set_print(canvas3D, &print); + _3DScene::set_SLA_print(canvas3D, &sla_print); _3DScene::set_config(canvas3D, config); _3DScene::enable_gizmos(canvas3D, true); _3DScene::enable_toolbar(canvas3D, true); @@ -1095,6 +1108,11 @@ void Plater::priv::update(bool force_autocenter) model.center_instances_around_point(bed_center); } + if (this->printer_technology == ptSLA) { + // Update the SLAPrint from the current Model, so that the reload_scene() + // pulls the correct data. + this->update_background_process(); + } _3DScene::reload_scene(canvas3D, false); preview->reset_gcode_preview_data(); preview->reload_print(); @@ -1416,8 +1434,6 @@ void Plater::priv::selection_changed() _3DScene::enable_toolbar_item(canvas3D, "layersediting", layers_height_allowed()); // forces a frame render to update the view (to avoid a missed update if, for example, the context menu appears) _3DScene::render(canvas3D); - - sidebar->update_info_sizer(); } void Plater::priv::object_list_changed() @@ -1450,6 +1466,12 @@ void Plater::priv::remove(size_t obj_idx) update(); } + +void Plater::priv::delete_object_from_model(size_t obj_idx) +{ + model.delete_object(obj_idx); +} + void Plater::priv::reset() { // Prevent toolpaths preview from rendering while we modify the Print object @@ -1610,10 +1632,18 @@ void Plater::priv::schedule_background_process() this->background_process_timer.Start(500, wxTIMER_ONE_SHOT); } -void Plater::priv::async_apply_config() +// Update background processing thread from the current config and Model. +// Returns a bitmask of UpdateBackgroundProcessReturnState. +unsigned int Plater::priv::update_background_process() { + // bitmap of enum UpdateBackgroundProcessReturnState + unsigned int return_state = 0; + + // If the async_apply_config() was not called by the timer, kill the timer, so the async_apply_config() + // will not be called again in vain. + this->background_process_timer.Stop(); + DynamicPrintConfig config = wxGetApp().preset_bundle->full_config(); - auto printer_technology = config.opt_enum("printer_technology"); BoundingBox bed_box_2D = get_extents(Polygon::new_scale(config.opt("bed_shape")->values)); BoundingBoxf3 print_volume(unscale(bed_box_2D.min(0), bed_box_2D.min(1), 0.0), unscale(bed_box_2D.max(0), bed_box_2D.max(1), scale_(config.opt_float("max_print_height")))); // Allow the objects to protrude below the print bed, only the part of the object above the print bed will be sliced. @@ -1634,40 +1664,55 @@ void Plater::priv::async_apply_config() // Reset preview canvases. If the print has been invalidated, the preview canvases will be cleared. // Otherwise they will be just refreshed. this->gcode_preview_data.reset(); - if (printer_technology == ptFFF) { + switch (this->printer_technology) { + case ptFFF: if (this->preview != nullptr) + // If the preview is not visible, the following line just invalidates the preview, + // but the G-code paths are calculated first once the preview is made visible. this->preview->reload_print(); // We also need to reload 3D scene because of the wipe tower preview box if (this->config->opt_bool("wipe_tower")) { // std::vector selections = this->collect_selections(); // Slic3r::_3DScene::set_objects_selections(this->canvas3D, selections); - // Slic3r::_3DScene::reload_scene(this->canvas3D, 1); + return_state |= UPDATE_BACKGROUND_PROCESS_REFRESH_SCENE; } + break; + case ptSLA: + //FIXME as of now the Print::APPLY_STATUS_INVALIDATED is not reliable, and + // currently the scene refresh is expensive and loses selection. + //return_state |= UPDATE_BACKGROUND_PROCESS_REFRESH_SCENE; + break; } } - if (invalidated != Print::APPLY_STATUS_UNCHANGED && this->get_config("background_processing") == "1" && - this->background_process.start()) - this->statusbar()->set_cancel_callback([this]() { - this->statusbar()->set_status_text(L("Cancelling")); - this->background_process.stop(); - }); + + if (! this->background_process.empty()) { + std::string err = this->background_process.validate(); + if (err.empty()) { + if (invalidated != Print::APPLY_STATUS_UNCHANGED) + return_state |= UPDATE_BACKGROUND_PROCESS_RESTART; + } else { + // The print is not valid. + GUI::show_error(this->q, _(err)); + return_state |= UPDATE_BACKGROUND_PROCESS_INVALID; + } + } + return return_state; } -void Plater::priv::start_background_process() +void Plater::priv::async_apply_config() { - if (this->background_process.running()) - return; - // Don't start process thread if Print is not valid. - std::string err = this->background_process.validate(); - if (! err.empty()) { - this->statusbar()->set_status_text(err); - } else { - // Copy the names of active presets into the placeholder parser. - //FIXME how to generate a file name for the SLA printers? - wxGetApp().preset_bundle->export_selections(this->q->print().placeholder_parser()); - // Start the background process. - this->background_process.start(); - } + // bitmask of UpdateBackgroundProcessReturnState + unsigned int state = this->update_background_process(); + if (state & UPDATE_BACKGROUND_PROCESS_REFRESH_SCENE) + _3DScene::reload_scene(canvas3D, false); + if ((state & UPDATE_BACKGROUND_PROCESS_RESTART) != 0 && this->get_config("background_processing") == "1") { + // The print is valid and it can be started. + if (this->background_process.start()) + this->statusbar()->set_cancel_callback([this]() { + this->statusbar()->set_status_text(L("Cancelling")); + this->background_process.stop(); + }); + } } void Plater::priv::reload_from_disk() @@ -1716,6 +1761,13 @@ void Plater::priv::on_notebook_changed(wxBookCtrlEvent&) const auto current_id = notebook->GetCurrentPage()->GetId(); if (current_id == canvas3D->GetId()) { if (_3DScene::is_reload_delayed(canvas3D)) { + // Delayed loading of the 3D scene. + if (this->printer_technology == ptSLA) { + // Update the SLAPrint from the current Model, so that the reload_scene() + // pulls the correct data. + if (this->update_background_process() & UPDATE_BACKGROUND_PROCESS_RESTART) + this->schedule_background_process(); + } _3DScene::reload_scene(canvas3D, true); } // sets the canvas as dirty to force a render at the 1st idle event (wxWidgets IsShownOnScreen() is buggy and cannot be used reliably) @@ -1811,22 +1863,18 @@ void Plater::priv::on_process_completed(wxCommandEvent &evt) //$self->object_list_changed; // refresh preview - if (this->preview != nullptr) - this->preview->reload_print(); - - // TODO: this needs to be implemented somehow - if(q->printer_technology() == PrinterTechnology::ptSLA) { - - class Renderer: public SLASupportRenderer { - public: - void add_pillar(const Mesh&, ClickCb ) override {} - void add_head(const Mesh&, ClickCb) override {} - void add_bridge(const Mesh&, ClickCb) override {} - void add_junction(const Mesh&, ClickCb) override {} - void add_pad(const Mesh&, ClickCb) override {} - } renderer; - - sla_print.render_supports(renderer); + switch (this->printer_technology) { + case ptFFF: + if (this->preview != nullptr) + this->preview->reload_print(); + break; + case ptSLA: + // Update the SLAPrint from the current Model, so that the reload_scene() + // pulls the correct data. + if (this->update_background_process() & UPDATE_BACKGROUND_PROCESS_RESTART) + this->schedule_background_process(); + _3DScene::reload_scene(canvas3D, true); + break; } } @@ -2069,6 +2117,7 @@ void Plater::update(bool force_autocenter) { p->update(force_autocenter); } void Plater::select_view(const std::string& direction) { p->select_view(direction); } void Plater::remove(size_t obj_idx) { p->remove(obj_idx); } +void Plater::delete_object_from_model(size_t obj_idx) { p->delete_object_from_model(obj_idx); } void Plater::remove_selected() { @@ -2285,21 +2334,24 @@ void Plater::export_3mf() } } - void Plater::reslice() { - // explicitly cancel a previous thread and start a new one. - // Don't reslice if export of G-code or sending to OctoPrint is running. -// if (! defined($self->{export_gcode_output_file}) && ! defined($self->{send_gcode_file})) { - // Stop the background processing threads, stop the async update timer. -// this->p->stop_background_process(); - // Rather perform one additional unnecessary update of the print object instead of skipping a pending async update. - this->p->async_apply_config(); - this->p->statusbar()->set_cancel_callback([this]() { - this->p->statusbar()->set_status_text(L("Cancelling")); - this->p->background_process.stop(); - }); - this->p->start_background_process(); + //FIXME Don't reslice if export of G-code or sending to OctoPrint is running. + // bitmask of UpdateBackgroundProcessReturnState + unsigned int state = this->p->update_background_process(); + if (state & priv::UPDATE_BACKGROUND_PROCESS_REFRESH_SCENE) + _3DScene::reload_scene(this->p->canvas3D, false); + if ((state & priv::UPDATE_BACKGROUND_PROCESS_INVALID) == 0 && !this->p->background_process.running()) { + // The print is valid and it can be started. + // Copy the names of active presets into the placeholder parser. + //FIXME how to generate a file name for the SLA printers? + wxGetApp().preset_bundle->export_selections(this->print().placeholder_parser()); + if (this->p->background_process.start()) + this->p->statusbar()->set_cancel_callback([this]() { + this->p->statusbar()->set_status_text(L("Cancelling")); + this->p->background_process.stop(); + }); + } } void Plater::send_gcode() @@ -2338,8 +2390,10 @@ void Plater::on_config_change(const DynamicPrintConfig &config) bool update_scheduled = false; for (auto opt_key : p->config->diff(config)) { p->config->set_key_value(opt_key, config.option(opt_key)->clone()); - if (opt_key == "printer_technology") - p->background_process.select_technology(config.opt_enum(opt_key)); + if (opt_key == "printer_technology") { + p->printer_technology = config.opt_enum(opt_key); + p->background_process.select_technology(this->printer_technology()); + } else if (opt_key == "bed_shape") { if (p->canvas3D) _3DScene::set_bed_shape(p->canvas3D, p->config->option(opt_key)->values); if (p->preview) p->preview->set_bed_shape(p->config->option(opt_key)->values); @@ -2393,7 +2447,7 @@ int Plater::get_selected_object_idx() return p->get_selected_object_idx(); } -bool Plater::is_single_full_object_selection() +bool Plater::is_single_full_object_selection() const { return p->get_selection().is_single_full_object(); } @@ -2405,7 +2459,7 @@ wxGLCanvas* Plater::canvas3D() PrinterTechnology Plater::printer_technology() const { - return wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology(); + return p->printer_technology; } void Plater::changed_object(int obj_idx) diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index 2a6d09dfd..1b2b53040 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -62,6 +62,7 @@ enum ButtonAction class Sidebar : public wxPanel { + /*ConfigMenuIDs*/int m_mode; public: Sidebar(Plater *parent); Sidebar(Sidebar &&) = delete; @@ -82,13 +83,13 @@ public: ConfigOptionsGroup* og_freq_chng_params(); wxButton* get_wiping_dialog_button(); void update_objects_list_extruder_column(int extruders_count); - void show_info_sizer(const bool show); - void update_info_sizer(); + void show_info_sizer(); void show_sliced_info_sizer(const bool show); void show_buttons(const bool show); void show_button(ButtonAction but_action, bool show); void enable_buttons(bool enable); bool is_multifilament(); + void set_mode_value(const /*ConfigMenuIDs*/int mode) { m_mode = mode; } std::vector& combos_filament(); private: @@ -118,6 +119,7 @@ public: void select_view(const std::string& direction); void remove(size_t obj_idx); + void delete_object_from_model(size_t obj_idx); void remove_selected(); void increase_instances(size_t num = 1); void decrease_instances(size_t num = 1); @@ -137,7 +139,7 @@ public: void on_config_change(const DynamicPrintConfig &config); int get_selected_object_idx(); - bool is_single_full_object_selection(); + bool is_single_full_object_selection() const; wxGLCanvas* canvas3D(); PrinterTechnology printer_technology() const;