Merge remote-tracking branch 'origin/et_transformations'
This commit is contained in:
commit
d9a8208e16
6 changed files with 125 additions and 65 deletions
|
@ -860,14 +860,26 @@ TransformationSVD::TransformationSVD(const Transform3d& trafo)
|
||||||
rotation_90_degrees = true;
|
rotation_90_degrees = true;
|
||||||
for (int i = 0; i < 3; ++i) {
|
for (int i = 0; i < 3; ++i) {
|
||||||
const Vec3d row = v.row(i).cwiseAbs();
|
const Vec3d row = v.row(i).cwiseAbs();
|
||||||
size_t num_zeros = is_approx(row[0], 0.) + is_approx(row[1], 0.) + is_approx(row[2], 0.);
|
const size_t num_zeros = is_approx(row[0], 0.) + is_approx(row[1], 0.) + is_approx(row[2], 0.);
|
||||||
size_t num_ones = is_approx(row[0], 1.) + is_approx(row[1], 1.) + is_approx(row[2], 1.);
|
const size_t num_ones = is_approx(row[0], 1.) + is_approx(row[1], 1.) + is_approx(row[2], 1.);
|
||||||
if (num_zeros != 2 || num_ones != 1) {
|
if (num_zeros != 2 || num_ones != 1) {
|
||||||
rotation_90_degrees = false;
|
rotation_90_degrees = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
skew = ! rotation_90_degrees;
|
// Detect skew by brute force: check if the axes are still orthogonal after transformation
|
||||||
|
const Matrix3d trafo_linear = trafo.linear();
|
||||||
|
const std::array<Vec3d, 3> axes = { Vec3d::UnitX(), Vec3d::UnitY(), Vec3d::UnitZ() };
|
||||||
|
std::array<Vec3d, 3> transformed_axes;
|
||||||
|
for (int i = 0; i < 3; ++i) {
|
||||||
|
transformed_axes[i] = trafo_linear * axes[i];
|
||||||
|
}
|
||||||
|
skew = std::abs(transformed_axes[0].dot(transformed_axes[1])) > EPSILON ||
|
||||||
|
std::abs(transformed_axes[1].dot(transformed_axes[2])) > EPSILON ||
|
||||||
|
std::abs(transformed_axes[2].dot(transformed_axes[0])) > EPSILON;
|
||||||
|
|
||||||
|
// This following old code does not work under all conditions. The v matrix can become non diagonal (see SPE-1492)
|
||||||
|
// skew = ! rotation_90_degrees;
|
||||||
} else
|
} else
|
||||||
skew = false;
|
skew = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3746,12 +3746,22 @@ void GLCanvas3D::do_reset_skew(const std::string& snapshot_type)
|
||||||
if (!snapshot_type.empty())
|
if (!snapshot_type.empty())
|
||||||
wxGetApp().plater()->take_snapshot(_(snapshot_type));
|
wxGetApp().plater()->take_snapshot(_(snapshot_type));
|
||||||
|
|
||||||
|
// stores current min_z of instances
|
||||||
|
std::map<std::pair<int, int>, double> min_zs;
|
||||||
|
if (!snapshot_type.empty()) {
|
||||||
|
for (int i = 0; i < static_cast<int>(m_model->objects.size()); ++i) {
|
||||||
|
const ModelObject* obj = m_model->objects[i];
|
||||||
|
for (int j = 0; j < static_cast<int>(obj->instances.size()); ++j) {
|
||||||
|
min_zs[{ i, j }] = obj->instance_bounding_box(j).min.z();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::set<std::pair<int, int>> done; // keeps track of modified instances
|
std::set<std::pair<int, int>> done; // keeps track of modified instances
|
||||||
|
|
||||||
const Selection::IndicesList& idxs = m_selection.get_volume_idxs();
|
Selection::EMode selection_mode = m_selection.get_mode();
|
||||||
|
|
||||||
for (unsigned int id : idxs) {
|
for (const GLVolume* v : m_volumes.volumes) {
|
||||||
const GLVolume* v = m_volumes.volumes[id];
|
|
||||||
int object_idx = v->object_idx();
|
int object_idx = v->object_idx();
|
||||||
if (object_idx < 0 || (int)m_model->objects.size() <= object_idx)
|
if (object_idx < 0 || (int)m_model->objects.size() <= object_idx)
|
||||||
continue;
|
continue;
|
||||||
|
@ -3761,14 +3771,30 @@ void GLCanvas3D::do_reset_skew(const std::string& snapshot_type)
|
||||||
|
|
||||||
done.insert(std::pair<int, int>(object_idx, instance_idx));
|
done.insert(std::pair<int, int>(object_idx, instance_idx));
|
||||||
|
|
||||||
|
// Mirror instances/volumes
|
||||||
ModelObject* model_object = m_model->objects[object_idx];
|
ModelObject* model_object = m_model->objects[object_idx];
|
||||||
if (model_object != nullptr) {
|
if (model_object != nullptr) {
|
||||||
|
if (selection_mode == Selection::Instance)
|
||||||
model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
|
model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
|
||||||
|
else if (selection_mode == Selection::Volume)
|
||||||
model_object->volumes[volume_idx]->set_transformation(v->get_volume_transformation());
|
model_object->volumes[volume_idx]->set_transformation(v->get_volume_transformation());
|
||||||
model_object->invalidate_bounding_box();
|
model_object->invalidate_bounding_box();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fixes sinking/flying instances
|
||||||
|
for (const std::pair<int, int>& i : done) {
|
||||||
|
ModelObject* m = m_model->objects[i.first];
|
||||||
|
double shift_z = m->get_instance_min_z(i.second);
|
||||||
|
// leave sinking instances as sinking
|
||||||
|
if (min_zs.empty() || min_zs.find({ i.first, i.second })->second >= SINKING_Z_THRESHOLD || shift_z > SINKING_Z_THRESHOLD) {
|
||||||
|
Vec3d shift(0.0, 0.0, -shift_z);
|
||||||
|
m_selection.translate(i.first, i.second, shift);
|
||||||
|
m->translate_instance(i.second, shift);
|
||||||
|
}
|
||||||
|
wxGetApp().obj_list()->update_info_items(static_cast<size_t>(i.first));
|
||||||
|
}
|
||||||
|
|
||||||
post_event(SimpleEvent(EVT_GLCANVAS_RESET_SKEW));
|
post_event(SimpleEvent(EVT_GLCANVAS_RESET_SKEW));
|
||||||
|
|
||||||
m_dirty = true;
|
m_dirty = true;
|
||||||
|
|
|
@ -446,7 +446,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
||||||
m_reset_rotation_button->Bind(wxEVT_BUTTON, [this](wxCommandEvent& e) {
|
m_reset_rotation_button->Bind(wxEVT_BUTTON, [this](wxCommandEvent& e) {
|
||||||
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
|
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
|
||||||
Selection& selection = canvas->get_selection();
|
Selection& selection = canvas->get_selection();
|
||||||
|
selection.setup_cache();
|
||||||
#if ENABLE_WORLD_COORDINATE
|
#if ENABLE_WORLD_COORDINATE
|
||||||
if (selection.is_single_volume_or_modifier()) {
|
if (selection.is_single_volume_or_modifier()) {
|
||||||
GLVolume* vol = const_cast<GLVolume*>(selection.get_first_volume());
|
GLVolume* vol = const_cast<GLVolume*>(selection.get_first_volume());
|
||||||
|
@ -468,9 +468,11 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
||||||
else
|
else
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Update rotation at the GLVolumes.
|
// Synchronize instances/volumes.
|
||||||
selection.synchronize_unselected_instances(Selection::SyncRotationType::GENERAL);
|
|
||||||
|
selection.synchronize_unselected_instances(Selection::SyncRotationType::RESET);
|
||||||
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"));
|
||||||
|
|
||||||
|
@ -490,6 +492,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
||||||
#if ENABLE_WORLD_COORDINATE
|
#if ENABLE_WORLD_COORDINATE
|
||||||
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
|
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
|
||||||
Selection& selection = canvas->get_selection();
|
Selection& selection = canvas->get_selection();
|
||||||
|
selection.setup_cache();
|
||||||
if (selection.is_single_volume_or_modifier()) {
|
if (selection.is_single_volume_or_modifier()) {
|
||||||
GLVolume* vol = const_cast<GLVolume*>(selection.get_first_volume());
|
GLVolume* vol = const_cast<GLVolume*>(selection.get_first_volume());
|
||||||
Geometry::Transformation trafo = vol->get_volume_transformation();
|
Geometry::Transformation trafo = vol->get_volume_transformation();
|
||||||
|
@ -506,6 +509,10 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
||||||
else
|
else
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// Synchronize instances/volumes.
|
||||||
|
selection.synchronize_unselected_instances(Selection::SyncRotationType::GENERAL);
|
||||||
|
selection.synchronize_unselected_volumes();
|
||||||
|
|
||||||
canvas->do_scale(L("Reset scale"));
|
canvas->do_scale(L("Reset scale"));
|
||||||
UpdateAndShow(true);
|
UpdateAndShow(true);
|
||||||
#else
|
#else
|
||||||
|
@ -750,7 +757,7 @@ void ObjectManipulation::update_settings_value(const Selection& selection)
|
||||||
m_new_rotation = volume->get_instance_rotation() * (180.0 / M_PI);
|
m_new_rotation = volume->get_instance_rotation() * (180.0 / M_PI);
|
||||||
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());
|
||||||
#endif // ENABLE_WORLD_COORDINATE
|
#endif // ENABLE_WORLD_COORDINATE
|
||||||
m_new_scale = volume->get_instance_scaling_factor() * 100.0;
|
m_new_scale = m_new_size.cwiseQuotient(selection.get_full_unscaled_instance_local_bounding_box().size()) * 100.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_new_enabled = true;
|
m_new_enabled = true;
|
||||||
|
|
|
@ -238,13 +238,7 @@ void GLGizmoRotate::init_data_from_selection(const Selection& selection)
|
||||||
selection.get_bounding_box_in_reference_system(ECoordinatesType::Local) : selection.get_bounding_box_in_current_reference_system();
|
selection.get_bounding_box_in_reference_system(ECoordinatesType::Local) : selection.get_bounding_box_in_current_reference_system();
|
||||||
m_bounding_box = box;
|
m_bounding_box = box;
|
||||||
m_center = box_trafo.translation();
|
m_center = box_trafo.translation();
|
||||||
m_orient_matrix = Geometry::translation_transform(m_center);
|
m_orient_matrix = box_trafo;
|
||||||
if (!wxGetApp().obj_manipul()->is_world_coordinates() || m_force_local_coordinate) {
|
|
||||||
const GLVolume& v = *selection.get_first_volume();
|
|
||||||
m_orient_matrix = m_orient_matrix * v.get_instance_transformation().get_rotation_matrix();
|
|
||||||
if (selection.is_single_volume_or_modifier() && wxGetApp().obj_manipul()->is_local_coordinates() || m_force_local_coordinate)
|
|
||||||
m_orient_matrix = m_orient_matrix * v.get_volume_transformation().get_rotation_matrix();
|
|
||||||
}
|
|
||||||
|
|
||||||
m_radius = Offset + m_bounding_box.radius();
|
m_radius = Offset + m_bounding_box.radius();
|
||||||
m_snap_coarse_in_radius = m_radius / 3.0f;
|
m_snap_coarse_in_radius = m_radius / 3.0f;
|
||||||
|
|
|
@ -918,7 +918,7 @@ void Selection::translate(const Vec3d& displacement, TransformationType transfor
|
||||||
v.set_instance_offset(inst_trafo.get_offset() + inst_trafo.get_rotation_matrix() * displacement);
|
v.set_instance_offset(inst_trafo.get_offset() + inst_trafo.get_rotation_matrix() * displacement);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
transform_instance_relative_world(v, volume_data, transformation_type, Geometry::translation_transform(displacement), m_cache.dragging_center);
|
transform_instance_relative(v, volume_data, transformation_type, Geometry::translation_transform(displacement), m_cache.dragging_center);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (transformation_type.local() && transformation_type.absolute()) {
|
if (transformation_type.local() && transformation_type.absolute()) {
|
||||||
|
@ -998,24 +998,32 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_
|
||||||
|
|
||||||
assert(transformation_type.relative() || (transformation_type.absolute() && transformation_type.local()));
|
assert(transformation_type.relative() || (transformation_type.absolute() && transformation_type.local()));
|
||||||
|
|
||||||
Transform3d rotation_matrix = Geometry::rotation_transform(rotation);
|
|
||||||
|
|
||||||
for (unsigned int i : m_list) {
|
for (unsigned int i : m_list) {
|
||||||
|
Transform3d rotation_matrix = Geometry::rotation_transform(rotation);
|
||||||
GLVolume& v = *(*m_volumes)[i];
|
GLVolume& v = *(*m_volumes)[i];
|
||||||
const VolumeCache& volume_data = m_cache.volumes_data[i];
|
const VolumeCache& volume_data = m_cache.volumes_data[i];
|
||||||
const Geometry::Transformation& inst_trafo = volume_data.get_instance_transform();
|
const Geometry::Transformation& inst_trafo = volume_data.get_instance_transform();
|
||||||
if (m_mode == Instance && !is_wipe_tower()) {
|
if (m_mode == Instance && !is_wipe_tower()) {
|
||||||
assert(is_from_fully_selected_instance(i));
|
assert(is_from_fully_selected_instance(i));
|
||||||
if (transformation_type.instance()) {
|
if (transformation_type.instance()) {
|
||||||
const Vec3d world_inst_pivot = m_cache.dragging_center - inst_trafo.get_offset();
|
// ensure that the instance rotates as a rigid body
|
||||||
const Vec3d local_inst_pivot = inst_trafo.get_matrix_no_offset().inverse() * world_inst_pivot;
|
Transform3d inst_rotation_matrix = inst_trafo.get_rotation_matrix();
|
||||||
Matrix3d inst_rotation, inst_scale;
|
if (inst_trafo.is_left_handed()) {
|
||||||
inst_trafo.get_matrix().computeRotationScaling(&inst_rotation, &inst_scale);
|
Geometry::TransformationSVD inst_svd(inst_trafo);
|
||||||
const Transform3d trafo = inst_trafo.get_rotation_matrix() * rotation_matrix;
|
inst_rotation_matrix = inst_svd.u * inst_svd.v.transpose();
|
||||||
v.set_instance_transformation(Geometry::translation_transform(world_inst_pivot) * inst_trafo.get_offset_matrix() * trafo * Transform3d(inst_scale) * Geometry::translation_transform(-local_inst_pivot));
|
// ensure the rotation has the proper direction
|
||||||
|
if (!rotation.normalized().cwiseAbs().isApprox(Vec3d::UnitX()))
|
||||||
|
rotation_matrix = rotation_matrix.inverse();
|
||||||
}
|
}
|
||||||
else
|
|
||||||
transform_instance_relative_world(v, volume_data, transformation_type, rotation_matrix, m_cache.dragging_center);
|
const Transform3d inst_matrix_no_offset = inst_trafo.get_matrix_no_offset();
|
||||||
|
rotation_matrix = inst_matrix_no_offset.inverse() * inst_rotation_matrix * rotation_matrix * inst_rotation_matrix.inverse() * inst_matrix_no_offset;
|
||||||
|
|
||||||
|
// rotate around selection center
|
||||||
|
const Vec3d inst_pivot = inst_trafo.get_matrix_no_offset().inverse() * (m_cache.dragging_center - inst_trafo.get_offset());
|
||||||
|
rotation_matrix = Geometry::translation_transform(inst_pivot) * rotation_matrix * Geometry::translation_transform(-inst_pivot);
|
||||||
|
}
|
||||||
|
transform_instance_relative(v, volume_data, transformation_type, rotation_matrix, m_cache.dragging_center);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (!is_single_volume_or_modifier()) {
|
if (!is_single_volume_or_modifier()) {
|
||||||
|
@ -1024,49 +1032,38 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (transformation_type.instance()) {
|
if (transformation_type.instance()) {
|
||||||
const Geometry::Transformation& vol_trafo = volume_data.get_volume_transform();
|
|
||||||
const Geometry::Transformation world_trafo = inst_trafo * vol_trafo;
|
|
||||||
// ensure proper sign of rotation for mirrored objects
|
|
||||||
if (world_trafo.is_left_handed() && !rotation.normalized().isApprox(Vec3d::UnitX()))
|
|
||||||
rotation_matrix = rotation_matrix.inverse();
|
|
||||||
|
|
||||||
// ensure that the volume rotates as a rigid body
|
// ensure that the volume rotates as a rigid body
|
||||||
const Geometry::TransformationSVD world_svd(world_trafo);
|
const Transform3d inst_scale_matrix = inst_trafo.get_scaling_factor_matrix();
|
||||||
if (world_svd.anisotropic_scale) {
|
rotation_matrix = inst_scale_matrix.inverse() * rotation_matrix * inst_scale_matrix;
|
||||||
const Transform3d vol_scale_matrix = vol_trafo.get_scaling_factor_matrix();
|
|
||||||
rotation_matrix = vol_scale_matrix.inverse() * rotation_matrix * vol_scale_matrix;
|
|
||||||
}
|
|
||||||
const Transform3d vol_rotation_matrix = vol_trafo.get_rotation_matrix();
|
|
||||||
rotation_matrix = vol_rotation_matrix.inverse() * rotation_matrix * vol_rotation_matrix;
|
|
||||||
|
|
||||||
v.set_volume_transformation(vol_trafo.get_matrix() * rotation_matrix);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (transformation_type.local()) {
|
if (transformation_type.local()) {
|
||||||
const Geometry::Transformation& vol_trafo = volume_data.get_volume_transform();
|
|
||||||
const Geometry::Transformation world_trafo = inst_trafo * vol_trafo;
|
|
||||||
// ensure proper sign of rotation for mirrored objects
|
|
||||||
if (world_trafo.is_left_handed() && !rotation.normalized().isApprox(Vec3d::UnitX()))
|
|
||||||
rotation_matrix = rotation_matrix.inverse();
|
|
||||||
|
|
||||||
// ensure that the volume rotates as a rigid body
|
// ensure that the volume rotates as a rigid body
|
||||||
const Geometry::TransformationSVD svd(world_trafo);
|
const Geometry::Transformation& vol_trafo = volume_data.get_volume_transform();
|
||||||
if (svd.anisotropic_scale) {
|
const Transform3d vol_matrix_no_offset = vol_trafo.get_matrix_no_offset();
|
||||||
const Transform3d vol_scale_matrix = vol_trafo.get_scaling_factor_matrix();
|
const Transform3d inst_scale_matrix = inst_trafo.get_scaling_factor_matrix();
|
||||||
rotation_matrix = vol_scale_matrix.inverse() * rotation_matrix * vol_scale_matrix;
|
Transform3d vol_rotation_matrix = vol_trafo.get_rotation_matrix();
|
||||||
|
if (vol_trafo.is_left_handed()) {
|
||||||
|
Geometry::TransformationSVD vol_svd(vol_trafo);
|
||||||
|
vol_rotation_matrix = vol_svd.u * vol_svd.v.transpose();
|
||||||
|
// ensure the rotation has the proper direction
|
||||||
|
if (!rotation.normalized().cwiseAbs().isApprox(Vec3d::UnitX()))
|
||||||
|
rotation_matrix = rotation_matrix.inverse();
|
||||||
|
}
|
||||||
|
rotation_matrix = vol_matrix_no_offset.inverse() * inst_scale_matrix.inverse() * vol_rotation_matrix * rotation_matrix *
|
||||||
|
vol_rotation_matrix.inverse() * inst_scale_matrix * vol_matrix_no_offset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
transform_volume_relative(v, volume_data, transformation_type, rotation_matrix, m_cache.dragging_center);
|
transform_volume_relative(v, volume_data, transformation_type, rotation_matrix, m_cache.dragging_center);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#if !DISABLE_INSTANCES_SYNCH
|
#if !DISABLE_INSTANCES_SYNCH
|
||||||
if (m_mode == Instance) {
|
if (m_mode == Instance) {
|
||||||
int rot_axis_max = 0;
|
int rot_axis_max = 0;
|
||||||
rotation.cwiseAbs().maxCoeff(&rot_axis_max);
|
rotation.cwiseAbs().maxCoeff(&rot_axis_max);
|
||||||
synchronize_unselected_instances((transformation_type.world() && rot_axis_max == 2) ? SyncRotationType::NONE : SyncRotationType::GENERAL);
|
synchronize_unselected_instances((rot_axis_max == 2) ? SyncRotationType::NONE : SyncRotationType::GENERAL);
|
||||||
}
|
}
|
||||||
else if (m_mode == Volume)
|
else if (m_mode == Volume)
|
||||||
synchronize_unselected_volumes();
|
synchronize_unselected_volumes();
|
||||||
|
@ -1468,7 +1465,7 @@ void Selection::scale_and_translate(const Vec3d& scale, const Vec3d& translation
|
||||||
v.set_instance_transformation(Geometry::translation_transform(world_inst_pivot) * offset_trafo * Transform3d(inst_rotation) * scale_trafo * Geometry::translation_transform(-local_inst_pivot));
|
v.set_instance_transformation(Geometry::translation_transform(world_inst_pivot) * offset_trafo * Transform3d(inst_rotation) * scale_trafo * Geometry::translation_transform(-local_inst_pivot));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
transform_instance_relative_world(v, volume_data, transformation_type, Geometry::translation_transform(translation) * Geometry::scale_transform(relative_scale), m_cache.dragging_center);
|
transform_instance_relative(v, volume_data, transformation_type, Geometry::translation_transform(translation) * Geometry::scale_transform(relative_scale), m_cache.dragging_center);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (!is_single_volume_or_modifier()) {
|
if (!is_single_volume_or_modifier()) {
|
||||||
|
@ -1553,6 +1550,15 @@ void Selection::reset_skew()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !DISABLE_INSTANCES_SYNCH
|
||||||
|
if (m_mode == Instance)
|
||||||
|
// even if there is no rotation, we pass SyncRotationType::GENERAL to force
|
||||||
|
// synchronize_unselected_instances() to remove skew from the other instances
|
||||||
|
synchronize_unselected_instances(SyncRotationType::GENERAL);
|
||||||
|
else if (m_mode == Volume)
|
||||||
|
synchronize_unselected_volumes();
|
||||||
|
#endif // !DISABLE_INSTANCES_SYNCH
|
||||||
|
|
||||||
ensure_on_bed();
|
ensure_on_bed();
|
||||||
set_bounding_boxes_dirty();
|
set_bounding_boxes_dirty();
|
||||||
wxGetApp().plater()->canvas3D()->requires_check_outside_state();
|
wxGetApp().plater()->canvas3D()->requires_check_outside_state();
|
||||||
|
@ -2771,6 +2777,7 @@ void Selection::render_debug_window() const
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ImGuiWrapper& imgui = *wxGetApp().imgui();
|
ImGuiWrapper& imgui = *wxGetApp().imgui();
|
||||||
|
ImGui::SetNextWindowCollapsed(true, ImGuiCond_Once);
|
||||||
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) {
|
||||||
|
@ -3010,7 +3017,12 @@ void Selection::synchronize_unselected_instances(SyncRotationType sync_rotation_
|
||||||
const Transform3d& old_inst_trafo_j = m_cache.volumes_data[j].get_instance_transform().get_matrix();
|
const Transform3d& old_inst_trafo_j = m_cache.volumes_data[j].get_instance_transform().get_matrix();
|
||||||
assert(is_rotation_xy_synchronized(old_inst_trafo_i, old_inst_trafo_j));
|
assert(is_rotation_xy_synchronized(old_inst_trafo_i, old_inst_trafo_j));
|
||||||
Transform3d new_inst_trafo_j = volume_j->get_instance_transformation().get_matrix();
|
Transform3d new_inst_trafo_j = volume_j->get_instance_transformation().get_matrix();
|
||||||
if (sync_rotation_type != SyncRotationType::NONE || mirrored)
|
if (sync_rotation_type == SyncRotationType::RESET) {
|
||||||
|
Geometry::Transformation new_inst_trafo_j_no_rotation(new_inst_trafo_j);
|
||||||
|
new_inst_trafo_j_no_rotation.reset_rotation();
|
||||||
|
new_inst_trafo_j = new_inst_trafo_j_no_rotation.get_matrix();
|
||||||
|
}
|
||||||
|
else if (sync_rotation_type != SyncRotationType::NONE || mirrored)
|
||||||
new_inst_trafo_j.linear() = (old_inst_trafo_j.linear() * old_inst_trafo_i.linear().inverse()) * curr_inst_trafo_i.linear();
|
new_inst_trafo_j.linear() = (old_inst_trafo_j.linear() * old_inst_trafo_i.linear().inverse()) * curr_inst_trafo_i.linear();
|
||||||
if (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA)
|
if (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA)
|
||||||
new_inst_trafo_j.translation().z() = curr_inst_trafo_i.translation().z();
|
new_inst_trafo_j.translation().z() = curr_inst_trafo_i.translation().z();
|
||||||
|
@ -3326,17 +3338,22 @@ void Selection::paste_objects_from_clipboard()
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ENABLE_WORLD_COORDINATE
|
#if ENABLE_WORLD_COORDINATE
|
||||||
void Selection::transform_instance_relative_world(GLVolume& volume, const VolumeCache& volume_data, TransformationType transformation_type,
|
void Selection::transform_instance_relative(GLVolume& volume, const VolumeCache& volume_data, TransformationType transformation_type,
|
||||||
const Transform3d& transform, const Vec3d& world_pivot)
|
const Transform3d& transform, const Vec3d& world_pivot)
|
||||||
{
|
{
|
||||||
assert(transformation_type.relative());
|
assert(transformation_type.relative());
|
||||||
assert(transformation_type.world());
|
|
||||||
|
|
||||||
const Geometry::Transformation& inst_trafo = volume_data.get_instance_transform();
|
const Geometry::Transformation& inst_trafo = volume_data.get_instance_transform();
|
||||||
|
if (transformation_type.world()) {
|
||||||
const Vec3d inst_pivot = transformation_type.independent() && !is_from_single_instance() ? inst_trafo.get_offset() : world_pivot;
|
const Vec3d inst_pivot = transformation_type.independent() && !is_from_single_instance() ? inst_trafo.get_offset() : world_pivot;
|
||||||
const Transform3d trafo = Geometry::translation_transform(inst_pivot) * transform * Geometry::translation_transform(-inst_pivot);
|
const Transform3d trafo = Geometry::translation_transform(inst_pivot) * transform * Geometry::translation_transform(-inst_pivot);
|
||||||
volume.set_instance_transformation(trafo * inst_trafo.get_matrix());
|
volume.set_instance_transformation(trafo * inst_trafo.get_matrix());
|
||||||
}
|
}
|
||||||
|
else if (transformation_type.instance())
|
||||||
|
volume.set_instance_transformation(inst_trafo.get_matrix() * transform);
|
||||||
|
else
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
|
||||||
void Selection::transform_volume_relative(GLVolume& volume, const VolumeCache& volume_data, TransformationType transformation_type,
|
void Selection::transform_volume_relative(GLVolume& volume, const VolumeCache& volume_data, TransformationType transformation_type,
|
||||||
const Transform3d& transform, const Vec3d& world_pivot)
|
const Transform3d& transform, const Vec3d& world_pivot)
|
||||||
|
|
|
@ -499,6 +499,10 @@ public:
|
||||||
NONE = 0,
|
NONE = 0,
|
||||||
// Synchronize after rotation by an axis not parallel with Z.
|
// Synchronize after rotation by an axis not parallel with Z.
|
||||||
GENERAL = 1,
|
GENERAL = 1,
|
||||||
|
#if ENABLE_WORLD_COORDINATE
|
||||||
|
// Synchronize after rotation reset.
|
||||||
|
RESET = 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();
|
||||||
|
@ -512,7 +516,7 @@ private:
|
||||||
void paste_objects_from_clipboard();
|
void paste_objects_from_clipboard();
|
||||||
|
|
||||||
#if ENABLE_WORLD_COORDINATE
|
#if ENABLE_WORLD_COORDINATE
|
||||||
void transform_instance_relative_world(GLVolume& volume, const VolumeCache& volume_data, TransformationType transformation_type,
|
void transform_instance_relative(GLVolume& volume, const VolumeCache& volume_data, TransformationType transformation_type,
|
||||||
const Transform3d& transform, const Vec3d& world_pivot);
|
const Transform3d& transform, const Vec3d& world_pivot);
|
||||||
void transform_volume_relative(GLVolume& volume, const VolumeCache& volume_data, TransformationType transformation_type,
|
void transform_volume_relative(GLVolume& volume, const VolumeCache& volume_data, TransformationType transformation_type,
|
||||||
const Transform3d& transform, const Vec3d& world_pivot);
|
const Transform3d& transform, const Vec3d& world_pivot);
|
||||||
|
|
Loading…
Add table
Reference in a new issue