Tech ENABLE_ALLOW_NEGATIVE_Z-> Synchronize sinking instances

This commit is contained in:
enricoturri1966 2021-05-05 11:53:24 +02:00
parent 3f6123e653
commit bb18edde0a
2 changed files with 79 additions and 101 deletions

View File

@ -58,13 +58,11 @@ bool Selection::Clipboard::is_sla_compliant() const
if (m_mode == Selection::Volume)
return false;
for (const ModelObject* o : m_model->objects)
{
for (const ModelObject* o : m_model->objects) {
if (o->is_multiparts())
return false;
for (const ModelVolume* v : o->volumes)
{
for (const ModelVolume* v : o->volumes) {
if (v->is_modifier())
return false;
}
@ -78,7 +76,8 @@ Selection::Clipboard::Clipboard()
m_model.reset(new Model);
}
void Selection::Clipboard::reset() {
void Selection::Clipboard::reset()
{
m_model->clear_objects();
}
@ -149,7 +148,7 @@ void Selection::set_model(Model* model)
void Selection::add(unsigned int volume_idx, bool as_single_selection, bool check_for_already_contained)
{
if (!m_valid || ((unsigned int)m_volumes->size() <= volume_idx))
if (!m_valid || (unsigned int)m_volumes->size() <= volume_idx)
return;
const GLVolume* volume = (*m_volumes)[volume_idx];
@ -167,8 +166,7 @@ void Selection::add(unsigned int volume_idx, bool as_single_selection, bool chec
needs_reset |= as_single_selection && !is_any_modifier() && volume->is_modifier;
needs_reset |= is_any_modifier() && !volume->is_modifier;
if (!already_contained || needs_reset)
{
if (!already_contained || needs_reset) {
wxGetApp().plater()->take_snapshot(_L("Selection-Add"));
if (needs_reset)
@ -185,7 +183,7 @@ void Selection::add(unsigned int volume_idx, bool as_single_selection, bool chec
{
case Volume:
{
if ((volume->volume_idx() >= 0) && (is_empty() || (volume->instance_idx() == get_instance_idx())))
if (volume->volume_idx() >= 0 && (is_empty() || volume->instance_idx() == get_instance_idx()))
do_add_volume(volume_idx);
break;
@ -204,7 +202,7 @@ void Selection::add(unsigned int volume_idx, bool as_single_selection, bool chec
void Selection::remove(unsigned int volume_idx)
{
if (!m_valid || ((unsigned int)m_volumes->size() <= volume_idx))
if (!m_valid || (unsigned int)m_volumes->size() <= volume_idx)
return;
if (!contains_volume(volume_idx))
@ -333,10 +331,9 @@ void Selection::remove_volume(unsigned int object_idx, unsigned int volume_idx)
if (!m_valid)
return;
for (unsigned int i = 0; i < (unsigned int)m_volumes->size(); ++i)
{
for (unsigned int i = 0; i < (unsigned int)m_volumes->size(); ++i) {
GLVolume* v = (*m_volumes)[i];
if ((v->object_idx() == (int)object_idx) && (v->volume_idx() == (int)volume_idx))
if (v->object_idx() == (int)object_idx && v->volume_idx() == (int)volume_idx)
do_remove_volume(i);
}
@ -358,8 +355,7 @@ void Selection::add_volumes(EMode mode, const std::vector<unsigned int>& volume_
clear();
m_mode = mode;
for (unsigned int i : volume_idxs)
{
for (unsigned int i : volume_idxs) {
if (i < (unsigned int)m_volumes->size())
do_add_volume(i);
}
@ -374,8 +370,7 @@ void Selection::remove_volumes(EMode mode, const std::vector<unsigned int>& volu
return;
m_mode = mode;
for (unsigned int i : volume_idxs)
{
for (unsigned int i : volume_idxs) {
if (i < (unsigned int)m_volumes->size())
do_remove_volume(i);
}
@ -390,8 +385,7 @@ void Selection::add_all()
return;
unsigned int count = 0;
for (unsigned int i = 0; i < (unsigned int)m_volumes->size(); ++i)
{
for (unsigned int i = 0; i < (unsigned int)m_volumes->size(); ++i) {
if (!(*m_volumes)[i]->is_wipe_tower)
++count;
}
@ -404,8 +398,7 @@ void Selection::add_all()
m_mode = Instance;
clear();
for (unsigned int i = 0; i < (unsigned int)m_volumes->size(); ++i)
{
for (unsigned int i = 0; i < (unsigned int)m_volumes->size(); ++i) {
if (!(*m_volumes)[i]->is_wipe_tower)
do_add_volume(i);
}
@ -455,8 +448,7 @@ void Selection::clear()
if (m_list.empty())
return;
for (unsigned int i : m_list)
{
for (unsigned int i : m_list) {
(*m_volumes)[i]->selected = false;
}
@ -522,16 +514,15 @@ bool Selection::is_single_full_instance() const
return false;
int object_idx = m_valid ? get_object_idx() : -1;
if ((object_idx < 0) || ((int)m_model->objects.size() <= object_idx))
if (object_idx < 0 || (int)m_model->objects.size() <= object_idx)
return false;
int instance_idx = (*m_volumes)[*m_list.begin()]->instance_idx();
std::set<int> volumes_idxs;
for (unsigned int i : m_list)
{
for (unsigned int i : m_list) {
const GLVolume* v = (*m_volumes)[i];
if ((object_idx != v->object_idx()) || (instance_idx != v->instance_idx()))
if (object_idx != v->object_idx() || instance_idx != v->instance_idx())
return false;
int volume_idx = v->volume_idx();
@ -544,8 +535,8 @@ bool Selection::is_single_full_instance() const
bool Selection::is_from_single_object() const
{
int idx = get_object_idx();
return (0 <= idx) && (idx < 1000);
const int idx = get_object_idx();
return 0 <= idx && idx < 1000;
}
bool Selection::is_sla_compliant() const
@ -553,8 +544,7 @@ bool Selection::is_sla_compliant() const
if (m_mode == Volume)
return false;
for (unsigned int i : m_list)
{
for (unsigned int i : m_list) {
if ((*m_volumes)[i]->is_modifier)
return false;
}
@ -564,8 +554,7 @@ bool Selection::is_sla_compliant() const
bool Selection::contains_all_volumes(const std::vector<unsigned int>& volume_idxs) const
{
for (unsigned int i : volume_idxs)
{
for (unsigned int i : volume_idxs) {
if (m_list.find(i) == m_list.end())
return false;
}
@ -575,8 +564,7 @@ bool Selection::contains_all_volumes(const std::vector<unsigned int>& volume_idx
bool Selection::contains_any_volume(const std::vector<unsigned int>& volume_idxs) const
{
for (unsigned int i : volume_idxs)
{
for (unsigned int i : volume_idxs) {
if (m_list.find(i) != m_list.end())
return true;
}
@ -588,8 +576,7 @@ bool Selection::matches(const std::vector<unsigned int>& volume_idxs) const
{
unsigned int count = 0;
for (unsigned int i : volume_idxs)
{
for (unsigned int i : volume_idxs) {
if (m_list.find(i) != m_list.end())
++count;
else
@ -614,8 +601,7 @@ int Selection::get_object_idx() const
int Selection::get_instance_idx() const
{
if (m_cache.content.size() == 1)
{
if (m_cache.content.size() == 1) {
const InstanceIdxsList& idxs = m_cache.content.begin()->second;
if (idxs.size() == 1)
return *idxs.begin();
@ -673,12 +659,11 @@ void Selection::translate(const Vec3d& displacement, bool local)
EMode translation_type = m_mode;
for (unsigned int i : m_list) {
if (m_mode == Volume || (*m_volumes)[i]->is_wipe_tower)
{
if (m_mode == Volume || (*m_volumes)[i]->is_wipe_tower) {
if (local)
(*m_volumes)[i]->set_volume_offset(m_cache.volumes_data[i].get_volume_position() + displacement);
else {
Vec3d local_displacement = (m_cache.volumes_data[i].get_instance_rotation_matrix() * m_cache.volumes_data[i].get_instance_scale_matrix() * m_cache.volumes_data[i].get_instance_mirror_matrix()).inverse() * displacement;
const Vec3d local_displacement = (m_cache.volumes_data[i].get_instance_rotation_matrix() * m_cache.volumes_data[i].get_instance_scale_matrix() * m_cache.volumes_data[i].get_instance_mirror_matrix()).inverse() * displacement;
(*m_volumes)[i]->set_volume_offset(m_cache.volumes_data[i].get_volume_position() + local_displacement);
}
}
@ -686,7 +671,7 @@ void Selection::translate(const Vec3d& displacement, bool local)
if (is_from_fully_selected_instance(i))
(*m_volumes)[i]->set_instance_offset(m_cache.volumes_data[i].get_instance_position() + displacement);
else {
Vec3d local_displacement = (m_cache.volumes_data[i].get_instance_rotation_matrix() * m_cache.volumes_data[i].get_instance_scale_matrix() * m_cache.volumes_data[i].get_instance_mirror_matrix()).inverse() * displacement;
const Vec3d local_displacement = (m_cache.volumes_data[i].get_instance_rotation_matrix() * m_cache.volumes_data[i].get_instance_scale_matrix() * m_cache.volumes_data[i].get_instance_mirror_matrix()).inverse() * displacement;
(*m_volumes)[i]->set_volume_offset(m_cache.volumes_data[i].get_volume_position() + local_displacement);
translation_type = Volume;
}
@ -714,18 +699,14 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_
if (!is_wipe_tower()) {
int rot_axis_max = 0;
if (rotation.isApprox(Vec3d::Zero()))
{
for (unsigned int i : m_list)
{
if (rotation.isApprox(Vec3d::Zero())) {
for (unsigned int i : m_list) {
GLVolume &volume = *(*m_volumes)[i];
if (m_mode == Instance)
{
if (m_mode == Instance) {
volume.set_instance_rotation(m_cache.volumes_data[i].get_instance_rotation());
volume.set_instance_offset(m_cache.volumes_data[i].get_instance_position());
}
else if (m_mode == Volume)
{
else if (m_mode == Volume) {
volume.set_volume_rotation(m_cache.volumes_data[i].get_volume_rotation());
volume.set_volume_offset(m_cache.volumes_data[i].get_volume_position());
}
@ -742,14 +723,14 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_
// 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, transformation_type](GLVolume &volume, int i) {
int first_volume_idx = object_instance_first[volume.object_idx()];
const 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.
// Always do a local rotation (do not consider the selection to be a rigid body).
assert(is_approx(rotation.z(), 0.0));
const GLVolume &first_volume = *(*m_volumes)[first_volume_idx];
const Vec3d &rotation = first_volume.get_instance_rotation();
double z_diff = Geometry::rotation_diff_z(m_cache.volumes_data[first_volume_idx].get_instance_rotation(), m_cache.volumes_data[i].get_instance_rotation());
const double z_diff = Geometry::rotation_diff_z(m_cache.volumes_data[first_volume_idx].get_instance_rotation(), m_cache.volumes_data[i].get_instance_rotation());
volume.set_instance_rotation(Vec3d(rotation(0), rotation(1), rotation(2) + z_diff));
}
else {
@ -759,7 +740,7 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_
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.
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_rotation(new_rotation);
@ -767,19 +748,16 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_
}
};
for (unsigned int i : m_list)
{
for (unsigned int i : m_list) {
GLVolume &volume = *(*m_volumes)[i];
if (is_single_full_instance())
rotate_instance(volume, i);
else if (is_single_volume() || is_single_modifier())
{
else if (is_single_volume() || is_single_modifier()) {
if (transformation_type.independent())
volume.set_volume_rotation(volume.get_volume_rotation() + rotation);
else
{
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());
else {
const Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), rotation);
const Vec3d new_rotation = Geometry::extract_euler_angles(m * m_cache.volumes_data[i].get_volume_rotation_matrix());
volume.set_volume_rotation(new_rotation);
}
}
@ -787,15 +765,13 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_
{
if (m_mode == Instance)
rotate_instance(volume, i);
else if (m_mode == Volume)
{
else if (m_mode == Volume) {
// 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 (transformation_type.joint())
{
Vec3d local_pivot = m_cache.volumes_data[i].get_instance_full_matrix().inverse() * m_cache.dragging_center;
Vec3d offset = m * (m_cache.volumes_data[i].get_volume_position() - local_pivot);
if (transformation_type.joint()) {
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);
volume.set_volume_offset(local_pivot + offset);
}
volume.set_volume_rotation(new_rotation);
@ -816,8 +792,8 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_
// make sure the wipe tower rotates around its center, not origin
// we can assume that only Z rotation changes
Vec3d center_local = volume.transformed_bounding_box().center() - volume.get_volume_offset();
Vec3d center_local_new = Eigen::AngleAxisd(rotation(2)-volume.get_volume_rotation()(2), Vec3d(0, 0, 1)) * center_local;
const Vec3d center_local = volume.transformed_bounding_box().center() - volume.get_volume_offset();
const Vec3d center_local_new = Eigen::AngleAxisd(rotation(2)-volume.get_volume_rotation()(2), Vec3d(0.0, 0.0, 1.0)) * center_local;
volume.set_volume_rotation(rotation);
volume.set_volume_offset(volume.get_volume_offset() + center_local - center_local_new);
}
@ -835,8 +811,7 @@ void Selection::flattening_rotate(const Vec3d& normal)
if (!m_valid)
return;
for (unsigned int i : m_list)
{
for (unsigned int i : m_list) {
// Normal transformed from the object coordinate space to the world coordinate space.
const auto &voldata = m_cache.volumes_data[i];
Vec3d tnormal = (Geometry::assemble_transform(
@ -1781,18 +1756,16 @@ void Selection::render_synchronized_volumes() const
float color[3] = { 1.0f, 1.0f, 0.0f };
for (unsigned int i : m_list)
{
for (unsigned int i : m_list) {
const GLVolume* volume = (*m_volumes)[i];
int object_idx = volume->object_idx();
int volume_idx = volume->volume_idx();
for (unsigned int j = 0; j < (unsigned int)m_volumes->size(); ++j)
{
for (unsigned int j = 0; j < (unsigned int)m_volumes->size(); ++j) {
if (i == j)
continue;
const GLVolume* v = (*m_volumes)[j];
if ((v->object_idx() != object_idx) || (v->volume_idx() != volume_idx))
if (v->object_idx() != object_idx || v->volume_idx() != volume_idx)
continue;
render_bounding_box(v->transformed_convex_hull_bounding_box(), color);
@ -1986,7 +1959,7 @@ void Selection::render_sidebar_layers_hints(const std::string& sidebar_field) co
glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
::glBegin(GL_QUADS);
if ((camera_on_top && (type == 1)) || (!camera_on_top && (type == 2)))
if ((camera_on_top && type == 1) || (!camera_on_top && type == 2))
::glColor4f(1.0f, 0.38f, 0.0f, 1.0f);
else
::glColor4f(0.8f, 0.8f, 0.8f, 0.5f);
@ -1997,7 +1970,7 @@ void Selection::render_sidebar_layers_hints(const std::string& sidebar_field) co
glsafe(::glEnd());
::glBegin(GL_QUADS);
if ((camera_on_top && (type == 2)) || (!camera_on_top && (type == 1)))
if ((camera_on_top && type == 2) || (!camera_on_top && type == 1))
::glColor4f(1.0f, 0.38f, 0.0f, 1.0f);
else
::glColor4f(0.8f, 0.8f, 0.8f, 0.5f);
@ -2014,9 +1987,9 @@ void Selection::render_sidebar_layers_hints(const std::string& sidebar_field) co
#ifndef NDEBUG
static bool is_rotation_xy_synchronized(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to)
{
Eigen::AngleAxisd angle_axis(Geometry::rotation_xyz_diff(rot_xyz_from, rot_xyz_to));
Vec3d axis = angle_axis.axis();
double angle = angle_axis.angle();
const Eigen::AngleAxisd angle_axis(Geometry::rotation_xyz_diff(rot_xyz_from, rot_xyz_to));
const Vec3d axis = angle_axis.axis();
const double angle = angle_axis.angle();
if (std::abs(angle) < 1e-8)
return true;
assert(std::abs(axis.x()) < 1e-8);
@ -2053,24 +2026,22 @@ void Selection::synchronize_unselected_instances(SyncRotationType sync_rotation_
std::set<unsigned int> done; // prevent processing volumes twice
done.insert(m_list.begin(), m_list.end());
for (unsigned int i : m_list)
{
for (unsigned int i : m_list) {
if (done.size() == m_volumes->size())
break;
const GLVolume* volume = (*m_volumes)[i];
int object_idx = volume->object_idx();
const int object_idx = volume->object_idx();
if (object_idx >= 1000)
continue;
int instance_idx = volume->instance_idx();
const int instance_idx = volume->instance_idx();
const Vec3d& rotation = volume->get_instance_rotation();
const Vec3d& scaling_factor = volume->get_instance_scaling_factor();
const Vec3d& mirror = volume->get_instance_mirror();
// Process unselected instances.
for (unsigned int j = 0; j < (unsigned int)m_volumes->size(); ++j)
{
for (unsigned int j = 0; j < (unsigned int)m_volumes->size(); ++j) {
if (done.size() == m_volumes->size())
break;
@ -2078,24 +2049,33 @@ void Selection::synchronize_unselected_instances(SyncRotationType sync_rotation_
continue;
GLVolume* v = (*m_volumes)[j];
if ((v->object_idx() != object_idx) || (v->instance_idx() == instance_idx))
if (v->object_idx() != object_idx || v->instance_idx() == instance_idx)
continue;
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) {
case SYNC_ROTATION_NONE:
case SYNC_ROTATION_NONE: {
#if ENABLE_ALLOW_NEGATIVE_Z
// z only rotation -> synch instance z
// The X,Y rotations should be synchronized from start to end of the rotation.
assert(is_rotation_xy_synchronized(rotation, v->get_instance_rotation()));
v->set_instance_offset(Z, volume->get_instance_offset().z());
break;
#else
// z only rotation -> keep instance z
// The X,Y rotations should be synchronized from start to end of the rotation.
assert(is_rotation_xy_synchronized(rotation, v->get_instance_rotation()));
break;
#endif // ENABLE_ALLOW_NEGATIVE_Z
}
case SYNC_ROTATION_FULL:
// rotation comes from place on face -> force given z
v->set_instance_rotation(Vec3d(rotation(0), rotation(1), rotation(2)));
v->set_instance_rotation({ rotation.x(), rotation.y(), rotation.z() });
break;
case SYNC_ROTATION_GENERAL:
// generic rotation -> update instance z with the delta of the rotation.
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(Vec3d(rotation(0), rotation(1), rotation(2) + z_diff));
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 });
break;
}
@ -2113,27 +2093,25 @@ void Selection::synchronize_unselected_instances(SyncRotationType sync_rotation_
void Selection::synchronize_unselected_volumes()
{
for (unsigned int i : m_list)
{
for (unsigned int i : m_list) {
const GLVolume* volume = (*m_volumes)[i];
int object_idx = volume->object_idx();
const int object_idx = volume->object_idx();
if (object_idx >= 1000)
continue;
int volume_idx = volume->volume_idx();
const int volume_idx = volume->volume_idx();
const Vec3d& offset = volume->get_volume_offset();
const Vec3d& rotation = volume->get_volume_rotation();
const Vec3d& scaling_factor = volume->get_volume_scaling_factor();
const Vec3d& mirror = volume->get_volume_mirror();
// Process unselected volumes.
for (unsigned int j = 0; j < (unsigned int)m_volumes->size(); ++j)
{
for (unsigned int j = 0; j < (unsigned int)m_volumes->size(); ++j) {
if (j == i)
continue;
GLVolume* v = (*m_volumes)[j];
if ((v->object_idx() != object_idx) || (v->volume_idx() != volume_idx))
if (v->object_idx() != object_idx || v->volume_idx() != volume_idx)
continue;
v->set_volume_offset(offset);

View File

@ -129,7 +129,7 @@ private:
TransformCache m_instance;
public:
VolumeCache() {}
VolumeCache() = default;
VolumeCache(const Geometry::Transformation& volume_transform, const Geometry::Transformation& instance_transform);
const Vec3d& get_volume_position() const { return m_volume.position; }