mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-14 12:55:53 +08:00
Class Selection - Added method to calculate bounding box aligned to current selected reference system
This commit is contained in:
parent
221770cc94
commit
fcacc7042c
@ -801,6 +801,131 @@ const BoundingBoxf3& Selection::get_full_unscaled_instance_local_bounding_box()
|
|||||||
}
|
}
|
||||||
return *m_full_unscaled_instance_local_bounding_box;
|
return *m_full_unscaled_instance_local_bounding_box;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
||||||
|
const std::pair<BoundingBoxf3, Transform3d>& 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<std::optional<std::pair<BoundingBoxf3, Transform3d>>*>(&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<Vec4d>& original, const Transform3d& trafo, bool normalize) {
|
||||||
|
std::vector<Vec4d> 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<Vec4d> 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<Vec4d> transformed_homo_vertices = apply_transform(homo_vertices, trafo, false);
|
||||||
|
|
||||||
|
// project back to current reference system
|
||||||
|
const std::vector<Vec4d> homo_axes = { Vec4d::UnitX(), Vec4d::UnitY(), Vec4d::UnitZ() };
|
||||||
|
std::vector<Vec4d> transformed_homo_axes = apply_transform(homo_axes, Geometry::Transformation(trafo).get_matrix_no_scaling_factor(), true);
|
||||||
|
std::vector<Vec3d> 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<Vec4d> box_center = { point_to_Vec4d(original_box.center()) };
|
||||||
|
std::vector<Vec4d> 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<std::optional<std::pair<BoundingBoxf3, Transform3d>>*>(&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
|
#endif // ENABLE_WORLD_COORDINATE
|
||||||
|
|
||||||
void Selection::setup_cache()
|
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
|
#if ENABLE_WORLD_COORDINATE_DEBUG
|
||||||
void Selection::render_debug_window() const
|
void Selection::render_debug_window() const
|
||||||
{
|
{
|
||||||
if (m_list.empty())
|
if (m_list.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (get_first_volume()->is_wipe_tower)
|
if (get_first_volume()->is_wipe_tower)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ImGuiWrapper& imgui = *wxGetApp().imgui();
|
ImGuiWrapper& imgui = *wxGetApp().imgui();
|
||||||
imgui.begin(std::string("Selection matrices"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize);
|
imgui.begin(std::string("Selection matrices"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize);
|
||||||
|
|
||||||
auto volume_name = [this](size_t id) {
|
auto volume_name = [this](size_t id) {
|
||||||
const GLVolume& v = *(*m_volumes)[id];
|
const GLVolume& v = *(*m_volumes)[id];
|
||||||
return m_model->objects[v.object_idx()]->volumes[v.volume_idx()]->name;
|
return m_model->objects[v.object_idx()]->volumes[v.volume_idx()]->name;
|
||||||
};
|
};
|
||||||
|
|
||||||
static size_t current_cmb_idx = 0;
|
static size_t current_cmb_idx = 0;
|
||||||
static size_t current_vol_idx = *m_list.begin();
|
static size_t current_vol_idx = *m_list.begin();
|
||||||
|
|
||||||
if (m_list.find(current_vol_idx) == m_list.end())
|
if (m_list.find(current_vol_idx) == m_list.end())
|
||||||
current_vol_idx = *m_list.begin();
|
current_vol_idx = *m_list.begin();
|
||||||
|
|
||||||
if (ImGui::BeginCombo("Volumes", volume_name(current_vol_idx).c_str())) {
|
if (ImGui::BeginCombo("Volumes", volume_name(current_vol_idx).c_str())) {
|
||||||
size_t count = 0;
|
size_t count = 0;
|
||||||
for (unsigned int id : m_list) {
|
for (unsigned int id : m_list) {
|
||||||
const GLVolume& v = *(*m_volumes)[id];
|
const GLVolume& v = *(*m_volumes)[id];
|
||||||
const bool is_selected = (current_cmb_idx == count);
|
const bool is_selected = (current_cmb_idx == count);
|
||||||
if (ImGui::Selectable(volume_name(id).c_str(), is_selected)) {
|
if (ImGui::Selectable(volume_name(id).c_str(), is_selected)) {
|
||||||
current_cmb_idx = count;
|
current_cmb_idx = count;
|
||||||
current_vol_idx = id;
|
current_vol_idx = id;
|
||||||
}
|
}
|
||||||
if (is_selected)
|
if (is_selected)
|
||||||
ImGui::SetItemDefaultFocus();
|
ImGui::SetItemDefaultFocus();
|
||||||
++count;
|
++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)));
|
|
||||||
}
|
}
|
||||||
}
|
ImGui::EndCombo();
|
||||||
ImGui::EndTable();
|
|
||||||
}
|
}
|
||||||
ImGui::EndGroup();
|
|
||||||
};
|
|
||||||
|
|
||||||
auto add_matrices_set = [add_matrix](const std::string& name, const Transform3d& m, size_t method) {
|
static int current_method_idx = 0;
|
||||||
static unsigned int counter = 0;
|
ImGui::Combo("Decomposition method", ¤t_method_idx, "computeRotationScaling\0computeScalingRotation\0");
|
||||||
++counter;
|
|
||||||
if (ImGui::CollapsingHeader(name.c_str(), ImGuiTreeNodeFlags_DefaultOpen)) {
|
|
||||||
add_matrix("Full", m, 4);
|
|
||||||
|
|
||||||
Matrix3d rotation;
|
const GLVolume& v = *get_volume(current_vol_idx);
|
||||||
Matrix3d scale;
|
|
||||||
if (method == 0)
|
|
||||||
m.computeRotationScaling(&rotation, &scale);
|
|
||||||
else
|
|
||||||
m.computeScalingRotation(&scale, &rotation);
|
|
||||||
|
|
||||||
ImGui::SameLine();
|
auto add_matrix = [&imgui](const std::string& name, const Transform3d& m, unsigned int size) {
|
||||||
add_matrix("Rotation component", Transform3d(rotation), 3);
|
ImGui::BeginGroup();
|
||||||
ImGui::SameLine();
|
imgui.text(name);
|
||||||
add_matrix("Scale component", Transform3d(scale), 3);
|
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);
|
auto add_matrices_set = [add_matrix](const std::string& name, const Transform3d& m, size_t method) {
|
||||||
add_matrices_set("Instance", v.get_instance_transformation().get_matrix(), current_method_idx);
|
static unsigned int counter = 0;
|
||||||
add_matrices_set("Volume", v.get_volume_transformation().get_matrix(), current_method_idx);
|
++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
|
#endif // ENABLE_WORLD_COORDINATE_DEBUG
|
||||||
|
|
||||||
|
@ -242,6 +242,11 @@ private:
|
|||||||
// Bounding box of a single full instance selection, in local coordinates, with no instance scaling applied.
|
// Bounding box of a single full instance selection, in local coordinates, with no instance scaling applied.
|
||||||
// Modifiers are taken in account
|
// Modifiers are taken in account
|
||||||
std::optional<BoundingBoxf3> m_full_unscaled_instance_local_bounding_box;
|
std::optional<BoundingBoxf3> 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<std::pair<BoundingBoxf3, Transform3d>> m_bounding_box_in_current_reference_system;
|
||||||
|
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
||||||
#endif // ENABLE_WORLD_COORDINATE
|
#endif // ENABLE_WORLD_COORDINATE
|
||||||
|
|
||||||
#if ENABLE_RENDER_SELECTION_CENTER
|
#if ENABLE_RENDER_SELECTION_CENTER
|
||||||
@ -385,10 +390,14 @@ public:
|
|||||||
// Bounding box of a single full instance selection, in world coordinates.
|
// Bounding box of a single full instance selection, in world coordinates.
|
||||||
// Modifiers are taken in account
|
// Modifiers are taken in account
|
||||||
const BoundingBoxf3& get_full_scaled_instance_bounding_box() const;
|
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.
|
// Bounding box of a single full instance selection, in local coordinates, with no instance scaling applied.
|
||||||
// Modifiers are taken in account
|
// Modifiers are taken in account
|
||||||
const BoundingBoxf3& get_full_unscaled_instance_local_bounding_box() const;
|
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<BoundingBoxf3, Transform3d>& get_bounding_box_in_current_reference_system() const;
|
||||||
|
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
||||||
#endif // ENABLE_WORLD_COORDINATE
|
#endif // ENABLE_WORLD_COORDINATE
|
||||||
|
|
||||||
void setup_cache();
|
void setup_cache();
|
||||||
@ -464,7 +473,10 @@ private:
|
|||||||
m_bounding_box.reset();
|
m_bounding_box.reset();
|
||||||
m_unscaled_instance_bounding_box.reset(); m_scaled_instance_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_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
|
#else
|
||||||
void set_bounding_boxes_dirty() { m_bounding_box.reset(); m_unscaled_instance_bounding_box.reset(); m_scaled_instance_bounding_box.reset(); }
|
void set_bounding_boxes_dirty() { m_bounding_box.reset(); m_unscaled_instance_bounding_box.reset(); m_scaled_instance_bounding_box.reset(); }
|
||||||
|
Loading…
x
Reference in New Issue
Block a user