diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 8531ab07e..81627347b 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -1263,10 +1263,10 @@ ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z, ModelObjectCutAttr instances[instance]->get_mirror() ); - z -= instances[instance]->get_offset()(2); + z -= instances[instance]->get_offset().z(); - // Lower part per-instance bounding boxes - std::vector lower_bboxes { instances.size() }; + // Displacement (in instance coordinates) to be applied to place the upper parts + Vec3d local_displace = Vec3d::Zero(); for (ModelVolume *volume : volumes) { const auto volume_matrix = volume->get_matrix(); @@ -1286,8 +1286,7 @@ ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z, ModelObjectCutAttr if (attributes.has(ModelObjectCutAttribute::KeepLower)) lower->add_volume(*volume); } - else if (! volume->mesh().empty()) { - + else if (! volume->mesh().empty()) { // Transform the mesh by the combined transformation matrix. // Flip the triangles in case the composite transformation is left handed. TriangleMesh mesh(volume->mesh()); @@ -1327,13 +1326,10 @@ ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z, ModelObjectCutAttr assert(vol->config.id() != volume->config.id()); vol->set_material(volume->material_id(), *volume->material()); - // Compute the lower part instances' bounding boxes to figure out where to place - // the upper part - 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)); - } - } + // Compute the displacement (in instance coordinates) to be applied to place the upper parts + // The upper part displacement is set to half of the lower part bounding box + // this is done in hope at least a part of the upper part will always be visible and draggable + local_displace = lower->full_raw_mesh_bounding_box().size().cwiseProduct(Vec3d(-0.5, -0.5, 0.0)); } } } @@ -1341,17 +1337,18 @@ ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z, ModelObjectCutAttr ModelObjectPtrs res; if (attributes.has(ModelObjectCutAttribute::KeepUpper) && upper->volumes.size() > 0) { - upper->invalidate_bounding_box(); - upper->center_around_origin(); + if (!upper->origin_translation.isApprox(Vec3d::Zero()) && instances[instance]->get_offset().isApprox(Vec3d::Zero())) { + upper->center_around_origin(); + upper->translate_instances(-upper->origin_translation); + upper->origin_translation = Vec3d::Zero(); + } // Reset instance transformation except offset and Z-rotation - for (size_t i = 0; i < instances.size(); i++) { + for (size_t i = 0; i < instances.size(); ++i) { auto &instance = upper->instances[i]; const Vec3d offset = instance->get_offset(); - const double rot_z = instance->get_rotation()(2); - // The upper part displacement is set to half of the lower part bounding box - // this is done in hope at least a part of the upper part will always be visible and draggable - const Vec3d displace = lower_bboxes[i].size().cwiseProduct(Vec3d(-0.5, -0.5, 0.0)); + const double rot_z = instance->get_rotation().z(); + const Vec3d displace = Geometry::assemble_transform(Vec3d::Zero(), instance->get_rotation()) * local_displace; instance->set_transformation(Geometry::Transformation()); instance->set_offset(offset + displace); @@ -1361,14 +1358,16 @@ ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z, ModelObjectCutAttr res.push_back(upper); } if (attributes.has(ModelObjectCutAttribute::KeepLower) && lower->volumes.size() > 0) { - lower->invalidate_bounding_box(); - lower->center_around_origin(); + if (!lower->origin_translation.isApprox(Vec3d::Zero()) && instances[instance]->get_offset().isApprox(Vec3d::Zero())) { + lower->center_around_origin(); + lower->translate_instances(-lower->origin_translation); + lower->origin_translation = Vec3d::Zero(); + } // Reset instance transformation except offset and Z-rotation for (auto *instance : lower->instances) { const Vec3d offset = instance->get_offset(); - const double rot_z = instance->get_rotation()(2); - + const double rot_z = instance->get_rotation().z(); instance->set_transformation(Geometry::Transformation()); instance->set_offset(offset); instance->set_rotation(Vec3d(attributes.has(ModelObjectCutAttribute::FlipLower) ? Geometry::deg2rad(180.0) : 0.0, 0.0, rot_z)); diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 8a24bee2e..7674fe908 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -2044,8 +2044,7 @@ void ObjectList::split() void ObjectList::merge(bool to_multipart_object) { // merge selected objects to the multipart object - if (to_multipart_object) - { + if (to_multipart_object) { auto get_object_idxs = [this](std::vector& obj_idxs, wxDataViewItemArray& sels) { // check selections and split instances to the separated objects... @@ -2056,8 +2055,7 @@ void ObjectList::merge(bool to_multipart_object) break; } - if (!instance_selection) - { + if (!instance_selection) { for (wxDataViewItem item : sels) { assert(m_objects_model->GetItemType(item) & itObject); obj_idxs.emplace_back(m_objects_model->GetIdByItem(item)); @@ -2069,8 +2067,7 @@ void ObjectList::merge(bool to_multipart_object) std::map> sel_map; std::set empty_set; for (wxDataViewItem item : sels) { - if (m_objects_model->GetItemType(item) & itObject) - { + if (m_objects_model->GetItemType(item) & itObject) { int obj_idx = m_objects_model->GetIdByItem(item); int inst_cnt = (*m_objects)[obj_idx]->instances.size(); if (inst_cnt == 1) @@ -2087,8 +2084,7 @@ void ObjectList::merge(bool to_multipart_object) // all objects, created from the instances will be added to the end of list int new_objects_cnt = 0; // count of this new objects - for (auto map_item : sel_map) - { + for (auto map_item : sel_map) { int obj_idx = map_item.first; // object with just 1 instance if (map_item.second.empty()) { @@ -2148,37 +2144,36 @@ void ObjectList::merge(bool to_multipart_object) new_object->name = _u8L("Merged"); ModelConfig &config = new_object->config; - for (int obj_idx : obj_idxs) - { + for (int obj_idx : obj_idxs) { ModelObject* object = (*m_objects)[obj_idx]; const Geometry::Transformation& transformation = object->instances[0]->get_transformation(); - Vec3d scale = transformation.get_scaling_factor(); - Vec3d mirror = transformation.get_mirror(); - Vec3d rotation = transformation.get_rotation(); + const Vec3d scale = transformation.get_scaling_factor(); + const Vec3d mirror = transformation.get_mirror(); + const Vec3d rotation = transformation.get_rotation(); if (object->id() == (*m_objects)[obj_idxs.front()]->id()) new_object->add_instance(); - Transform3d volume_offset_correction = new_object->instances[0]->get_transformation().get_matrix().inverse() * transformation.get_matrix(); + const Transform3d& volume_offset_correction = transformation.get_matrix(); // merge volumes for (const ModelVolume* volume : object->volumes) { ModelVolume* new_volume = new_object->add_volume(*volume); //set rotation - Vec3d vol_rot = new_volume->get_rotation() + rotation; + const Vec3d vol_rot = new_volume->get_rotation() + rotation; new_volume->set_rotation(vol_rot); // set scale - Vec3d vol_sc_fact = new_volume->get_scaling_factor().cwiseProduct(scale); + const Vec3d vol_sc_fact = new_volume->get_scaling_factor().cwiseProduct(scale); new_volume->set_scaling_factor(vol_sc_fact); // set mirror - Vec3d vol_mirror = new_volume->get_mirror().cwiseProduct(mirror); + const Vec3d vol_mirror = new_volume->get_mirror().cwiseProduct(mirror); new_volume->set_mirror(vol_mirror); // set offset - Vec3d vol_offset = volume_offset_correction* new_volume->get_offset(); + const Vec3d vol_offset = volume_offset_correction* new_volume->get_offset(); new_volume->set_offset(vol_offset); } new_object->sort_volumes(wxGetApp().app_config->get("order_volumes") == "1"); @@ -2211,6 +2206,11 @@ void ObjectList::merge(bool to_multipart_object) for (const auto& range : object->layer_config_ranges) new_object->layer_config_ranges.emplace(range); } + + new_object->center_around_origin(); + new_object->translate_instances(-new_object->origin_translation); + new_object->origin_translation = Vec3d::Zero(); + // remove selected objects remove(); @@ -2221,8 +2221,7 @@ void ObjectList::merge(bool to_multipart_object) } // merge all parts to the one single object // all part's settings will be lost - else - { + else { wxDataViewItem item = GetSelection(); if (!item) return;