From e4e8c5df129b1f90cca148c03e10d8a4e2126da8 Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Sun, 27 Jun 2021 17:36:25 +0200 Subject: [PATCH] As an example of using the enum_bitmask infrastructure for type safe sets of optional boolean parameters, the cut function "keep upper", "keep lower" and "flip lower" boolean parameters were converted into a single type safe enum_bitmask. Such a coding style is certainly wordier than the original code, but much safer and more readable than the error prone "boolean, boolean, boolean" function call parameter list. --- src/PrusaSlicer.cpp | 2 +- src/libslic3r/Model.cpp | 35 +++++++++++++++------------- src/libslic3r/Model.hpp | 7 +++++- src/slic3r/GUI/Gizmos/GLGizmoCut.cpp | 6 ++++- src/slic3r/GUI/Plater.cpp | 9 +++---- src/slic3r/GUI/Plater.hpp | 5 +++- 6 files changed, 38 insertions(+), 26 deletions(-) diff --git a/src/PrusaSlicer.cpp b/src/PrusaSlicer.cpp index 5212d66c8..3f43c3ebd 100644 --- a/src/PrusaSlicer.cpp +++ b/src/PrusaSlicer.cpp @@ -376,7 +376,7 @@ int CLI::run(int argc, char **argv) o->cut(Z, m_config.opt_float("cut"), &out); } #else - model.objects.front()->cut(0, m_config.opt_float("cut"), true, true, true); + model.objects.front()->cut(0, m_config.opt_float("cut"), ModelObjectCutAttribute::KeepLower | ModelObjectCutAttribute::KeepUpper | ModelObjectCutAttribute::FlipLower); #endif model.delete_object(size_t(0)); } diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 5943f960e..3ddf65333 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -1143,17 +1143,18 @@ bool ModelObject::needed_repair() const return false; } -ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z, bool keep_upper, bool keep_lower, bool rotate_lower) +ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z, ModelObjectCutAttributes attributes) { - if (!keep_upper && !keep_lower) { return {}; } + if (! attributes.has(ModelObjectCutAttribute::KeepUpper) && ! attributes.has(ModelObjectCutAttribute::KeepLower)) + return {}; BOOST_LOG_TRIVIAL(trace) << "ModelObject::cut - start"; // Clone the object to duplicate instances, materials etc. - ModelObject* upper = keep_upper ? ModelObject::new_clone(*this) : nullptr; - ModelObject* lower = keep_lower ? ModelObject::new_clone(*this) : nullptr; + ModelObject* upper = attributes.has(ModelObjectCutAttribute::KeepUpper) ? ModelObject::new_clone(*this) : nullptr; + ModelObject* lower = attributes.has(ModelObjectCutAttribute::KeepLower) ? ModelObject::new_clone(*this) : nullptr; - if (keep_upper) { + if (attributes.has(ModelObjectCutAttribute::KeepUpper)) { upper->set_model(nullptr); upper->sla_support_points.clear(); upper->sla_drain_holes.clear(); @@ -1162,7 +1163,7 @@ ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z, bool keep_upper, b upper->input_file.clear(); } - if (keep_lower) { + if (attributes.has(ModelObjectCutAttribute::KeepLower)) { lower->set_model(nullptr); lower->sla_support_points.clear(); lower->sla_drain_holes.clear(); @@ -1202,8 +1203,10 @@ ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z, bool keep_upper, b volume->set_transformation(Geometry::Transformation(instance_matrix * volume_matrix)); - if (keep_upper) { upper->add_volume(*volume); } - if (keep_lower) { lower->add_volume(*volume); } + if (attributes.has(ModelObjectCutAttribute::KeepUpper)) + upper->add_volume(*volume); + if (attributes.has(ModelObjectCutAttribute::KeepLower)) + lower->add_volume(*volume); } else if (! volume->mesh().empty()) { @@ -1223,19 +1226,19 @@ ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z, bool keep_upper, b indexed_triangle_set upper_its, lower_its; mesh.require_shared_vertices(); cut_mesh(mesh.its, float(z), &upper_its, &lower_its); - if (keep_upper) { + if (attributes.has(ModelObjectCutAttribute::KeepUpper)) { upper_mesh = TriangleMesh(upper_its); upper_mesh.repair(); upper_mesh.reset_repair_stats(); } - if (keep_lower) { + if (attributes.has(ModelObjectCutAttribute::KeepLower)) { lower_mesh = TriangleMesh(lower_its); lower_mesh.repair(); lower_mesh.reset_repair_stats(); } } - if (keep_upper && upper_mesh.facets_count() > 0) { + if (attributes.has(ModelObjectCutAttribute::KeepUpper) && upper_mesh.facets_count() > 0) { ModelVolume* vol = upper->add_volume(upper_mesh); vol->name = volume->name; // Don't copy the config's ID. @@ -1244,7 +1247,7 @@ ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z, bool keep_upper, b assert(vol->config.id() != volume->config.id()); vol->set_material(volume->material_id(), *volume->material()); } - if (keep_lower && lower_mesh.facets_count() > 0) { + if (attributes.has(ModelObjectCutAttribute::KeepLower) && lower_mesh.facets_count() > 0) { ModelVolume* vol = lower->add_volume(lower_mesh); vol->name = volume->name; // Don't copy the config's ID. @@ -1255,7 +1258,7 @@ ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z, bool keep_upper, b // Compute the lower part instances' bounding boxes to figure out where to place // the upper part - if (keep_upper) { + if (attributes.has(ModelObjectCutAttribute::KeepUpper)) { for (size_t i = 0; i < instances.size(); i++) { lower_bboxes[i].merge(instances[i]->transform_mesh_bounding_box(lower_mesh, true)); } @@ -1266,7 +1269,7 @@ ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z, bool keep_upper, b ModelObjectPtrs res; - if (keep_upper && upper->volumes.size() > 0) { + if (attributes.has(ModelObjectCutAttribute::KeepUpper) && upper->volumes.size() > 0) { upper->invalidate_bounding_box(); upper->center_around_origin(); @@ -1286,7 +1289,7 @@ ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z, bool keep_upper, b res.push_back(upper); } - if (keep_lower && lower->volumes.size() > 0) { + if (attributes.has(ModelObjectCutAttribute::KeepLower) && lower->volumes.size() > 0) { lower->invalidate_bounding_box(); lower->center_around_origin(); @@ -1297,7 +1300,7 @@ ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z, bool keep_upper, b instance->set_transformation(Geometry::Transformation()); instance->set_offset(offset); - instance->set_rotation(Vec3d(rotate_lower ? Geometry::deg2rad(180.0) : 0.0, 0.0, rot_z)); + instance->set_rotation(Vec3d(attributes.has(ModelObjectCutAttribute::FlipLower) ? Geometry::deg2rad(180.0) : 0.0, 0.0, rot_z)); } res.push_back(lower); diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index f835aa0ea..59ab14b4c 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -2,6 +2,7 @@ #define slic3r_Model_hpp_ #include "libslic3r.h" +#include "enum_bitmask.hpp" #include "Geometry.hpp" #include "ObjectID.hpp" #include "Point.hpp" @@ -227,6 +228,10 @@ enum class ModelVolumeType : int { SUPPORT_ENFORCER, }; +enum class ModelObjectCutAttribute : int { KeepUpper, KeepLower, FlipLower }; +using ModelObjectCutAttributes = enum_bitmask; +ENABLE_ENUM_BITMASK_OPERATORS(ModelObjectCutAttribute); + // A printable object, possibly having multiple print volumes (each with its own set of parameters and materials), // and possibly having multiple modifier volumes, each modifier volume with its set of parameters and materials. // Each ModelObject may be instantiated mutliple times, each instance having different placement on the print bed, @@ -345,7 +350,7 @@ public: size_t materials_count() const; size_t facets_count() const; bool needed_repair() const; - ModelObjectPtrs cut(size_t instance, coordf_t z, bool keep_upper = true, bool keep_lower = true, bool rotate_lower = false); // Note: z is in world coordinates + ModelObjectPtrs cut(size_t instance, coordf_t z, ModelObjectCutAttributes attributes); void split(ModelObjectPtrs* new_objects); void merge(); // Support for non-uniform scaling of instances. If an instance is rotated by angles, which are not multiples of ninety degrees, diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp index f0813732f..9499bd6de 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp @@ -15,6 +15,7 @@ #include "slic3r/GUI/Plater.hpp" #include "slic3r/GUI/GUI_ObjectManipulation.hpp" #include "libslic3r/AppConfig.hpp" +#include "libslic3r/Model.hpp" namespace Slic3r { @@ -231,7 +232,10 @@ void GLGizmoCut::perform_cut(const Selection& selection) coordf_t object_cut_z = m_cut_z - first_glvolume->get_sla_shift_z(); if (object_cut_z > 0.) - wxGetApp().plater()->cut(object_idx, instance_idx, object_cut_z, m_keep_upper, m_keep_lower, m_rotate_lower); + wxGetApp().plater()->cut(object_idx, instance_idx, object_cut_z, + only_if(m_keep_upper, ModelObjectCutAttribute::KeepUpper) | + only_if(m_keep_lower, ModelObjectCutAttribute::KeepLower) | + only_if(m_rotate_lower, ModelObjectCutAttribute::FlipLower)); else { // the object is SLA-elevated and the plane is under it. } diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 0c34f21dd..7460b43dd 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -5315,21 +5315,20 @@ void Plater::toggle_layers_editing(bool enable) wxPostEvent(canvas3D()->get_wxglcanvas(), SimpleEvent(EVT_GLTOOLBAR_LAYERSEDITING)); } -void Plater::cut(size_t obj_idx, size_t instance_idx, coordf_t z, bool keep_upper, bool keep_lower, bool rotate_lower) +void Plater::cut(size_t obj_idx, size_t instance_idx, coordf_t z, ModelObjectCutAttributes attributes) { wxCHECK_RET(obj_idx < p->model.objects.size(), "obj_idx out of bounds"); auto *object = p->model.objects[obj_idx]; wxCHECK_RET(instance_idx < object->instances.size(), "instance_idx out of bounds"); - if (!keep_upper && !keep_lower) { + if (! attributes.has(ModelObjectCutAttribute::KeepUpper) && ! attributes.has(ModelObjectCutAttribute::KeepLower)) return; - } Plater::TakeSnapshot snapshot(this, _L("Cut by Plane")); wxBusyCursor wait; - const auto new_objects = object->cut(instance_idx, z, keep_upper, keep_lower, rotate_lower); + const auto new_objects = object->cut(instance_idx, z, attributes); remove(obj_idx); p->load_model_objects(new_objects); @@ -5337,9 +5336,7 @@ void Plater::cut(size_t obj_idx, size_t instance_idx, coordf_t z, bool keep_uppe Selection& selection = p->get_selection(); size_t last_id = p->model.objects.size() - 1; for (size_t i = 0; i < new_objects.size(); ++i) - { selection.add_object((unsigned int)(last_id - i), i == 0); - } } void Plater::export_gcode(bool prefer_removable) diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index 49bc952b8..6f69ee4dc 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -9,6 +9,7 @@ #include "Selection.hpp" +#include "libslic3r/enum_bitmask.hpp" #include "libslic3r/Preset.hpp" #include "libslic3r/BoundingBox.hpp" #include "libslic3r/GCode/GCodeProcessor.hpp" @@ -24,6 +25,8 @@ namespace Slic3r { class Model; class ModelObject; +enum class ModelObjectCutAttribute : int; +using ModelObjectCutAttributes = enum_bitmask; class ModelInstance; class Print; class SLAPrint; @@ -204,7 +207,7 @@ public: void convert_unit(ConversionType conv_type); void toggle_layers_editing(bool enable); - void cut(size_t obj_idx, size_t instance_idx, coordf_t z, bool keep_upper = true, bool keep_lower = true, bool rotate_lower = false); + void cut(size_t obj_idx, size_t instance_idx, coordf_t z, ModelObjectCutAttributes attributes); void export_gcode(bool prefer_removable); void export_stl(bool extended = false, bool selection_only = false);