Fixed rotation of single instance -> it works now with absolute values.

Added Absolute / relative, World / Local, Rigid body / independent
modifier parameter to the object / group rotation.
This commit is contained in:
bubnikv 2019-03-01 10:20:12 +01:00
parent f4b2d51f47
commit d009be7609
3 changed files with 82 additions and 15 deletions

View file

@ -1261,17 +1261,21 @@ static double rotation_diff_z(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to
return (axis.z() < 0) ? -angle : angle;
}
void GLCanvas3D::Selection::rotate(const Vec3d& rotation, bool local)
// Rotate an object around one of the axes. Only one rotation component is expected to be changing.
void GLCanvas3D::Selection::rotate(const Vec3d& rotation, GLCanvas3D::TransformationType transformation_type)
{
if (!m_valid)
return;
// Only relative rotation values are allowed in the world coordinate system.
assert(! transformation_type.world() || transformation_type.relative());
int rot_axis_max;
rotation.cwiseAbs().maxCoeff(&rot_axis_max);
// For generic rotation, we want to rotate the first volume in selection, and then to synchronize the other volumes with it.
std::vector<int> object_instance_first(m_model->objects.size(), -1);
auto rotate_instance = [this, &rotation, &object_instance_first, rot_axis_max, local](GLVolume &volume, int i) {
auto rotate_instance = [this, &rotation, &object_instance_first, rot_axis_max, transformation_type](GLVolume &volume, int i) {
int first_volume_idx = object_instance_first[volume.object_idx()];
if (rot_axis_max != 2 && first_volume_idx != -1) {
// Generic rotation, but no rotation around the Z axis.
@ -1283,11 +1287,14 @@ void GLCanvas3D::Selection::rotate(const Vec3d& rotation, bool local)
volume.set_instance_rotation(Vec3d(rotation(0), rotation(1), rotation(2) + z_diff));
} else {
// extracts rotations from the composed transformation
Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), rotation);
Vec3d new_rotation = Geometry::extract_euler_angles(m * m_cache.volumes_data[i].get_instance_rotation_matrix());
if (rot_axis_max == 2 && !local)
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()) :
transformation_type.absolute() ? rotation : rotation + m_cache.volumes_data[i].get_instance_rotation();
if (rot_axis_max == 2 && transformation_type.joint()) {
// Only allow rotation of multiple instances as a single rigid body when rotating around the Z axis.
volume.set_instance_offset(m_cache.dragging_center + m * (m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center));
double z_diff = rotation_diff_z(new_rotation, m_cache.volumes_data[i].get_instance_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_rotation(new_rotation);
object_instance_first[volume.object_idx()] = i;
}
@ -1300,7 +1307,7 @@ void GLCanvas3D::Selection::rotate(const Vec3d& rotation, bool local)
rotate_instance(volume, i);
else if (is_single_volume() || is_single_modifier())
{
if (local)
if (transformation_type.independent())
volume.set_volume_rotation(volume.get_volume_rotation() + rotation);
else
{
@ -1318,7 +1325,7 @@ void GLCanvas3D::Selection::rotate(const Vec3d& rotation, bool local)
// extracts rotations from the composed transformation
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());
if (!local)
if (transformation_type.joint())
{
Vec3d offset = m * (m_cache.volumes_data[i].get_volume_position() + m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center);
volume.set_volume_offset(m_cache.dragging_center - m_cache.volumes_data[i].get_instance_position() + offset);
@ -5162,7 +5169,10 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
case Gizmos::Rotate:
{
// Apply new temporary rotations
m_selection.rotate(m_gizmos.get_rotation(), evt.AltDown());
TransformationType transformation_type(TransformationType::World_Relative_Joint);
if (evt.AltDown())
transformation_type.set_independent();
m_selection.rotate(m_gizmos.get_rotation(), transformation_type);
wxGetApp().obj_manipul()->update_settings_value(m_selection);
break;
}

View file

@ -375,6 +375,59 @@ class GLCanvas3D
};
public:
class TransformationType
{
public:
enum Enum {
// Transforming in a world coordinate system
World = 0,
// Transforming in a local coordinate system
Local = 1,
// Absolute transformations, allowed in local coordinate system only.
Absolute = 0,
// Relative transformations, allowed in both local and world coordinate system.
Relative = 2,
// For group selection, the transformation is performed as if the group made a single solid body.
Joint = 0,
// For group selection, the transformation is performed on each object independently.
Independent = 4,
World_Relative_Joint = World | Relative | Joint,
World_Relative_Independent = World | Relative | Independent,
Local_Absolute_Joint = Local | Absolute | Joint,
Local_Absolute_Independent = Local | Absolute | Independent,
Local_Relative_Joint = Local | Relative | Joint,
Local_Relative_Independent = Local | Relative | Independent,
};
TransformationType() : m_value(World) {}
TransformationType(Enum value) : m_value(value) {}
TransformationType& operator=(Enum value) { m_value = value; return *this; }
Enum operator()() const { return m_value; }
bool has(Enum v) const { return ((unsigned int)m_value & (unsigned int)v) != 0; }
void set_world() { this->remove(Local); }
void set_local() { this->add(Local); }
void set_absolute() { this->remove(Relative); }
void set_relative() { this->add(Relative); }
void set_joint() { this->remove(Independent); }
void set_independent() { this->add(Independent); }
bool world() const { return ! this->has(Local); }
bool local() const { return this->has(Local); }
bool absolute() const { return ! this->has(Relative); }
bool relative() const { return this->has(Relative); }
bool joint() const { return ! this->has(Independent); }
bool independent() const { return this->has(Independent); }
private:
void add(Enum v) { m_value = Enum((unsigned int)m_value | (unsigned int)v); }
void remove(Enum v) { m_value = Enum((unsigned int)m_value & (~(unsigned int)v)); }
Enum m_value;
};
class Selection
{
public:
@ -553,7 +606,7 @@ public:
void start_dragging();
void translate(const Vec3d& displacement, bool local = false);
void rotate(const Vec3d& rotation, bool local);
void rotate(const Vec3d& rotation, TransformationType transformation_type);
void flattening_rotate(const Vec3d& normal);
void scale(const Vec3d& scale, bool local);
void mirror(Axis axis);

View file

@ -361,16 +361,20 @@ void ObjectManipulation::change_rotation_value(const Vec3d& rotation)
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
const GLCanvas3D::Selection& selection = canvas->get_selection();
Vec3d delta_rotation = rotation - m_cache.rotation;
GLCanvas3D::TransformationType transformation_type(GLCanvas3D::TransformationType::World_Relative_Joint);
if (selection.is_single_full_instance() || selection.requires_local_axes())
transformation_type.set_independent();
if (selection.is_single_full_instance()) {
transformation_type.set_absolute();
transformation_type.set_local();
}
Vec3d rad_rotation;
for (size_t i = 0; i < 3; ++i)
{
rad_rotation(i) = Geometry::deg2rad(delta_rotation(i));
}
rad_rotation(i) = Geometry::deg2rad((transformation_type.absolute()) ? rotation(i) : rotation(i) - m_cache.rotation(i));
canvas->get_selection().start_dragging();
canvas->get_selection().rotate(rad_rotation, selection.is_single_full_instance() || selection.requires_local_axes());
canvas->get_selection().rotate(rad_rotation, transformation_type);
canvas->do_rotate();
m_cache.rotation = rotation;