Fix instance Z synchronization (#15465)

This commit is contained in:
Noisyfox
2026-10-13 22:26:53 +08:00
committed by GitHub
parent e821665e4b
commit a338f6ca7d
7 changed files with 57 additions and 84 deletions
+14 -15
View File
@@ -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 << " </" << BUILD_TAG << ">\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())
+7 -8
View File
@@ -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)
+7 -6
View File
@@ -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<ModelConfigObject const> config_wrapper(config);
Internal::StaticSerializationWrapper<LayerHeightProfile const> 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<class Archive> 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);
}
};
+6 -11
View File
@@ -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<int, int>& 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<int, int> &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<int, int>& 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<int, int>& i : done) {
ModelObject* mo = m_model->objects[i.first];
ModelInstance* mi = mo->instances[i.second];
if (!mi->auto_drop) {
if (!mo->auto_drop) {
continue;
}
+5 -13
View File
@@ -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<size_t>(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());
+2 -5
View File
@@ -10359,10 +10359,7 @@ std::vector<size_t> 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);
+16 -26
View File
@@ -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<std::pair<int, int>> instances_idxs;
std::set<int> 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<std::pair<int, int>> instances_idxs;
std::set<int> 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())