diff --git a/src/libslic3r/Format/bbs_3mf.cpp b/src/libslic3r/Format/bbs_3mf.cpp index 5419434936..082f1e31ed 100644 --- a/src/libslic3r/Format/bbs_3mf.cpp +++ b/src/libslic3r/Format/bbs_3mf.cpp @@ -987,6 +987,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) MetadataList metadata; VolumeMetadataList volumes; + bool auto_drop { true }; }; struct CutObjectInfo @@ -1367,7 +1368,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) bool _handle_start_text_configuration(const char** attributes, unsigned int num_attributes); bool _handle_start_shape_configuration(const char **attributes, unsigned int num_attributes); - bool _create_object_instance(std::string const & path, int object_id, const Transform3d& transform, const bool printable, const bool auto_drop, unsigned int recur_counter); + bool _create_object_instance(std::string const & path, int object_id, const Transform3d& transform, const bool printable, unsigned int recur_counter); void _apply_transform(ModelInstance& instance, const Transform3d& transform); @@ -2259,6 +2260,8 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) if (obj_metadata != m_objects_metadata.end()) { // config data has been found, this model was saved using slic3r pe + model_object->auto_drop = obj_metadata->second.auto_drop; + // apply object's name and config data for (const Metadata& metadata : obj_metadata->second.metadata) { if (metadata.key == "name") @@ -4117,9 +4120,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) std::string path = bbs_get_attribute_value_string(attributes, num_attributes, PPATH_ATTR); Transform3d transform = bbs_get_transform_from_3mf_specs_string(bbs_get_attribute_value_string(attributes, num_attributes, TRANSFORM_ATTR)); int printable = bbs_get_attribute_value_bool(attributes, num_attributes, PRINTABLE_ATTR); - int auto_drop = bbs_get_attribute_value_bool(attributes, num_attributes, AUTO_DROP_ATTR); - - return !m_load_model || _create_object_instance(path, object_id, transform, printable, auto_drop, 1); + return !m_load_model || _create_object_instance(path, object_id, transform, printable, 1); } bool _BBS_3MF_Importer::_handle_end_item() @@ -4347,7 +4348,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) return true; } - bool _BBS_3MF_Importer::_create_object_instance(std::string const & path, int object_id, const Transform3d& transform, const bool printable, const bool auto_drop, unsigned int recur_counter) + bool _BBS_3MF_Importer::_create_object_instance(std::string const & path, int object_id, const Transform3d& transform, const bool printable, unsigned int recur_counter) { static const unsigned int MAX_RECURSIONS = 10; @@ -4384,7 +4385,6 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) return false; } instance->printable = printable; - instance->auto_drop = auto_drop; m_instances.emplace_back(instance, transform); @@ -4417,7 +4417,6 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) return false; } instance->printable = printable; - instance->auto_drop = auto_drop; m_instances.emplace_back(instance, transform); } @@ -4488,7 +4487,9 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) // Added because of github #3435, currently not used by PrusaSlicer // int instances_count_id = bbs_get_attribute_value_int(attributes, num_attributes, INSTANCESCOUNT_ATTR); - m_objects_metadata.insert({ object_id, ObjectMetadata() }); + ObjectMetadata metadata; + metadata.auto_drop = bbs_get_attribute_value_bool(attributes, num_attributes, AUTO_DROP_ATTR); + m_objects_metadata.insert({ object_id, std::move(metadata) }); m_curr_config.object_id = object_id; return true; } @@ -6164,14 +6165,12 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) unsigned int id; Transform3d transform; bool printable; - bool auto_drop; - BuildItem(std::string const & path, unsigned int id, const Transform3d& transform, const bool printable, const bool auto_drop) + BuildItem(std::string const & path, unsigned int id, const Transform3d& transform, const bool printable) : path(path) , id(id) , transform(transform) , printable(printable) - , auto_drop(auto_drop) { } }; @@ -7412,7 +7411,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) // instance_id is just a 1 indexed index in build_items. //assert(m_skip_static || curr_id == build_items.size() + 1); - build_items.emplace_back("", object_it->second.object_id, t, instance->printable, instance->auto_drop); + build_items.emplace_back("", object_it->second.object_id, t, instance->printable); count++; } @@ -7862,8 +7861,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) stream << "\" " << PPATH_ATTR << "=\"" << xml_escape(item.path); stream << "\" " << TRANSFORM_ATTR << "=\""; add_transformation(stream, item.transform); - stream << "\" " << PRINTABLE_ATTR << "=\"" << item.printable; - stream << "\" " << AUTO_DROP_ATTR << "=\"" << item.auto_drop << "\"/>\n"; + stream << "\" " << PRINTABLE_ATTR << "=\"" << item.printable << "\"/>\n"; } stream << " \n"; @@ -8300,7 +8298,8 @@ bool _BBS_3MF_Exporter::_add_model_config_file_to_archive(mz_zip_archive& archiv if (obj != nullptr) { // Output of instances count added because of github #3435, currently not used by PrusaSlicer //stream << " <" << OBJECT_TAG << " " << ID_ATTR << "=\"" << obj_metadata.first << "\" " << INSTANCESCOUNT_ATTR << "=\"" << obj->instances.size() << "\">\n"; - stream << " <" << OBJECT_TAG << " " << ID_ATTR << "=\"" << object_data.object_id << "\">\n"; + stream << " <" << OBJECT_TAG << " " << ID_ATTR << "=\"" << object_data.object_id + << "\" " << AUTO_DROP_ATTR << "=\"" << obj->auto_drop << "\">\n"; // stores object's name if (!obj->name.empty()) diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 392f83976f..aea1b2be36 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -1280,6 +1280,7 @@ ModelObject& ModelObject::assign_copy(const ModelObject &rhs) this->layer_config_ranges = rhs.layer_config_ranges; this->layer_height_profile = rhs.layer_height_profile; this->printable = rhs.printable; + this->auto_drop = rhs.auto_drop; this->origin_translation = rhs.origin_translation; this->cut_id.copy(rhs.cut_id); this->copy_transformation_caches(rhs); @@ -1320,6 +1321,7 @@ ModelObject& ModelObject::assign_copy(ModelObject &&rhs) this->layer_config_ranges = std::move(rhs.layer_config_ranges); this->layer_height_profile = std::move(rhs.layer_height_profile); this->printable = std::move(rhs.printable); + this->auto_drop = rhs.auto_drop; this->origin_translation = std::move(rhs.origin_translation); this->copy_transformation_caches(rhs); @@ -1889,6 +1891,9 @@ void ModelObject::center_around_origin(bool include_modifiers) void ModelObject::ensure_on_bed(bool allow_negative_z) { + if (!auto_drop) + return; + double z_offset = 0.0; if (allow_negative_z) { @@ -1907,14 +1912,8 @@ void ModelObject::ensure_on_bed(bool allow_negative_z) else z_offset = -this->min_z(); - if (z_offset != 0.0) { - for (size_t i = 0; i < instances.size(); ++i) { - if (!instances[i]->auto_drop) - continue; - - translate_instance(i, z_offset * Vec3d::UnitZ()); - } - } + if (z_offset != 0.0) + translate_instances(z_offset * Vec3d::UnitZ()); } void ModelObject::translate_instances(const Vec3d& vector) diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index d7859446b5..ea0a02cbe0 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -400,6 +400,9 @@ public: LayerHeightProfile layer_height_profile; // Whether or not this object is printable bool printable { true }; + // Whether this object is snapped to the build plate after transformations. + // Instance Z offsets are shared by all instances of an object. + bool auto_drop { true }; // This vector holds position of selected support points for SLA. The data are // saved in mesh coordinates to allow using them for several instances. @@ -706,7 +709,7 @@ private: Internal::StaticSerializationWrapper config_wrapper(config); Internal::StaticSerializationWrapper layer_heigth_profile_wrapper(layer_height_profile); ar(name, module_name, input_file, instances, volumes, config_wrapper, layer_config_ranges, layer_heigth_profile_wrapper, - sla_support_points, sla_points_status, sla_drain_holes, printable, origin_translation, brim_points, + sla_support_points, sla_points_status, sla_drain_holes, printable, auto_drop, origin_translation, brim_points, m_bounding_box_approx, m_bounding_box_approx_valid, m_bounding_box_exact, m_bounding_box_exact_valid, m_min_max_z_valid, m_raw_bounding_box, m_raw_bounding_box_valid, m_raw_mesh_bounding_box, m_raw_mesh_bounding_box_valid, @@ -719,7 +722,7 @@ private: // BBS: add backup, check modify SaveObjectGaurd gaurd(*this); ar(name, module_name, input_file, instances, volumes, config_wrapper, layer_config_ranges, layer_heigth_profile_wrapper, - sla_support_points, sla_points_status, sla_drain_holes, printable, origin_translation, brim_points, + sla_support_points, sla_points_status, sla_drain_holes, printable, auto_drop, origin_translation, brim_points, m_bounding_box_approx, m_bounding_box_approx_valid, m_bounding_box_exact, m_bounding_box_exact_valid, m_min_max_z_valid, m_raw_bounding_box, m_raw_bounding_box_valid, m_raw_mesh_bounding_box, m_raw_mesh_bounding_box_valid, @@ -1427,7 +1430,6 @@ public: ModelInstanceEPrintVolumeState print_volume_state; // Whether or not this instance is printable bool printable; - bool auto_drop; bool use_loaded_id_for_label {false}; int arrange_order = 0; // BBS size_t loaded_id = 0; // BBS @@ -1557,7 +1559,7 @@ private: // Constructor, which assigns a new unique ID. explicit ModelInstance(ModelObject* object) - : print_volume_state(ModelInstancePVS_Inside), printable(true), auto_drop(true), object(object), m_assemble_initialized(false) + : print_volume_state(ModelInstancePVS_Inside), printable(true), object(object), m_assemble_initialized(false) { assert(this->id().valid()); } @@ -1568,7 +1570,6 @@ private: , m_offset_to_assembly(other.m_offset_to_assembly) , print_volume_state(ModelInstancePVS_Inside) , printable(other.printable) - , auto_drop(other.auto_drop) , object(object) , m_assemble_initialized(false) { assert(this->id().valid() && this->id() != other.id()); } @@ -1582,7 +1583,7 @@ private: ModelInstance() : ObjectBase(-1), object(nullptr) { assert(this->id().invalid()); } // BBS. Add added members to archive. template void serialize(Archive& ar) { - ar(m_transformation, print_volume_state, printable, auto_drop, m_assemble_transformation, m_offset_to_assembly, m_assemble_initialized); + ar(m_transformation, print_volume_state, printable, m_assemble_transformation, m_offset_to_assembly, m_assemble_initialized); } }; diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 0873444fc8..de838f5a2b 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -3053,10 +3053,9 @@ void GLCanvas3D::ensure_on_bed(unsigned int object_idx, bool allow_negative_z) InstancesToZMap instances_min_z; for (GLVolume* volume : m_volumes.volumes) { - ModelObject* mo = m_model->objects[volume->object_idx()]; - ModelInstance* mi = mo->instances[volume->instance_idx()]; + ModelObject* mo = m_model->objects[volume->object_idx()]; - if (!mi->auto_drop) { + if (!mo->auto_drop) { continue; } @@ -5604,9 +5603,8 @@ void GLCanvas3D::do_move(const std::string& snapshot_type) // Fixes sinking/flying instances (snaps object to buildplate) for (const std::pair& i : done) { ModelObject* mo = m_model->objects[i.first]; - ModelInstance* mi = mo->instances[i.second]; - if (!mi->auto_drop) { + if (!mo->auto_drop) { continue; } @@ -5735,9 +5733,8 @@ void GLCanvas3D::do_rotate(const std::string& snapshot_type) // Fixes sinking/flying instances (snaps object to buildplate) for (const std::pair &i : done) { ModelObject *mo = m_model->objects[i.first]; - ModelInstance* mi = mo->instances[i.second]; - if (!mi->auto_drop) { + if (!mo->auto_drop) { continue; } @@ -5838,9 +5835,8 @@ void GLCanvas3D::do_scale(const std::string& snapshot_type) // Fixes sinking/flying instances (snaps object to buildplate) for (const std::pair& i : done) { ModelObject* mo = m_model->objects[i.first]; - ModelInstance* mi = mo->instances[i.second]; - if (!mi->auto_drop) { + if (!mo->auto_drop) { continue; } @@ -5959,9 +5955,8 @@ void GLCanvas3D::do_mirror(const std::string& snapshot_type) // Fixes sinking/flying instances (snaps object to buildplate) for (const std::pair& i : done) { ModelObject* mo = m_model->objects[i.first]; - ModelInstance* mi = mo->instances[i.second]; - if (!mi->auto_drop) { + if (!mo->auto_drop) { continue; } diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 40ba495349..e7d1041cb6 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -3234,8 +3234,8 @@ void ObjectList::merge(bool to_multipart_object) new_object->printable = false; new_object->instances[0]->printable = false; } - if (object->instances[0]->auto_drop == false) { - new_object->instances[0]->auto_drop = false; + if (object->auto_drop == false) { + new_object->auto_drop = false; } // merge layers @@ -7098,18 +7098,10 @@ void ObjectList::toggle_auto_drop() obj_idxs.emplace_back(static_cast(obj_idx)); - ItemType type = m_objects_model->GetItemType(item); - // set auto_drop value for selected instance/instances in object - if (type == itInstance) { - int inst_idx = m_objects_model->GetInstanceIdByItem(item); - obj->instances[inst_idx]->auto_drop = !current_auto_drop; - } else { - for (auto inst : obj->instances) - inst->auto_drop = !current_auto_drop; - - if (current_auto_drop == false) + // auto_drop is shared by all instances of an object. + obj->auto_drop = !current_auto_drop; + if (current_auto_drop == false) obj->ensure_on_bed(); - } } sort(obj_idxs.begin(), obj_idxs.end()); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index d2b788966e..303f50d8d4 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -10359,10 +10359,7 @@ std::vector Plater::priv::load_model_objects(const ModelObjectPtrs& mode } if (!auto_drop) { - for (size_t i = 0; i < object->instances.size(); ++i) { - ModelInstance* instance = object->instances[i]; - instance->auto_drop = auto_drop; - } + object->auto_drop = false; // if under the bed, move over the bed double dist_to_bed = std::min(object->min_z(), double(0)); @@ -10991,7 +10988,7 @@ void Plater::priv::split_object(int obj_idx, bool auto_drop /* = true */) return false; }; bool split_auto_drop = auto_drop; - if (current_model_object->instances[0]->auto_drop && is_atleast_one_floating()) { + if (current_model_object->auto_drop && is_atleast_one_floating()) { MessageDialog dlg(q, _L("Disable Auto-Drop to preserve Z positioning?\n"), _L("Object with floating parts was detected"), wxICON_QUESTION | wxYES_NO); diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index c19ed2fe43..db27a05ac6 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -638,26 +638,21 @@ void Selection::set_printable(bool printable) } bool Selection::get_auto_drop() const { - // The wipe tower is not a ModelObject and has no per-instance auto_drop; + // The wipe tower is not a ModelObject and has no auto_drop state; // return the default to avoid indexing m_model->objects with its synthetic id. if (!m_valid || is_wipe_tower()) return true; - std::set> instances_idxs; + std::set object_idxs; for (const auto& [obj_idx, inst_list] : m_cache.content) { - for (int inst_idx : inst_list) { - instances_idxs.insert({obj_idx, inst_idx}); - } + object_idxs.insert(obj_idx); } - // return false, if one of the instances in the selection has auto_drop disabled, otherwise return true - for (const auto& [obj_idx, inst_idx] : instances_idxs) { + // Return false if one selected object has auto_drop disabled. + for (int obj_idx : object_idxs) { ModelObject* object = m_model->objects[obj_idx]; - for (const auto* inst : object->instances) { - if (!inst->auto_drop) { - return false; - } - } + if (!object->auto_drop) + return false; } return true; @@ -668,22 +663,18 @@ void Selection::set_auto_drop(bool enabled) if (!m_valid) return; - std::set> instances_idxs; + std::set object_idxs; for (const auto& [obj_idx, inst_list] : m_cache.content) { - for (int inst_idx : inst_list) { - instances_idxs.insert({obj_idx, inst_idx}); - } + object_idxs.insert(obj_idx); } std::string snapshot_text = (boost::format("%1%") % (enabled ? "Set Selection Auto-Drop Enabled" : "Set Selection Auto-Drop Disabled")).str(); wxGetApp().plater()->take_snapshot(snapshot_text); - // set auto_drop value for all instances in object - for (const auto& [obj_idx, inst_idx] : instances_idxs) { + // auto_drop is shared by all instances of an object. + for (int obj_idx : object_idxs) { ModelObject* object = m_model->objects[obj_idx]; - for (auto* inst : object->instances) { - inst->auto_drop = enabled; - } + object->auto_drop = enabled; } // update scene @@ -3088,8 +3079,9 @@ void Selection::synchronize_unselected_instances(SyncRotationType sync_rotation_ else if (sync_rotation_type != SyncRotationType::NONE || mirrored) new_inst_trafo_j.linear() = (old_inst_trafo_j.linear() * old_inst_trafo_i.linear().inverse()) * curr_inst_trafo_i.linear(); - bool should_synchronize_z = m_model->objects[volume_j->object_idx()]->instances[volume_j->instance_idx()]->auto_drop == false; - if (should_synchronize_z && wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA) + // Instances of the same object must remain at the same height. auto_drop + // only controls snapping after the move, not the instance transform itself. + if (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA) new_inst_trafo_j.translation().z() = curr_inst_trafo_i.translation().z(); assert(is_rotation_xy_synchronized(curr_inst_trafo_i, new_inst_trafo_j)); @@ -3136,9 +3128,7 @@ void Selection::ensure_on_bed() for (size_t i = 0; i < m_volumes->size(); ++i) { GLVolume* volume = (*m_volumes)[i]; ModelObject* mo = m_model->objects[volume->object_idx()]; - ModelInstance* mi = mo->instances[volume->instance_idx()]; - - if (mi->auto_drop == false + if (mo->auto_drop == false || volume->is_wipe_tower || volume->is_modifier || std::find(m_cache.sinking_volumes.begin(), m_cache.sinking_volumes.end(), i) != m_cache.sinking_volumes.end())