diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index 2e92c8b6b0..bd48e14c12 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -801,6 +801,131 @@ const BoundingBoxf3& Selection::get_full_unscaled_instance_local_bounding_box() } return *m_full_unscaled_instance_local_bounding_box; } + +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +const std::pair& Selection::get_bounding_box_in_current_reference_system() const +{ + static int last_coordinates_type = -1; + + assert(!is_empty()); + + ECoordinatesType coordinates_type = wxGetApp().obj_manipul()->get_coordinates_type(); + if (m_mode == Instance && coordinates_type == ECoordinatesType::Local) + coordinates_type = ECoordinatesType::World; + + if (last_coordinates_type != int(coordinates_type)) + const_cast>*>(&m_bounding_box_in_current_reference_system)->reset(); + + if (!m_bounding_box_in_current_reference_system.has_value()) { + last_coordinates_type = int(coordinates_type); + + BoundingBoxf3 original_box; + Transform3d trafo; + + // + // calculate box aligned to current reference system + // + switch (coordinates_type) + { + case ECoordinatesType::World: + { + original_box = get_bounding_box(); + trafo = Transform3d::Identity(); + break; + } + case ECoordinatesType::Instance: { + for (unsigned int id : m_list) { + const GLVolume& v = *get_volume(id); + original_box.merge(v.transformed_convex_hull_bounding_box(v.get_volume_transformation().get_matrix())); + } + trafo = get_first_volume()->get_instance_transformation().get_matrix(); + break; + } + case ECoordinatesType::Local: { + assert(is_single_volume_or_modifier()); + const GLVolume& v = *get_first_volume(); + original_box = v.bounding_box(); + trafo = v.world_matrix(); + break; + } + } + + // + // calculate box size in world coordinates + // + auto point_to_Vec4d = [](const Vec3d& p) { return Vec4d(p.x(), p.y(), p.z(), 1.0); }; + auto Vec4d_to_Vec3d = [](const Vec4d& v) { return Vec3d(v.x(), v.y(), v.z()); }; + + auto apply_transform = [](const std::vector& original, const Transform3d& trafo, bool normalize) { + std::vector transformed(original.size()); + for (size_t i = 0; i < original.size(); ++i) { + transformed[i] = trafo * original[i]; + if (normalize) + transformed[i].normalize(); + } + return transformed; + }; + + auto calc_box_size = [point_to_Vec4d, Vec4d_to_Vec3d, apply_transform](const BoundingBoxf3& box, const Transform3d& trafo) { + Geometry::Transformation transformation(trafo); + + // box aligned to current reference system + std::vector homo_vertices = { + point_to_Vec4d({ box.min.x(), box.min.y(), box.min.z() }), + point_to_Vec4d({ box.max.x(), box.min.y(), box.min.z() }), + point_to_Vec4d({ box.max.x(), box.max.y(), box.min.z() }), + point_to_Vec4d({ box.min.x(), box.max.y(), box.min.z() }), + point_to_Vec4d({ box.min.x(), box.min.y(), box.max.z() }), + point_to_Vec4d({ box.max.x(), box.min.y(), box.max.z() }), + point_to_Vec4d({ box.max.x(), box.max.y(), box.max.z() }), + point_to_Vec4d({ box.min.x(), box.max.y(), box.max.z() }) + }; + + // box vertices in world coordinates + std::vector transformed_homo_vertices = apply_transform(homo_vertices, trafo, false); + + // project back to current reference system + const std::vector homo_axes = { Vec4d::UnitX(), Vec4d::UnitY(), Vec4d::UnitZ() }; + std::vector transformed_homo_axes = apply_transform(homo_axes, Geometry::Transformation(trafo).get_matrix_no_scaling_factor(), true); + std::vector transformed_axes(transformed_homo_axes.size()); + for (size_t i = 0; i < transformed_homo_axes.size(); ++i) { + transformed_axes[i] = Vec4d_to_Vec3d(transformed_homo_axes[i]); + } + + Vec3d min = { DBL_MAX, DBL_MAX, DBL_MAX }; + Vec3d max = { -DBL_MAX, -DBL_MAX, -DBL_MAX }; + + for (const Vec4d& v_homo : transformed_homo_vertices) { + const Vec3d v = Vec4d_to_Vec3d(v_homo); + for (int i = 0; i < 3; ++i) { + const double dot_i = v.dot(transformed_axes[i]); + min(i) = std::min(min(i), dot_i); + max(i) = std::max(max(i), dot_i); + } + } + + // return size + const Vec3d size = max - min; + return size; + }; + + const Vec3d box_size = calc_box_size(original_box, trafo); + const std::vector box_center = { point_to_Vec4d(original_box.center()) }; + std::vector transformed_box_center = apply_transform(box_center, trafo, false); + + // + // return box centered at 0, 0, 0 + // + const Vec3d half_box_size = 0.5 * box_size; + BoundingBoxf3 out_box(-half_box_size, half_box_size); + Geometry::Transformation out_trafo(trafo); + out_trafo.set_offset(Vec4d_to_Vec3d(transformed_box_center[0])); + *const_cast>*>(&m_bounding_box_in_current_reference_system) = { out_box, out_trafo.get_matrix_no_scaling_factor() }; + } + + return *m_bounding_box_in_current_reference_system; +} +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #endif // ENABLE_WORLD_COORDINATE void Selection::setup_cache() @@ -2669,88 +2794,88 @@ void Selection::render_sidebar_layers_hints(const std::string& sidebar_field, GL #if ENABLE_WORLD_COORDINATE_DEBUG void Selection::render_debug_window() const { - if (m_list.empty()) - return; + if (m_list.empty()) + return; - if (get_first_volume()->is_wipe_tower) - return; + if (get_first_volume()->is_wipe_tower) + return; - ImGuiWrapper& imgui = *wxGetApp().imgui(); - imgui.begin(std::string("Selection matrices"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize); + ImGuiWrapper& imgui = *wxGetApp().imgui(); + imgui.begin(std::string("Selection matrices"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize); - auto volume_name = [this](size_t id) { - const GLVolume& v = *(*m_volumes)[id]; - return m_model->objects[v.object_idx()]->volumes[v.volume_idx()]->name; - }; + auto volume_name = [this](size_t id) { + const GLVolume& v = *(*m_volumes)[id]; + return m_model->objects[v.object_idx()]->volumes[v.volume_idx()]->name; + }; - static size_t current_cmb_idx = 0; - static size_t current_vol_idx = *m_list.begin(); + static size_t current_cmb_idx = 0; + static size_t current_vol_idx = *m_list.begin(); - if (m_list.find(current_vol_idx) == m_list.end()) - current_vol_idx = *m_list.begin(); + if (m_list.find(current_vol_idx) == m_list.end()) + current_vol_idx = *m_list.begin(); - if (ImGui::BeginCombo("Volumes", volume_name(current_vol_idx).c_str())) { - size_t count = 0; - for (unsigned int id : m_list) { - const GLVolume& v = *(*m_volumes)[id]; - const bool is_selected = (current_cmb_idx == count); - if (ImGui::Selectable(volume_name(id).c_str(), is_selected)) { - current_cmb_idx = count; - current_vol_idx = id; - } - if (is_selected) - ImGui::SetItemDefaultFocus(); - ++count; - } - ImGui::EndCombo(); - } - - static int current_method_idx = 0; - ImGui::Combo("Decomposition method", ¤t_method_idx, "computeRotationScaling\0computeScalingRotation\0"); - - const GLVolume& v = *get_volume(current_vol_idx); - - auto add_matrix = [&imgui](const std::string& name, const Transform3d& m, unsigned int size) { - ImGui::BeginGroup(); - imgui.text(name); - if (ImGui::BeginTable(name.c_str(), size, ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersInner)) { - for (unsigned int r = 0; r < size; ++r) { - ImGui::TableNextRow(); - for (unsigned int c = 0; c < size; ++c) { - ImGui::TableSetColumnIndex(c); - imgui.text(std::to_string(m(r, c))); + if (ImGui::BeginCombo("Volumes", volume_name(current_vol_idx).c_str())) { + size_t count = 0; + for (unsigned int id : m_list) { + const GLVolume& v = *(*m_volumes)[id]; + const bool is_selected = (current_cmb_idx == count); + if (ImGui::Selectable(volume_name(id).c_str(), is_selected)) { + current_cmb_idx = count; + current_vol_idx = id; + } + if (is_selected) + ImGui::SetItemDefaultFocus(); + ++count; } - } - ImGui::EndTable(); + ImGui::EndCombo(); } - ImGui::EndGroup(); - }; - auto add_matrices_set = [add_matrix](const std::string& name, const Transform3d& m, size_t method) { - static unsigned int counter = 0; - ++counter; - if (ImGui::CollapsingHeader(name.c_str(), ImGuiTreeNodeFlags_DefaultOpen)) { - add_matrix("Full", m, 4); + static int current_method_idx = 0; + ImGui::Combo("Decomposition method", ¤t_method_idx, "computeRotationScaling\0computeScalingRotation\0"); - Matrix3d rotation; - Matrix3d scale; - if (method == 0) - m.computeRotationScaling(&rotation, &scale); - else - m.computeScalingRotation(&scale, &rotation); + const GLVolume& v = *get_volume(current_vol_idx); - ImGui::SameLine(); - add_matrix("Rotation component", Transform3d(rotation), 3); - ImGui::SameLine(); - add_matrix("Scale component", Transform3d(scale), 3); - } - }; + auto add_matrix = [&imgui](const std::string& name, const Transform3d& m, unsigned int size) { + ImGui::BeginGroup(); + imgui.text(name); + if (ImGui::BeginTable(name.c_str(), size, ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersInner)) { + for (unsigned int r = 0; r < size; ++r) { + ImGui::TableNextRow(); + for (unsigned int c = 0; c < size; ++c) { + ImGui::TableSetColumnIndex(c); + imgui.text(std::to_string(m(r, c))); + } + } + ImGui::EndTable(); + } + ImGui::EndGroup(); + }; - add_matrices_set("World", v.world_matrix(), current_method_idx); - add_matrices_set("Instance", v.get_instance_transformation().get_matrix(), current_method_idx); - add_matrices_set("Volume", v.get_volume_transformation().get_matrix(), current_method_idx); + auto add_matrices_set = [add_matrix](const std::string& name, const Transform3d& m, size_t method) { + static unsigned int counter = 0; + ++counter; + if (ImGui::CollapsingHeader(name.c_str(), ImGuiTreeNodeFlags_DefaultOpen)) { + add_matrix("Full", m, 4); - imgui.end(); + Matrix3d rotation; + Matrix3d scale; + if (method == 0) + m.computeRotationScaling(&rotation, &scale); + else + m.computeScalingRotation(&scale, &rotation); + + ImGui::SameLine(); + add_matrix("Rotation component", Transform3d(rotation), 3); + ImGui::SameLine(); + add_matrix("Scale component", Transform3d(scale), 3); + } + }; + + add_matrices_set("World", v.world_matrix(), current_method_idx); + add_matrices_set("Instance", v.get_instance_transformation().get_matrix(), current_method_idx); + add_matrices_set("Volume", v.get_volume_transformation().get_matrix(), current_method_idx); + + imgui.end(); } #endif // ENABLE_WORLD_COORDINATE_DEBUG diff --git a/src/slic3r/GUI/Selection.hpp b/src/slic3r/GUI/Selection.hpp index d2c483c6e6..cb2c461ef1 100644 --- a/src/slic3r/GUI/Selection.hpp +++ b/src/slic3r/GUI/Selection.hpp @@ -242,6 +242,11 @@ private: // Bounding box of a single full instance selection, in local coordinates, with no instance scaling applied. // Modifiers are taken in account std::optional m_full_unscaled_instance_local_bounding_box; +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + // Bounding box aligned to the axis of the currently selected reference system (World/Object/Part) + // and transform to place and orient it in world coordinates + std::optional> m_bounding_box_in_current_reference_system; +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #endif // ENABLE_WORLD_COORDINATE #if ENABLE_RENDER_SELECTION_CENTER @@ -385,10 +390,14 @@ public: // Bounding box of a single full instance selection, in world coordinates. // Modifiers are taken in account const BoundingBoxf3& get_full_scaled_instance_bounding_box() const; - // Bounding box of a single full instance selection, in local coordinates, with no instance scaling applied. // Modifiers are taken in account const BoundingBoxf3& get_full_unscaled_instance_local_bounding_box() const; +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + // Returns the bounding box aligned to the axis of the currently selected reference system (World/Object/Part) + // and the transform to place and orient it in world coordinates + const std::pair& get_bounding_box_in_current_reference_system() const; +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #endif // ENABLE_WORLD_COORDINATE void setup_cache(); @@ -464,7 +473,10 @@ private: m_bounding_box.reset(); m_unscaled_instance_bounding_box.reset(); m_scaled_instance_bounding_box.reset(); m_full_unscaled_instance_bounding_box.reset(); m_full_scaled_instance_bounding_box.reset(); - m_full_unscaled_instance_local_bounding_box.reset();; + m_full_unscaled_instance_local_bounding_box.reset(); +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + m_bounding_box_in_current_reference_system.reset(); +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ } #else void set_bounding_boxes_dirty() { m_bounding_box.reset(); m_unscaled_instance_bounding_box.reset(); m_scaled_instance_bounding_box.reset(); }