Tech ENABLE_WORLD_COORDINATE - Gizmo rotate oriented in dependence of the selected coordinate system

Fixed conflicts during rebase with master
This commit is contained in:
enricoturri1966 2021-10-12 11:07:31 +02:00
parent 61e7eb4ade
commit ca5742c401
9 changed files with 155 additions and 54 deletions

View File

@ -619,7 +619,7 @@ Eigen::Quaterniond rotation_xyz_diff(const Vec3d &rot_xyz_from, const Vec3d &rot
double rotation_diff_z(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to) double rotation_diff_z(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to)
{ {
const Eigen::AngleAxisd angle_axis(rotation_xyz_diff(rot_xyz_from, rot_xyz_to)); const Eigen::AngleAxisd angle_axis(rotation_xyz_diff(rot_xyz_from, rot_xyz_to));
const Vec3d axis = angle_axis.axis(); const Vec3d& axis = angle_axis.axis();
const double angle = angle_axis.angle(); const double angle = angle_axis.angle();
#ifndef NDEBUG #ifndef NDEBUG
if (std::abs(angle) > 1e-8) { if (std::abs(angle) > 1e-8) {

View File

@ -278,7 +278,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
return; return;
// Update mirroring at the GLVolumes. // Update mirroring at the GLVolumes.
selection.synchronize_unselected_instances(Selection::SYNC_ROTATION_GENERAL); selection.synchronize_unselected_instances(Selection::SyncRotationType::GENERAL);
selection.synchronize_unselected_volumes(); selection.synchronize_unselected_volumes();
// Copy mirroring values from GLVolumes into Model (ModelInstance / ModelVolume), trigger background processing. // Copy mirroring values from GLVolumes into Model (ModelInstance / ModelVolume), trigger background processing.
canvas->do_mirror(L("Set Mirror")); canvas->do_mirror(L("Set Mirror"));
@ -379,7 +379,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
return; return;
// Update rotation at the GLVolumes. // Update rotation at the GLVolumes.
selection.synchronize_unselected_instances(Selection::SYNC_ROTATION_GENERAL); selection.synchronize_unselected_instances(Selection::SyncRotationType::GENERAL);
selection.synchronize_unselected_volumes(); selection.synchronize_unselected_volumes();
// Copy rotation values from GLVolumes into Model (ModelInstance / ModelVolume), trigger background processing. // Copy rotation values from GLVolumes into Model (ModelInstance / ModelVolume), trigger background processing.
canvas->do_rotate(L("Reset Rotation")); canvas->do_rotate(L("Reset Rotation"));
@ -551,17 +551,23 @@ void ObjectManipulation::update_settings_value(const Selection& selection)
m_new_position = volume->get_instance_offset(); m_new_position = volume->get_instance_offset();
#endif // ENABLE_WORLD_COORDINATE #endif // ENABLE_WORLD_COORDINATE
m_new_rotate_label_string = L("Rotate"); m_new_rotate_label_string = L("Rotate");
m_new_rotation = Vec3d::Zero(); #if ENABLE_WORLD_COORDINATE
m_new_size = selection.get_scaled_instance_bounding_box().size(); m_new_rotation = volume->get_instance_rotation() * (180.0 / M_PI);
#else
m_new_rotation = Vec3d::Zero();
#endif // ENABLE_WORLD_COORDINATE
m_new_size = selection.get_scaled_instance_bounding_box().size();
m_new_scale = m_new_size.cwiseProduct(selection.get_unscaled_instance_bounding_box().size().cwiseInverse()) * 100.0; m_new_scale = m_new_size.cwiseProduct(selection.get_unscaled_instance_bounding_box().size().cwiseInverse()) * 100.0;
} }
else { else {
#if ENABLE_WORLD_COORDINATE #if ENABLE_WORLD_COORDINATE
m_new_position = Vec3d::Zero(); m_new_position = Vec3d::Zero();
#endif // ENABLE_WORLD_COORDINATE m_new_rotation = Vec3d::Zero();
#else
m_new_rotation = volume->get_instance_rotation() * (180.0 / M_PI); m_new_rotation = volume->get_instance_rotation() * (180.0 / M_PI);
#endif // ENABLE_WORLD_COORDINATE
m_new_size = volume->get_instance_scaling_factor().cwiseProduct(wxGetApp().model().objects[volume->object_idx()]->raw_mesh_bounding_box().size()); m_new_size = volume->get_instance_scaling_factor().cwiseProduct(wxGetApp().model().objects[volume->object_idx()]->raw_mesh_bounding_box().size());
m_new_scale = volume->get_instance_scaling_factor() * 100.; m_new_scale = volume->get_instance_scaling_factor() * 100.0;
} }
m_new_enabled = true; m_new_enabled = true;
@ -570,7 +576,7 @@ void ObjectManipulation::update_settings_value(const Selection& selection)
const BoundingBoxf3& box = selection.get_bounding_box(); const BoundingBoxf3& box = selection.get_bounding_box();
m_new_position = box.center(); m_new_position = box.center();
m_new_rotation = Vec3d::Zero(); m_new_rotation = Vec3d::Zero();
m_new_scale = Vec3d(100., 100., 100.); m_new_scale = Vec3d(100.0, 100.0, 100.0);
m_new_size = box.size(); m_new_size = box.size();
m_new_rotate_label_string = L("Rotate"); m_new_rotate_label_string = L("Rotate");
m_new_scale_label_string = L("Scale"); m_new_scale_label_string = L("Scale");
@ -586,7 +592,7 @@ void ObjectManipulation::update_settings_value(const Selection& selection)
const Vec3d& offset = trafo.get_offset(); const Vec3d& offset = trafo.get_offset();
const Vec3d& rotation = trafo.get_rotation(); const Vec3d& rotation = trafo.get_rotation();
const Vec3d& scaling_factor = trafo.get_scaling_factor(); const Vec3d& scaling_factor = trafo.get_scaling_factor();
const Vec3d& m = trafo.get_mirror(); // const Vec3d& mirror = trafo.get_mirror();
m_new_position = offset; m_new_position = offset;
m_new_rotation = rotation * (180.0 / M_PI); m_new_rotation = rotation * (180.0 / M_PI);
@ -596,8 +602,8 @@ void ObjectManipulation::update_settings_value(const Selection& selection)
else { else {
#endif // ENABLE_WORLD_COORDINATE #endif // ENABLE_WORLD_COORDINATE
m_new_position = volume->get_volume_offset(); m_new_position = volume->get_volume_offset();
m_new_rotation = volume->get_volume_rotation() * (180. / M_PI); m_new_rotation = volume->get_volume_rotation() * (180.0 / M_PI);
m_new_scale = volume->get_volume_scaling_factor() * 100.; m_new_scale = volume->get_volume_scaling_factor() * 100.0;
m_new_size = volume->get_instance_scaling_factor().cwiseProduct(volume->get_volume_scaling_factor().cwiseProduct(volume->bounding_box().size())); m_new_size = volume->get_instance_scaling_factor().cwiseProduct(volume->get_volume_scaling_factor().cwiseProduct(volume->bounding_box().size()));
#if ENABLE_WORLD_COORDINATE #if ENABLE_WORLD_COORDINATE
} }
@ -712,11 +718,20 @@ void ObjectManipulation::update_reset_buttons_visibility()
if (selection.is_single_full_instance() || selection.is_single_modifier() || selection.is_single_volume()) { if (selection.is_single_full_instance() || selection.is_single_modifier() || selection.is_single_volume()) {
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
#if ENABLE_WORLD_COORDINATE
Vec3d rotation = Vec3d::Zero();
Vec3d scale = Vec3d::Ones();
#else
Vec3d rotation; Vec3d rotation;
Vec3d scale; Vec3d scale;
double min_z = 0.; #endif // ENABLE_WORLD_COORDINATE
double min_z = 0.0;
#if ENABLE_WORLD_COORDINATE
if (selection.is_single_full_instance() && m_world_coordinates) {
#else
if (selection.is_single_full_instance()) { if (selection.is_single_full_instance()) {
#endif // ENABLE_WORLD_COORDINATE
rotation = volume->get_instance_rotation(); rotation = volume->get_instance_rotation();
scale = volume->get_instance_scaling_factor(); scale = volume->get_instance_scaling_factor();
min_z = wxGetApp().model().objects[volume->composite_id.object_id]->bounding_box().min.z(); min_z = wxGetApp().model().objects[volume->composite_id.object_id]->bounding_box().min.z();
@ -728,7 +743,11 @@ void ObjectManipulation::update_reset_buttons_visibility()
} }
show_rotation = !rotation.isApprox(Vec3d::Zero()); show_rotation = !rotation.isApprox(Vec3d::Zero());
show_scale = !scale.isApprox(Vec3d::Ones()); show_scale = !scale.isApprox(Vec3d::Ones());
#if ENABLE_WORLD_COORDINATE
show_drop_to_bed = min_z > EPSILON;
#else
show_drop_to_bed = std::abs(min_z) > SINKING_Z_THRESHOLD; show_drop_to_bed = std::abs(min_z) > SINKING_Z_THRESHOLD;
#endif // ENABLE_WORLD_COORDINATE
} }
wxGetApp().CallAfter([this, show_rotation, show_scale, show_drop_to_bed] { wxGetApp().CallAfter([this, show_rotation, show_scale, show_drop_to_bed] {
@ -1042,6 +1061,13 @@ void ObjectManipulation::set_world_coordinates(const bool world_coordinates)
canvas->set_as_dirty(); canvas->set_as_dirty();
canvas->request_extra_frame(); canvas->request_extra_frame();
} }
bool ObjectManipulation::get_world_coordinates() const
{
const Selection& selection = wxGetApp().plater()->canvas3D()->get_selection();
return wxGetApp().get_mode() != comSimple && (selection.is_single_full_instance() || selection.is_single_volume() || selection.is_single_modifier()) ?
m_world_coordinates : true;
}
#endif // ENABLE_WORLD_COORDINATE #endif // ENABLE_WORLD_COORDINATE
void ObjectManipulation::msw_rescale() void ObjectManipulation::msw_rescale()

View File

@ -185,10 +185,11 @@ public:
// Does the object manipulation panel work in World or Local coordinates? // Does the object manipulation panel work in World or Local coordinates?
#if ENABLE_WORLD_COORDINATE #if ENABLE_WORLD_COORDINATE
void set_world_coordinates(const bool world_coordinates); void set_world_coordinates(const bool world_coordinates);
bool get_world_coordinates() const;
#else #else
void set_world_coordinates(const bool world_coordinates) { m_world_coordinates = world_coordinates; this->UpdateAndShow(true); } void set_world_coordinates(const bool world_coordinates) { m_world_coordinates = world_coordinates; this->UpdateAndShow(true); }
#endif // ENABLE_WORLD_COORDINATE
bool get_world_coordinates() const { return m_world_coordinates; } bool get_world_coordinates() const { return m_world_coordinates; }
#endif // ENABLE_WORLD_COORDINATE
void reset_cache() { m_cache.reset(); } void reset_cache() { m_cache.reset(); }
#ifndef __APPLE__ #ifndef __APPLE__

View File

@ -24,27 +24,18 @@ GLGizmoMove3D::GLGizmoMove3D(GLCanvas3D& parent, const std::string& icon_filenam
std::string GLGizmoMove3D::get_tooltip() const std::string GLGizmoMove3D::get_tooltip() const
{ {
const Selection& selection = m_parent.get_selection();
const bool show_position = selection.is_single_full_instance();
#if ENABLE_WORLD_COORDINATE #if ENABLE_WORLD_COORDINATE
const bool world_coordinates = wxGetApp().obj_manipul()->get_world_coordinates();
Vec3d position = Vec3d::Zero();
if (!world_coordinates) {
if (selection.is_single_modifier() || selection.is_single_volume() || selection.is_wipe_tower())
position = selection.get_volume(*selection.get_volume_idxs().begin())->get_volume_offset();
}
else
position = selection.get_bounding_box().center();
if (m_hover_id == 0) if (m_hover_id == 0)
return m_grabbers[0].dragging ? "DX: " + format(m_displacement.x(), 2) : "X: " + format(position.x(), 2); return "X: " + format(m_displacement.x(), 2);
else if (m_hover_id == 1) else if (m_hover_id == 1)
return m_grabbers[1].dragging ? "DY: " + format(m_displacement.y(), 2) : "Y: " + format(position.y(), 2); return "Y: " + format(m_displacement.y(), 2);
else if (m_hover_id == 2) else if (m_hover_id == 2)
return m_grabbers[2].dragging ? "DZ: " + format(m_displacement.z(), 2) : "Z: " + format(position.z(), 2); return "Z: " + format(m_displacement.z(), 2);
else else
return ""; return "";
#else #else
const Selection& selection = m_parent.get_selection();
const bool show_position = selection.is_single_full_instance();
const Vec3d& position = selection.get_bounding_box().center(); const Vec3d& position = selection.get_bounding_box().center();
if (m_hover_id == 0 || m_grabbers[0].dragging) if (m_hover_id == 0 || m_grabbers[0].dragging)

View File

@ -60,9 +60,6 @@ protected:
virtual bool on_is_activable() const override; virtual bool on_is_activable() const override;
virtual void on_start_dragging() override; virtual void on_start_dragging() override;
virtual void on_stop_dragging() override; virtual void on_stop_dragging() override;
#if !ENABLE_WORLD_COORDINATE
virtual void on_start_dragging() override;
#endif // !ENABLE_WORLD_COORDINATE
virtual void on_dragging(const UpdateData& data) override; virtual void on_dragging(const UpdateData& data) override;
virtual void on_render() override; virtual void on_render() override;
virtual void on_render_for_picking() override; virtual void on_render_for_picking() override;

View File

@ -2,15 +2,18 @@
#include "GLGizmoRotate.hpp" #include "GLGizmoRotate.hpp"
#include "slic3r/GUI/GLCanvas3D.hpp" #include "slic3r/GUI/GLCanvas3D.hpp"
#include "slic3r/GUI/ImGuiWrapper.hpp" #include "slic3r/GUI/ImGuiWrapper.hpp"
#if ENABLE_WORLD_COORDINATE
#include <GL/glew.h> #include "slic3r/GUI/GUI_ObjectManipulation.hpp"
#endif // ENABLE_WORLD_COORDINATE
#include "slic3r/GUI/GUI_App.hpp" #include "slic3r/GUI/GUI_App.hpp"
#include "slic3r/GUI/GUI.hpp" #include "slic3r/GUI/GUI.hpp"
#include "slic3r/GUI/Plater.hpp" #include "slic3r/GUI/Plater.hpp"
#include "slic3r/GUI/Jobs/RotoptimizeJob.hpp"
#include "libslic3r/PresetBundle.hpp" #include "libslic3r/PresetBundle.hpp"
#include "slic3r/GUI/Jobs/RotoptimizeJob.hpp" #include <GL/glew.h>
namespace Slic3r { namespace Slic3r {
namespace GUI { namespace GUI {
@ -99,6 +102,9 @@ bool GLGizmoRotate::on_init()
void GLGizmoRotate::on_start_dragging() void GLGizmoRotate::on_start_dragging()
{ {
#if ENABLE_WORLD_COORDINATE
init_data_from_selection(m_parent.get_selection());
#else
const BoundingBoxf3& box = m_parent.get_selection().get_bounding_box(); const BoundingBoxf3& box = m_parent.get_selection().get_bounding_box();
m_center = box.center(); m_center = box.center();
m_radius = Offset + box.radius(); m_radius = Offset + box.radius();
@ -106,6 +112,7 @@ void GLGizmoRotate::on_start_dragging()
m_snap_coarse_out_radius = 2.0f * m_snap_coarse_in_radius; m_snap_coarse_out_radius = 2.0f * m_snap_coarse_in_radius;
m_snap_fine_in_radius = m_radius; m_snap_fine_in_radius = m_radius;
m_snap_fine_out_radius = m_snap_fine_in_radius + m_radius * ScaleLongTooth; m_snap_fine_out_radius = m_snap_fine_in_radius + m_radius * ScaleLongTooth;
#endif // ENABLE_WORLD_COORDINATE
} }
void GLGizmoRotate::on_dragging(const UpdateData &data) void GLGizmoRotate::on_dragging(const UpdateData &data)
@ -154,12 +161,16 @@ void GLGizmoRotate::on_render()
const BoundingBoxf3& box = selection.get_bounding_box(); const BoundingBoxf3& box = selection.get_bounding_box();
if (m_hover_id != 0 && !m_grabbers.front().dragging) { if (m_hover_id != 0 && !m_grabbers.front().dragging) {
#if ENABLE_WORLD_COORDINATE
init_data_from_selection(selection);
#else
m_center = box.center(); m_center = box.center();
m_radius = Offset + box.radius(); m_radius = Offset + box.radius();
m_snap_coarse_in_radius = m_radius / 3.0f; m_snap_coarse_in_radius = m_radius / 3.0f;
m_snap_coarse_out_radius = 2.0f * m_snap_coarse_in_radius; m_snap_coarse_out_radius = 2.0f * m_snap_coarse_in_radius;
m_snap_fine_in_radius = m_radius; m_snap_fine_in_radius = m_radius;
m_snap_fine_out_radius = m_radius * (1.0f + ScaleLongTooth); m_snap_fine_out_radius = m_radius * (1.0f + ScaleLongTooth);
#endif // ENABLE_WORLD_COORDINATE
} }
const double grabber_radius = (double)m_radius * (1.0 + (double)GrabberOffset); const double grabber_radius = (double)m_radius * (1.0 + (double)GrabberOffset);
@ -257,6 +268,24 @@ void GLGizmoRotate::on_render_for_picking()
#endif // !ENABLE_GL_SHADERS_ATTRIBUTES #endif // !ENABLE_GL_SHADERS_ATTRIBUTES
} }
#if ENABLE_WORLD_COORDINATE
void GLGizmoRotate::init_data_from_selection(const Selection& selection)
{
const BoundingBoxf3& box = selection.get_bounding_box();
m_center = box.center();
m_radius = Offset + box.radius();
m_snap_coarse_in_radius = m_radius / 3.0f;
m_snap_coarse_out_radius = 2.0f * m_snap_coarse_in_radius;
m_snap_fine_in_radius = m_radius;
m_snap_fine_out_radius = m_snap_fine_in_radius + m_radius * ScaleLongTooth;
if (wxGetApp().obj_manipul()->get_world_coordinates())
m_orient_matrix = Transform3d::Identity();
else
m_orient_matrix = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(true, false, true, true);
}
#endif // ENABLE_WORLD_COORDINATE
void GLGizmoRotate3D::on_render_input_window(float x, float y, float bottom_limit) void GLGizmoRotate3D::on_render_input_window(float x, float y, float bottom_limit)
{ {
if (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA) if (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA)
@ -317,10 +346,10 @@ void GLGizmoRotate::render_circle() const
#else #else
::glBegin(GL_LINE_LOOP); ::glBegin(GL_LINE_LOOP);
for (unsigned int i = 0; i < ScaleStepsCount; ++i) { for (unsigned int i = 0; i < ScaleStepsCount; ++i) {
float angle = (float)i * ScaleStepRad; const float angle = (float)i * ScaleStepRad;
float x = ::cos(angle) * m_radius; const float x = ::cos(angle) * m_radius;
float y = ::sin(angle) * m_radius; const float y = ::sin(angle) * m_radius;
float z = 0.0f; const float z = 0.0f;
::glVertex3f((GLfloat)x, (GLfloat)y, (GLfloat)z); ::glVertex3f((GLfloat)x, (GLfloat)y, (GLfloat)z);
} }
glsafe(::glEnd()); glsafe(::glEnd());
@ -519,10 +548,10 @@ void GLGizmoRotate::render_angle() const
#else #else
::glBegin(GL_LINE_STRIP); ::glBegin(GL_LINE_STRIP);
for (unsigned int i = 0; i <= AngleResolution; ++i) { for (unsigned int i = 0; i <= AngleResolution; ++i) {
float angle = (float)i * step_angle; const float angle = (float)i * step_angle;
float x = ::cos(angle) * ex_radius; const float x = ::cos(angle) * ex_radius;
float y = ::sin(angle) * ex_radius; const float y = ::sin(angle) * ex_radius;
float z = 0.0f; const float z = 0.0f;
::glVertex3f((GLfloat)x, (GLfloat)y, (GLfloat)z); ::glVertex3f((GLfloat)x, (GLfloat)y, (GLfloat)z);
} }
glsafe(::glEnd()); glsafe(::glEnd());
@ -687,10 +716,14 @@ void GLGizmoRotate::transform_to_local(const Selection& selection) const
{ {
glsafe(::glTranslated(m_center.x(), m_center.y(), m_center.z())); glsafe(::glTranslated(m_center.x(), m_center.y(), m_center.z()));
#if ENABLE_WORLD_COORDINATE
glsafe(::glMultMatrixd(m_orient_matrix.data()));
#else
if (selection.is_single_volume() || selection.is_single_modifier() || selection.requires_local_axes()) { if (selection.is_single_volume() || selection.is_single_modifier() || selection.requires_local_axes()) {
const Transform3d orient_matrix = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(true, false, true, true); const Transform3d orient_matrix = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(true, false, true, true);
glsafe(::glMultMatrixd(orient_matrix.data())); glsafe(::glMultMatrixd(orient_matrix.data()));
} }
#endif // ENABLE_WORLD_COORDINATE
switch (m_axis) switch (m_axis)
{ {
@ -744,8 +777,12 @@ Vec3d GLGizmoRotate::mouse_position_in_local_plane(const Linef3& mouse_ray, cons
} }
} }
#if ENABLE_WORLD_COORDINATE
m = m * m_orient_matrix.inverse();
#else
if (selection.is_single_volume() || selection.is_single_modifier() || selection.requires_local_axes()) if (selection.is_single_volume() || selection.is_single_modifier() || selection.requires_local_axes())
m = m * selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(true, false, true, true).inverse(); m = m * selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(true, false, true, true).inverse();
#endif // ENABLE_WORLD_COORDINATE
m.translate(-m_center); m.translate(-m_center);

View File

@ -34,6 +34,9 @@ private:
float m_snap_coarse_out_radius{ 0.0f }; float m_snap_coarse_out_radius{ 0.0f };
float m_snap_fine_in_radius{ 0.0f }; float m_snap_fine_in_radius{ 0.0f };
float m_snap_fine_out_radius{ 0.0f }; float m_snap_fine_out_radius{ 0.0f };
#if ENABLE_WORLD_COORDINATE
Transform3d m_orient_matrix{ Transform3d::Identity() };
#endif // ENABLE_WORLD_COORDINATE
#if !ENABLE_GIZMO_GRABBER_REFACTOR #if !ENABLE_GIZMO_GRABBER_REFACTOR
GLModel m_cone; GLModel m_cone;
@ -119,6 +122,10 @@ private:
// returns the intersection of the mouse ray with the plane perpendicular to the gizmo axis, in local coordinate // returns the intersection of the mouse ray with the plane perpendicular to the gizmo axis, in local coordinate
Vec3d mouse_position_in_local_plane(const Linef3& mouse_ray, const Selection& selection) const; Vec3d mouse_position_in_local_plane(const Linef3& mouse_ray, const Selection& selection) const;
#if ENABLE_WORLD_COORDINATE
void init_data_from_selection(const Selection& selection);
#endif // ENABLE_WORLD_COORDINATE
}; };
class GLGizmoRotate3D : public GLGizmoBase class GLGizmoRotate3D : public GLGizmoBase

View File

@ -734,7 +734,7 @@ void Selection::translate(const Vec3d& displacement, bool local)
#if !DISABLE_INSTANCES_SYNCH #if !DISABLE_INSTANCES_SYNCH
if (translation_type == Instance) if (translation_type == Instance)
synchronize_unselected_instances(SYNC_ROTATION_NONE); synchronize_unselected_instances(SyncRotationType::NONE);
else if (translation_type == Volume) else if (translation_type == Volume)
synchronize_unselected_volumes(); synchronize_unselected_volumes();
#endif // !DISABLE_INSTANCES_SYNCH #endif // !DISABLE_INSTANCES_SYNCH
@ -791,7 +791,18 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_
} }
else { else {
// extracts rotations from the composed transformation // extracts rotations from the composed transformation
Vec3d new_rotation = transformation_type.world() ? #if ENABLE_WORLD_COORDINATE
const Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), rotation);
const Vec3d new_rotation = transformation_type.world() ?
Geometry::extract_euler_angles(m * m_cache.volumes_data[i].get_instance_rotation_matrix()) :
transformation_type.absolute() ? rotation : Geometry::extract_euler_angles(m_cache.volumes_data[i].get_instance_rotation_matrix() * m);
if (rot_axis_max == 2 && transformation_type.world() && transformation_type.joint()) {
// Only allow rotation of multiple instances as a single rigid body when rotating around the Z axis.
const double z_diff = Geometry::rotation_diff_z(m_cache.volumes_data[i].get_instance_rotation(), new_rotation);
volume.set_instance_offset(m_cache.dragging_center + Eigen::AngleAxisd(z_diff, Vec3d::UnitZ()) * (m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center));
}
#else
const Vec3d new_rotation = transformation_type.world() ?
Geometry::extract_euler_angles(Geometry::assemble_transform(Vec3d::Zero(), rotation) * m_cache.volumes_data[i].get_instance_rotation_matrix()) : Geometry::extract_euler_angles(Geometry::assemble_transform(Vec3d::Zero(), rotation) * m_cache.volumes_data[i].get_instance_rotation_matrix()) :
transformation_type.absolute() ? rotation : rotation + m_cache.volumes_data[i].get_instance_rotation(); transformation_type.absolute() ? rotation : rotation + m_cache.volumes_data[i].get_instance_rotation();
if (rot_axis_max == 2 && transformation_type.joint()) { if (rot_axis_max == 2 && transformation_type.joint()) {
@ -799,6 +810,7 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_
const double z_diff = Geometry::rotation_diff_z(m_cache.volumes_data[i].get_instance_rotation(), new_rotation); const double z_diff = Geometry::rotation_diff_z(m_cache.volumes_data[i].get_instance_rotation(), new_rotation);
volume.set_instance_offset(m_cache.dragging_center + Eigen::AngleAxisd(z_diff, Vec3d::UnitZ()) * (m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center)); volume.set_instance_offset(m_cache.dragging_center + Eigen::AngleAxisd(z_diff, Vec3d::UnitZ()) * (m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center));
} }
#endif // ENABLE_WORLD_COORDINATE
else if (!(m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center).isApprox(Vec3d::Zero())) else if (!(m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center).isApprox(Vec3d::Zero()))
volume.set_instance_offset(m_cache.dragging_center + Geometry::assemble_transform(Vec3d::Zero(), new_rotation) * m_cache.volumes_data[i].get_instance_rotation_matrix().inverse() * (m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center)); volume.set_instance_offset(m_cache.dragging_center + Geometry::assemble_transform(Vec3d::Zero(), new_rotation) * m_cache.volumes_data[i].get_instance_rotation_matrix().inverse() * (m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center));
@ -826,8 +838,8 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_
rotate_instance(v, i); rotate_instance(v, i);
else if (m_mode == Volume) { else if (m_mode == Volume) {
// extracts rotations from the composed transformation // extracts rotations from the composed transformation
Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), rotation); const Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), rotation);
Vec3d new_rotation = Geometry::extract_euler_angles(m * m_cache.volumes_data[i].get_volume_rotation_matrix()); const Vec3d new_rotation = Geometry::extract_euler_angles(m * m_cache.volumes_data[i].get_volume_rotation_matrix());
if (transformation_type.joint()) { if (transformation_type.joint()) {
const Vec3d local_pivot = m_cache.volumes_data[i].get_instance_full_matrix().inverse() * m_cache.dragging_center; const Vec3d local_pivot = m_cache.volumes_data[i].get_instance_full_matrix().inverse() * m_cache.dragging_center;
const Vec3d offset = m * (m_cache.volumes_data[i].get_volume_position() - local_pivot); const Vec3d offset = m * (m_cache.volumes_data[i].get_volume_position() - local_pivot);
@ -840,11 +852,24 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_
} }
#if !DISABLE_INSTANCES_SYNCH #if !DISABLE_INSTANCES_SYNCH
#if ENABLE_WORLD_COORDINATE
if (m_mode == Instance) {
SyncRotationType synch;
if (transformation_type.world() && rot_axis_max == 2)
synch = SyncRotationType::NONE;
else if (transformation_type.local())
synch = SyncRotationType::FULL;
else
synch = SyncRotationType::GENERAL;
synchronize_unselected_instances(synch);
}
#else
if (m_mode == Instance) if (m_mode == Instance)
synchronize_unselected_instances((rot_axis_max == 2) ? SYNC_ROTATION_NONE : SYNC_ROTATION_GENERAL); synchronize_unselected_instances((rot_axis_max == 2) ? SYNC_ROTATION_NONE : SYNC_ROTATION_GENERAL);
#endif // ENABLE_WORLD_COORDINATE
else if (m_mode == Volume) else if (m_mode == Volume)
synchronize_unselected_volumes(); synchronize_unselected_volumes();
#endif // !DISABLE_INSTANCES_SYNCH #endif // !DISABLE_INSTANCES_SYNCH
} }
else { // it's the wipe tower that's selected and being rotated else { // it's the wipe tower that's selected and being rotated
GLVolume& volume = *((*m_volumes)[*m_list.begin()]); // the wipe tower is always alone in the selection GLVolume& volume = *((*m_volumes)[*m_list.begin()]); // the wipe tower is always alone in the selection
@ -887,7 +912,7 @@ void Selection::flattening_rotate(const Vec3d& normal)
// Apply the same transformation also to other instances, // Apply the same transformation also to other instances,
// but respect their possibly diffrent z-rotation. // but respect their possibly diffrent z-rotation.
if (m_mode == Instance) if (m_mode == Instance)
synchronize_unselected_instances(SYNC_ROTATION_GENERAL); synchronize_unselected_instances(SyncRotationType::GENERAL);
#endif // !DISABLE_INSTANCES_SYNCH #endif // !DISABLE_INSTANCES_SYNCH
this->set_bounding_boxes_dirty(); this->set_bounding_boxes_dirty();
@ -950,7 +975,7 @@ void Selection::scale(const Vec3d& scale, TransformationType transformation_type
#if !DISABLE_INSTANCES_SYNCH #if !DISABLE_INSTANCES_SYNCH
if (m_mode == Instance) if (m_mode == Instance)
synchronize_unselected_instances(SYNC_ROTATION_NONE); synchronize_unselected_instances(SyncRotationType::NONE);
else if (m_mode == Volume) else if (m_mode == Volume)
synchronize_unselected_volumes(); synchronize_unselected_volumes();
#endif // !DISABLE_INSTANCES_SYNCH #endif // !DISABLE_INSTANCES_SYNCH
@ -1063,7 +1088,7 @@ void Selection::mirror(Axis axis)
#if !DISABLE_INSTANCES_SYNCH #if !DISABLE_INSTANCES_SYNCH
if (m_mode == Instance) if (m_mode == Instance)
synchronize_unselected_instances(SYNC_ROTATION_NONE); synchronize_unselected_instances(SyncRotationType::NONE);
else if (m_mode == Volume) else if (m_mode == Volume)
synchronize_unselected_volumes(); synchronize_unselected_volumes();
#endif // !DISABLE_INSTANCES_SYNCH #endif // !DISABLE_INSTANCES_SYNCH
@ -2528,7 +2553,7 @@ void Selection::synchronize_unselected_instances(SyncRotationType sync_rotation_
assert(is_rotation_xy_synchronized(m_cache.volumes_data[i].get_instance_rotation(), m_cache.volumes_data[j].get_instance_rotation())); assert(is_rotation_xy_synchronized(m_cache.volumes_data[i].get_instance_rotation(), m_cache.volumes_data[j].get_instance_rotation()));
switch (sync_rotation_type) { switch (sync_rotation_type) {
case SYNC_ROTATION_NONE: { case SyncRotationType::NONE: {
// z only rotation -> synch instance z // z only rotation -> synch instance z
// The X,Y rotations should be synchronized from start to end of the rotation. // The X,Y rotations should be synchronized from start to end of the rotation.
assert(is_rotation_xy_synchronized(rotation, v->get_instance_rotation())); assert(is_rotation_xy_synchronized(rotation, v->get_instance_rotation()));
@ -2536,12 +2561,25 @@ void Selection::synchronize_unselected_instances(SyncRotationType sync_rotation_
v->set_instance_offset(Z, volume->get_instance_offset().z()); v->set_instance_offset(Z, volume->get_instance_offset().z());
break; break;
} }
case SYNC_ROTATION_GENERAL: case SyncRotationType::GENERAL: {
// generic rotation -> update instance z with the delta of the rotation. // generic rotation -> update instance z with the delta of the rotation.
const double z_diff = Geometry::rotation_diff_z(m_cache.volumes_data[i].get_instance_rotation(), m_cache.volumes_data[j].get_instance_rotation()); const double z_diff = Geometry::rotation_diff_z(m_cache.volumes_data[i].get_instance_rotation(), m_cache.volumes_data[j].get_instance_rotation());
v->set_instance_rotation({ rotation.x(), rotation.y(), rotation.z() + z_diff }); v->set_instance_rotation({ rotation.x(), rotation.y(), rotation.z() + z_diff });
break; break;
} }
#if ENABLE_WORLD_COORDINATE
case SyncRotationType::FULL: {
// generic rotation -> update instance z with the delta of the rotation.
const Eigen::AngleAxisd angle_axis(Geometry::rotation_xyz_diff(rotation, m_cache.volumes_data[j].get_instance_rotation()));
const Vec3d& axis = angle_axis.axis();
const double z_diff = (std::abs(axis.x()) > EPSILON || std::abs(axis.y()) > EPSILON) ?
angle_axis.angle() * axis.z() : Geometry::rotation_diff_z(rotation, m_cache.volumes_data[j].get_instance_rotation());
v->set_instance_rotation({ rotation.x(), rotation.y(), rotation.z() + z_diff });
break;
}
#endif // ENABLE_WORLD_COORDINATE
}
v->set_instance_scaling_factor(scaling_factor); v->set_instance_scaling_factor(scaling_factor);
v->set_instance_mirror(mirror); v->set_instance_mirror(mirror);

View File

@ -389,11 +389,15 @@ private:
#endif // ENABLE_GL_SHADERS_ATTRIBUTES #endif // ENABLE_GL_SHADERS_ATTRIBUTES
public: public:
enum SyncRotationType { enum class SyncRotationType {
// Do not synchronize rotation. Either not rotating at all, or rotating by world Z axis. // Do not synchronize rotation. Either not rotating at all, or rotating by world Z axis.
SYNC_ROTATION_NONE = 0, NONE = 0,
// Synchronize after rotation by an axis not parallel with Z. // Synchronize after rotation by an axis not parallel with Z.
SYNC_ROTATION_GENERAL = 1, GENERAL = 1,
#if ENABLE_WORLD_COORDINATE
// Fully synchronize rotation.
FULL = 2,
#endif // ENABLE_WORLD_COORDINATE
}; };
void synchronize_unselected_instances(SyncRotationType sync_rotation_type); void synchronize_unselected_instances(SyncRotationType sync_rotation_type);
void synchronize_unselected_volumes(); void synchronize_unselected_volumes();