Merge remote-tracking branch 'origin/et_trafo_matrix_rebase'

This commit is contained in:
enricoturri1966 2022-06-06 14:59:03 +02:00
commit db8a120953
42 changed files with 13353 additions and 10526 deletions

View File

@ -313,9 +313,60 @@ Transform3d assemble_transform(const Vec3d& translation, const Vec3d& rotation,
return transform;
}
void assemble_transform(Transform3d& transform, const Transform3d& translation, const Transform3d& rotation, const Transform3d& scale, const Transform3d& mirror)
{
transform = translation * rotation * scale * mirror;
}
Transform3d assemble_transform(const Transform3d& translation, const Transform3d& rotation, const Transform3d& scale, const Transform3d& mirror)
{
Transform3d transform;
assemble_transform(transform, translation, rotation, scale, mirror);
return transform;
}
void translation_transform(Transform3d& transform, const Vec3d& translation)
{
transform = Transform3d::Identity();
transform.translate(translation);
}
Transform3d translation_transform(const Vec3d& translation)
{
Transform3d transform;
translation_transform(transform, translation);
return transform;
}
void rotation_transform(Transform3d& transform, const Vec3d& rotation)
{
transform = Transform3d::Identity();
transform.rotate(Eigen::AngleAxisd(rotation.z(), Vec3d::UnitZ()) * Eigen::AngleAxisd(rotation.y(), Vec3d::UnitY()) * Eigen::AngleAxisd(rotation.x(), Vec3d::UnitX()));
}
Transform3d rotation_transform(const Vec3d& rotation)
{
Transform3d transform;
rotation_transform(transform, rotation);
return transform;
}
void scale_transform(Transform3d& transform, const Vec3d& scale)
{
transform = Transform3d::Identity();
transform.scale(scale);
}
Transform3d scale_transform(const Vec3d& scale)
{
Transform3d transform;
scale_transform(transform, scale);
return transform;
}
Vec3d extract_euler_angles(const Eigen::Matrix<double, 3, 3, Eigen::DontAlign>& rotation_matrix)
{
// reference: http://www.gregslabaugh.net/publications/euler.pdf
// reference: http://eecs.qmul.ac.uk/~gslabaugh/publications/euler.pdf
Vec3d angles1 = Vec3d::Zero();
Vec3d angles2 = Vec3d::Zero();
if (std::abs(std::abs(rotation_matrix(2, 0)) - 1.0) < 1e-5) {
@ -363,6 +414,54 @@ Vec3d extract_euler_angles(const Transform3d& transform)
return extract_euler_angles(m);
}
#if ENABLE_WORLD_COORDINATE
Transform3d Transformation::get_offset_matrix() const
{
return assemble_transform(get_offset());
}
static Transform3d extract_rotation(const Transform3d& trafo)
{
Matrix3d rotation;
Matrix3d scale;
trafo.computeRotationScaling(&rotation, &scale);
return Transform3d(rotation);
}
static Transform3d extract_scale(const Transform3d& trafo)
{
Matrix3d rotation;
Matrix3d scale;
trafo.computeRotationScaling(&rotation, &scale);
return Transform3d(scale);
}
static std::pair<Transform3d, Transform3d> extract_rotation_scale(const Transform3d& trafo)
{
Matrix3d rotation;
Matrix3d scale;
trafo.computeRotationScaling(&rotation, &scale);
return { Transform3d(rotation), Transform3d(scale) };
}
static bool contains_skew(const Transform3d& trafo)
{
Matrix3d rotation;
Matrix3d scale;
trafo.computeRotationScaling(&rotation, &scale);
return !scale.isDiagonal();
}
Vec3d Transformation::get_rotation() const
{
return extract_euler_angles(extract_rotation(m_matrix));
}
Transform3d Transformation::get_rotation_matrix() const
{
return extract_rotation(m_matrix);
}
#else
bool Transformation::Flags::needs_update(bool dont_translate, bool dont_rotate, bool dont_scale, bool dont_mirror) const
{
return (this->dont_translate != dont_translate) || (this->dont_rotate != dont_rotate) || (this->dont_scale != dont_scale) || (this->dont_mirror != dont_mirror);
@ -400,12 +499,19 @@ void Transformation::set_offset(Axis axis, double offset)
m_dirty = true;
}
}
#endif // ENABLE_WORLD_COORDINATE
void Transformation::set_rotation(const Vec3d& rotation)
{
#if ENABLE_WORLD_COORDINATE
const Vec3d offset = get_offset();
m_matrix = rotation_transform(rotation) * extract_scale(m_matrix);
m_matrix.translation() = offset;
#else
set_rotation(X, rotation.x());
set_rotation(Y, rotation.y());
set_rotation(Z, rotation.z());
#endif // ENABLE_WORLD_COORDINATE
}
void Transformation::set_rotation(Axis axis, double rotation)
@ -414,32 +520,106 @@ void Transformation::set_rotation(Axis axis, double rotation)
if (is_approx(std::abs(rotation), 2.0 * double(PI)))
rotation = 0.0;
#if ENABLE_WORLD_COORDINATE
auto [curr_rotation, scale] = extract_rotation_scale(m_matrix);
Vec3d angles = extract_euler_angles(curr_rotation);
angles[axis] = rotation;
const Vec3d offset = get_offset();
m_matrix = rotation_transform(angles) * scale;
m_matrix.translation() = offset;
#else
if (m_rotation(axis) != rotation) {
m_rotation(axis) = rotation;
m_dirty = true;
}
#endif // ENABLE_WORLD_COORDINATE
}
#if ENABLE_WORLD_COORDINATE
Vec3d Transformation::get_scaling_factor() const
{
const Transform3d scale = extract_scale(m_matrix);
return { scale(0, 0), scale(1, 1), scale(2, 2) };
}
Transform3d Transformation::get_scaling_factor_matrix() const
{
return extract_scale(m_matrix);
}
#endif // ENABLE_WORLD_COORDINATE
void Transformation::set_scaling_factor(const Vec3d& scaling_factor)
{
#if ENABLE_WORLD_COORDINATE
assert(scaling_factor.x() > 0.0 && scaling_factor.y() > 0.0 && scaling_factor.z() > 0.0);
const Vec3d offset = get_offset();
m_matrix = extract_rotation(m_matrix) * scale_transform(scaling_factor);
m_matrix.translation() = offset;
#else
set_scaling_factor(X, scaling_factor.x());
set_scaling_factor(Y, scaling_factor.y());
set_scaling_factor(Z, scaling_factor.z());
#endif // ENABLE_WORLD_COORDINATE
}
void Transformation::set_scaling_factor(Axis axis, double scaling_factor)
{
#if ENABLE_WORLD_COORDINATE
assert(scaling_factor > 0.0);
auto [rotation, scale] = extract_rotation_scale(m_matrix);
scale(axis, axis) = scaling_factor;
const Vec3d offset = get_offset();
m_matrix = rotation * scale;
m_matrix.translation() = offset;
#else
if (m_scaling_factor(axis) != std::abs(scaling_factor)) {
m_scaling_factor(axis) = std::abs(scaling_factor);
m_dirty = true;
}
#endif // ENABLE_WORLD_COORDINATE
}
#if ENABLE_WORLD_COORDINATE
Vec3d Transformation::get_mirror() const
{
const Transform3d scale = extract_scale(m_matrix);
return { scale(0, 0) / std::abs(scale(0, 0)), scale(1, 1) / std::abs(scale(1, 1)), scale(2, 2) / std::abs(scale(2, 2)) };
}
Transform3d Transformation::get_mirror_matrix() const
{
const Vec3d scale = get_scaling_factor();
return scale_transform({ scale.x() / std::abs(scale.x()), scale.y() / std::abs(scale.y()), scale.z() / std::abs(scale.z()) });
}
#endif // ENABLE_WORLD_COORDINATE
void Transformation::set_mirror(const Vec3d& mirror)
{
#if ENABLE_WORLD_COORDINATE
Vec3d copy(mirror);
const Vec3d abs_mirror = copy.cwiseAbs();
for (int i = 0; i < 3; ++i) {
if (abs_mirror(i) == 0.0)
copy(i) = 1.0;
else if (abs_mirror(i) != 1.0)
copy(i) /= abs_mirror(i);
}
const Vec3d curr_scale = get_scaling_factor();
const Vec3d signs = curr_scale.cwiseProduct(copy);
set_scaling_factor({
signs.x() < 0.0 ? std::abs(curr_scale.x()) * copy.x() : curr_scale.x(),
signs.y() < 0.0 ? std::abs(curr_scale.y()) * copy.y() : curr_scale.y(),
signs.z() < 0.0 ? std::abs(curr_scale.z()) * copy.z() : curr_scale.z()
});
#else
set_mirror(X, mirror.x());
set_mirror(Y, mirror.y());
set_mirror(Z, mirror.z());
#endif // ENABLE_WORLD_COORDINATE
}
void Transformation::set_mirror(Axis axis, double mirror)
@ -450,12 +630,24 @@ void Transformation::set_mirror(Axis axis, double mirror)
else if (abs_mirror != 1.0)
mirror /= abs_mirror;
#if ENABLE_WORLD_COORDINATE
const double curr_scale = get_scaling_factor(axis);
const double sign = curr_scale * mirror;
set_scaling_factor(axis, sign < 0.0 ? std::abs(curr_scale) * mirror : curr_scale);
#else
if (m_mirror(axis) != mirror) {
m_mirror(axis) = mirror;
m_dirty = true;
}
#endif // ENABLE_WORLD_COORDINATE
}
#if ENABLE_WORLD_COORDINATE
bool Transformation::has_skew() const
{
return contains_skew(m_matrix);
}
#else
void Transformation::set_from_transform(const Transform3d& transform)
{
// offset
@ -493,17 +685,62 @@ void Transformation::set_from_transform(const Transform3d& transform)
// if (!m_matrix.isApprox(transform))
// std::cout << "something went wrong in extracting data from matrix" << std::endl;
}
#endif // ENABLE_WORLD_COORDINATE
void Transformation::reset()
{
#if !ENABLE_WORLD_COORDINATE
m_offset = Vec3d::Zero();
m_rotation = Vec3d::Zero();
m_scaling_factor = Vec3d::Ones();
m_mirror = Vec3d::Ones();
#endif // !ENABLE_WORLD_COORDINATE
m_matrix = Transform3d::Identity();
#if !ENABLE_WORLD_COORDINATE
m_dirty = false;
#endif // !ENABLE_WORLD_COORDINATE
}
#if ENABLE_WORLD_COORDINATE
void Transformation::reset_skew()
{
Matrix3d rotation;
Matrix3d scale;
m_matrix.computeRotationScaling(&rotation, &scale);
const double average_scale = std::cbrt(scale(0, 0) * scale(1, 1) * scale(2, 2));
scale(0, 0) = average_scale;
scale(1, 1) = average_scale;
scale(2, 2) = average_scale;
scale(0, 1) = 0.0;
scale(0, 2) = 0.0;
scale(1, 0) = 0.0;
scale(1, 2) = 0.0;
scale(2, 0) = 0.0;
scale(2, 1) = 0.0;
const Vec3d offset = get_offset();
m_matrix = rotation * scale;
m_matrix.translation() = offset;
}
Transform3d Transformation::get_matrix_no_offset() const
{
Transformation copy(*this);
copy.reset_offset();
return copy.get_matrix();
}
Transform3d Transformation::get_matrix_no_scaling_factor() const
{
Transformation copy(*this);
copy.reset_scaling_factor();
copy.reset_mirror();
return copy.get_matrix();
}
#else
const Transform3d& Transformation::get_matrix(bool dont_translate, bool dont_rotate, bool dont_scale, bool dont_mirror) const
{
if (m_dirty || m_flags.needs_update(dont_translate, dont_rotate, dont_scale, dont_mirror)) {
@ -520,12 +757,14 @@ const Transform3d& Transformation::get_matrix(bool dont_translate, bool dont_rot
return m_matrix;
}
#endif // ENABLE_WORLD_COORDINATE
Transformation Transformation::operator * (const Transformation& other) const
{
return Transformation(get_matrix() * other.get_matrix());
}
#if !ENABLE_WORLD_COORDINATE
Transformation Transformation::volume_to_bed_transformation(const Transformation& instance_transformation, const BoundingBoxf3& bbox)
{
Transformation out;
@ -571,8 +810,7 @@ Transformation Transformation::volume_to_bed_transformation(const Transformation
out.set_scaling_factor(Vec3d(std::abs(scale.x()), std::abs(scale.y()), std::abs(scale.z())));
out.set_mirror(Vec3d(scale.x() > 0 ? 1. : -1, scale.y() > 0 ? 1. : -1, scale.z() > 0 ? 1. : -1));
}
else
{
else {
// General anisotropic scaling, general rotation.
// Keep the modifier mesh in the instance coordinate system, so the modifier mesh will not be aligned with the world.
// Scale it to get the required size.
@ -581,6 +819,7 @@ Transformation Transformation::volume_to_bed_transformation(const Transformation
return out;
}
#endif // !ENABLE_WORLD_COORDINATE
// For parsing a transformation matrix from 3MF / AMF.
Transform3d transform3d_from_string(const std::string& transform_str)
@ -619,7 +858,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)
{
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();
#ifndef NDEBUG
if (std::abs(angle) > 1e-8) {

View File

@ -323,7 +323,8 @@ bool arrange(
// 4) rotate Y
// 5) rotate Z
// 6) translate
void assemble_transform(Transform3d& transform, const Vec3d& translation = Vec3d::Zero(), const Vec3d& rotation = Vec3d::Zero(), const Vec3d& scale = Vec3d::Ones(), const Vec3d& mirror = Vec3d::Ones());
void assemble_transform(Transform3d& transform, const Vec3d& translation = Vec3d::Zero(), const Vec3d& rotation = Vec3d::Zero(),
const Vec3d& scale = Vec3d::Ones(), const Vec3d& mirror = Vec3d::Ones());
// Returns the transform obtained by assembling the given transformations in the following order:
// 1) mirror
@ -332,7 +333,43 @@ void assemble_transform(Transform3d& transform, const Vec3d& translation = Vec3d
// 4) rotate Y
// 5) rotate Z
// 6) translate
Transform3d assemble_transform(const Vec3d& translation = Vec3d::Zero(), const Vec3d& rotation = Vec3d::Zero(), const Vec3d& scale = Vec3d::Ones(), const Vec3d& mirror = Vec3d::Ones());
Transform3d assemble_transform(const Vec3d& translation = Vec3d::Zero(), const Vec3d& rotation = Vec3d::Zero(),
const Vec3d& scale = Vec3d::Ones(), const Vec3d& mirror = Vec3d::Ones());
// Sets the given transform by multiplying the given transformations in the following order:
// T = translation * rotation * scale * mirror
void assemble_transform(Transform3d& transform, const Transform3d& translation = Transform3d::Identity(),
const Transform3d& rotation = Transform3d::Identity(), const Transform3d& scale = Transform3d::Identity(),
const Transform3d& mirror = Transform3d::Identity());
// Returns the transform obtained by multiplying the given transformations in the following order:
// T = translation * rotation * scale * mirror
Transform3d assemble_transform(const Transform3d& translation = Transform3d::Identity(), const Transform3d& rotation = Transform3d::Identity(),
const Transform3d& scale = Transform3d::Identity(), const Transform3d& mirror = Transform3d::Identity());
// Sets the given transform by assembling the given translation
void translation_transform(Transform3d& transform, const Vec3d& translation);
// Returns the transform obtained by assembling the given translation
Transform3d translation_transform(const Vec3d& translation);
// Sets the given transform by assembling the given rotations in the following order:
// 1) rotate X
// 2) rotate Y
// 3) rotate Z
void rotation_transform(Transform3d& transform, const Vec3d& rotation);
// Returns the transform obtained by assembling the given rotations in the following order:
// 1) rotate X
// 2) rotate Y
// 3) rotate Z
Transform3d rotation_transform(const Vec3d& rotation);
// Sets the given transform by assembling the given scale factors
void scale_transform(Transform3d& transform, const Vec3d& scale);
// Returns the transform obtained by assembling the given scale factors
Transform3d scale_transform(const Vec3d& scale);
// Returns the euler angles extracted from the given rotation matrix
// Warning -> The matrix should not contain any scale or shear !!!
@ -344,6 +381,9 @@ Vec3d extract_euler_angles(const Transform3d& transform);
class Transformation
{
#if ENABLE_WORLD_COORDINATE
Transform3d m_matrix{ Transform3d::Identity() };
#else
struct Flags
{
bool dont_translate{ true };
@ -363,8 +403,26 @@ class Transformation
mutable Transform3d m_matrix{ Transform3d::Identity() };
mutable Flags m_flags;
mutable bool m_dirty{ false };
#endif // ENABLE_WORLD_COORDINATE
public:
#if ENABLE_WORLD_COORDINATE
Transformation() = default;
explicit Transformation(const Transform3d& transform) : m_matrix(transform) {}
Vec3d get_offset() const { return m_matrix.translation(); }
double get_offset(Axis axis) const { return get_offset()[axis]; }
Transform3d get_offset_matrix() const;
void set_offset(const Vec3d& offset) { m_matrix.translation() = offset; }
void set_offset(Axis axis, double offset) { m_matrix.translation()[axis] = offset; }
Vec3d get_rotation() const;
double get_rotation(Axis axis) const { return get_rotation()[axis]; }
Transform3d get_rotation_matrix() const;
#else
Transformation();
explicit Transformation(const Transform3d& transform);
@ -376,39 +434,94 @@ public:
const Vec3d& get_rotation() const { return m_rotation; }
double get_rotation(Axis axis) const { return m_rotation(axis); }
#endif // ENABLE_WORLD_COORDINATE
void set_rotation(const Vec3d& rotation);
void set_rotation(Axis axis, double rotation);
#if ENABLE_WORLD_COORDINATE
Vec3d get_scaling_factor() const;
double get_scaling_factor(Axis axis) const { return get_scaling_factor()[axis]; }
Transform3d get_scaling_factor_matrix() const;
bool is_scaling_uniform() const {
const Vec3d scale = get_scaling_factor();
return std::abs(scale.x() - scale.y()) < 1e-8 && std::abs(scale.x() - scale.z()) < 1e-8;
}
#else
const Vec3d& get_scaling_factor() const { return m_scaling_factor; }
double get_scaling_factor(Axis axis) const { return m_scaling_factor(axis); }
#endif // ENABLE_WORLD_COORDINATE
void set_scaling_factor(const Vec3d& scaling_factor);
void set_scaling_factor(Axis axis, double scaling_factor);
#if ENABLE_WORLD_COORDINATE
Vec3d get_mirror() const;
double get_mirror(Axis axis) const { return get_mirror()[axis]; }
Transform3d get_mirror_matrix() const;
bool is_left_handed() const {
const Vec3d mirror = get_mirror();
return mirror.x() * mirror.y() * mirror.z() < 0.0;
}
#else
bool is_scaling_uniform() const { return std::abs(m_scaling_factor.x() - m_scaling_factor.y()) < 1e-8 && std::abs(m_scaling_factor.x() - m_scaling_factor.z()) < 1e-8; }
const Vec3d& get_mirror() const { return m_mirror; }
double get_mirror(Axis axis) const { return m_mirror(axis); }
bool is_left_handed() const { return m_mirror.x() * m_mirror.y() * m_mirror.z() < 0.; }
#endif // ENABLE_WORLD_COORDINATE
void set_mirror(const Vec3d& mirror);
void set_mirror(Axis axis, double mirror);
#if ENABLE_WORLD_COORDINATE
bool has_skew() const;
#else
void set_from_transform(const Transform3d& transform);
#endif // ENABLE_WORLD_COORDINATE
void reset();
#if ENABLE_WORLD_COORDINATE
void reset_offset() { set_offset(Vec3d::Zero()); }
void reset_rotation() { set_rotation(Vec3d::Zero()); }
void reset_scaling_factor() { set_scaling_factor(Vec3d::Ones()); }
void reset_mirror() { set_mirror(Vec3d::Ones()); }
void reset_skew();
const Transform3d& get_matrix() const { return m_matrix; }
Transform3d get_matrix_no_offset() const;
Transform3d get_matrix_no_scaling_factor() const;
void set_matrix(const Transform3d& transform) { m_matrix = transform; }
#else
const Transform3d& get_matrix(bool dont_translate = false, bool dont_rotate = false, bool dont_scale = false, bool dont_mirror = false) const;
#endif // ENABLE_WORLD_COORDINATE
Transformation operator * (const Transformation& other) const;
#if !ENABLE_WORLD_COORDINATE
// Find volume transformation, so that the chained (instance_trafo * volume_trafo) will be as close to identity
// as possible in least squares norm in regard to the 8 corners of bbox.
// Bounding box is expected to be centered around zero in all axes.
static Transformation volume_to_bed_transformation(const Transformation& instance_transformation, const BoundingBoxf3& bbox);
#endif // !ENABLE_WORLD_COORDINATE
private:
friend class cereal::access;
#if ENABLE_WORLD_COORDINATE
template<class Archive> void serialize(Archive& ar) { ar(m_matrix); }
explicit Transformation(int) {}
template <class Archive> static void load_and_construct(Archive& ar, cereal::construct<Transformation>& construct)
{
// Calling a private constructor with special "int" parameter to indicate that no construction is necessary.
construct(1);
ar(construct.ptr()->m_matrix);
}
#else
template<class Archive> void serialize(Archive& ar) { ar(m_offset, m_rotation, m_scaling_factor, m_mirror); }
explicit Transformation(int) : m_dirty(true) {}
template <class Archive> static void load_and_construct(Archive& ar, cereal::construct<Transformation>& construct)
@ -417,6 +530,7 @@ private:
construct(1);
ar(construct.ptr()->m_offset, construct.ptr()->m_rotation, construct.ptr()->m_scaling_factor, construct.ptr()->m_mirror);
}
#endif // ENABLE_WORLD_COORDINATE
};
// For parsing a transformation matrix from 3MF / AMF.

View File

@ -945,7 +945,11 @@ const BoundingBoxf3& ModelObject::raw_bounding_box() const
if (this->instances.empty())
throw Slic3r::InvalidArgument("Can't call raw_bounding_box() with no instances");
#if ENABLE_WORLD_COORDINATE
const Transform3d inst_matrix = this->instances.front()->get_transformation().get_matrix_no_offset();
#else
const Transform3d& inst_matrix = this->instances.front()->get_transformation().get_matrix(true);
#endif // ENABLE_WORLD_COORDINATE
for (const ModelVolume *v : this->volumes)
if (v->is_model_part())
m_raw_bounding_box.merge(v->mesh().transformed_bounding_box(inst_matrix * v->get_matrix()));
@ -957,9 +961,15 @@ const BoundingBoxf3& ModelObject::raw_bounding_box() const
BoundingBoxf3 ModelObject::instance_bounding_box(size_t instance_idx, bool dont_translate) const
{
BoundingBoxf3 bb;
#if ENABLE_WORLD_COORDINATE
const Transform3d inst_matrix = dont_translate ?
this->instances[instance_idx]->get_transformation().get_matrix_no_offset() :
this->instances[instance_idx]->get_transformation().get_matrix();
#else
const Transform3d& inst_matrix = this->instances[instance_idx]->get_transformation().get_matrix(dont_translate);
for (ModelVolume *v : this->volumes)
{
#endif // ENABLE_WORLD_COORDINATE
for (ModelVolume *v : this->volumes) {
if (v->is_model_part())
bb.merge(v->mesh().transformed_bounding_box(inst_matrix * v->get_matrix()));
}
@ -1368,9 +1378,12 @@ void ModelObject::split(ModelObjectPtrs* new_objects)
new_object->add_instance(*model_instance);
ModelVolume* new_vol = new_object->add_volume(*volume, std::move(mesh));
for (ModelInstance* model_instance : new_object->instances)
{
for (ModelInstance* model_instance : new_object->instances) {
#if ENABLE_WORLD_COORDINATE
Vec3d shift = model_instance->get_transformation().get_matrix_no_offset() * new_vol->get_offset();
#else
Vec3d shift = model_instance->get_transformation().get_matrix(true) * new_vol->get_offset();
#endif // ENABLE_WORLD_COORDINATE
model_instance->set_offset(model_instance->get_offset() + shift);
}
@ -1412,9 +1425,11 @@ void ModelObject::bake_xy_rotation_into_meshes(size_t instance_idx)
assert(instance_idx < this->instances.size());
const Geometry::Transformation reference_trafo = this->instances[instance_idx]->get_transformation();
#if !ENABLE_WORLD_COORDINATE
if (Geometry::is_rotation_ninety_degrees(reference_trafo.get_rotation()))
// nothing to do, scaling in the world coordinate space is possible in the representation of Geometry::Transformation.
return;
#endif // !ENABLE_WORLD_COORDINATE
bool left_handed = reference_trafo.is_left_handed();
bool has_mirrorring = ! reference_trafo.get_mirror().isApprox(Vec3d(1., 1., 1.));
@ -1432,7 +1447,17 @@ void ModelObject::bake_xy_rotation_into_meshes(size_t instance_idx)
// Adjust the meshes.
// Transformation to be applied to the meshes.
#if ENABLE_WORLD_COORDINATE
Geometry::Transformation reference_trafo_mod = reference_trafo;
reference_trafo_mod.reset_offset();
if (uniform_scaling)
reference_trafo_mod.reset_scaling_factor();
if (!has_mirrorring)
reference_trafo_mod.reset_mirror();
Eigen::Matrix3d mesh_trafo_3x3 = reference_trafo_mod.get_matrix().matrix().block<3, 3>(0, 0);
#else
Eigen::Matrix3d mesh_trafo_3x3 = reference_trafo.get_matrix(true, false, uniform_scaling, ! has_mirrorring).matrix().block<3, 3>(0, 0);
#endif // ENABLE_WORLD_COORDINATE
Transform3d volume_offset_correction = this->instances[instance_idx]->get_transformation().get_matrix().inverse() * reference_trafo.get_matrix();
for (ModelVolume *model_volume : this->volumes) {
const Geometry::Transformation volume_trafo = model_volume->get_transformation();
@ -1442,7 +1467,17 @@ void ModelObject::bake_xy_rotation_into_meshes(size_t instance_idx)
std::abs(volume_trafo.get_scaling_factor().x() - volume_trafo.get_scaling_factor().z()) < EPSILON;
double volume_new_scaling_factor = volume_uniform_scaling ? volume_trafo.get_scaling_factor().x() : 1.;
// Transform the mesh.
#if ENABLE_WORLD_COORDINATE
Geometry::Transformation volume_trafo_mod = volume_trafo;
volume_trafo_mod.reset_offset();
if (volume_uniform_scaling)
volume_trafo_mod.reset_scaling_factor();
if (!volume_has_mirrorring)
volume_trafo_mod.reset_mirror();
Eigen::Matrix3d volume_trafo_3x3 = volume_trafo_mod.get_matrix().matrix().block<3, 3>(0, 0);
#else
Matrix3d volume_trafo_3x3 = volume_trafo.get_matrix(true, false, volume_uniform_scaling, !volume_has_mirrorring).matrix().block<3, 3>(0, 0);
#endif // ENABLE_WORLD_COORDINATE
// Following method creates a new shared_ptr<TriangleMesh>
model_volume->transform_this_mesh(mesh_trafo_3x3 * volume_trafo_3x3, left_handed != volume_left_handed);
// Reset the rotation, scaling and mirroring.
@ -1489,7 +1524,11 @@ double ModelObject::get_instance_min_z(size_t instance_idx) const
double min_z = DBL_MAX;
const ModelInstance* inst = instances[instance_idx];
#if ENABLE_WORLD_COORDINATE
const Transform3d mi = inst->get_matrix_no_offset();
#else
const Transform3d& mi = inst->get_matrix(true);
#endif // ENABLE_WORLD_COORDINATE
for (const ModelVolume* v : volumes) {
if (!v->is_model_part())
@ -1510,7 +1549,11 @@ double ModelObject::get_instance_max_z(size_t instance_idx) const
double max_z = -DBL_MAX;
const ModelInstance* inst = instances[instance_idx];
#if ENABLE_WORLD_COORDINATE
const Transform3d mi = inst->get_matrix_no_offset();
#else
const Transform3d& mi = inst->get_matrix(true);
#endif // ENABLE_WORLD_COORDINATE
for (const ModelVolume* v : volumes) {
if (!v->is_model_part())
@ -1936,14 +1979,22 @@ void ModelVolume::convert_from_meters()
void ModelInstance::transform_mesh(TriangleMesh* mesh, bool dont_translate) const
{
#if ENABLE_WORLD_COORDINATE
mesh->transform(dont_translate ? get_matrix_no_offset() : get_matrix());
#else
mesh->transform(get_matrix(dont_translate));
#endif // ENABLE_WORLD_COORDINATE
}
BoundingBoxf3 ModelInstance::transform_mesh_bounding_box(const TriangleMesh& mesh, bool dont_translate) const
{
// Rotate around mesh origin.
TriangleMesh copy(mesh);
#if ENABLE_WORLD_COORDINATE
copy.transform(get_transformation().get_rotation_matrix());
#else
copy.transform(get_matrix(true, false, true, true));
#endif // ENABLE_WORLD_COORDINATE
BoundingBoxf3 bbox = copy.bounding_box();
if (!empty(bbox)) {
@ -1968,12 +2019,20 @@ BoundingBoxf3 ModelInstance::transform_mesh_bounding_box(const TriangleMesh& mes
BoundingBoxf3 ModelInstance::transform_bounding_box(const BoundingBoxf3 &bbox, bool dont_translate) const
{
#if ENABLE_WORLD_COORDINATE
return bbox.transformed(dont_translate ? get_matrix_no_offset() : get_matrix());
#else
return bbox.transformed(get_matrix(dont_translate));
#endif // ENABLE_WORLD_COORDINATE
}
Vec3d ModelInstance::transform_vector(const Vec3d& v, bool dont_translate) const
{
#if ENABLE_WORLD_COORDINATE
return dont_translate ? get_matrix_no_offset() * v : get_matrix() * v;
#else
return get_matrix(dont_translate) * v;
#endif // ENABLE_WORLD_COORDINATE
}
void ModelInstance::transform_polygon(Polygon* polygon) const

View File

@ -691,15 +691,26 @@ public:
const Geometry::Transformation& get_transformation() const { return m_transformation; }
void set_transformation(const Geometry::Transformation& transformation) { m_transformation = transformation; }
#if ENABLE_WORLD_COORDINATE
void set_transformation(const Transform3d& trafo) { m_transformation.set_matrix(trafo); }
Vec3d get_offset() const { return m_transformation.get_offset(); }
#else
void set_transformation(const Transform3d &trafo) { m_transformation.set_from_transform(trafo); }
const Vec3d& get_offset() const { return m_transformation.get_offset(); }
#endif // ENABLE_WORLD_COORDINATE
double get_offset(Axis axis) const { return m_transformation.get_offset(axis); }
void set_offset(const Vec3d& offset) { m_transformation.set_offset(offset); }
void set_offset(Axis axis, double offset) { m_transformation.set_offset(axis, offset); }
#if ENABLE_WORLD_COORDINATE
Vec3d get_rotation() const { return m_transformation.get_rotation(); }
#else
const Vec3d& get_rotation() const { return m_transformation.get_rotation(); }
#endif // ENABLE_WORLD_COORDINATE
double get_rotation(Axis axis) const { return m_transformation.get_rotation(axis); }
void set_rotation(const Vec3d& rotation) { m_transformation.set_rotation(rotation); }
@ -711,7 +722,11 @@ public:
void set_scaling_factor(const Vec3d& scaling_factor) { m_transformation.set_scaling_factor(scaling_factor); }
void set_scaling_factor(Axis axis, double scaling_factor) { m_transformation.set_scaling_factor(axis, scaling_factor); }
#if ENABLE_WORLD_COORDINATE
Vec3d get_mirror() const { return m_transformation.get_mirror(); }
#else
const Vec3d& get_mirror() const { return m_transformation.get_mirror(); }
#endif // ENABLE_WORLD_COORDINATE
double get_mirror(Axis axis) const { return m_transformation.get_mirror(axis); }
bool is_left_handed() const { return m_transformation.is_left_handed(); }
@ -720,7 +735,12 @@ public:
void convert_from_imperial_units();
void convert_from_meters();
#if ENABLE_WORLD_COORDINATE
const Transform3d& get_matrix() const { return m_transformation.get_matrix(); }
Transform3d get_matrix_no_offset() const { return m_transformation.get_matrix_no_offset(); }
#else
const Transform3d& get_matrix(bool dont_translate = false, bool dont_rotate = false, bool dont_scale = false, bool dont_mirror = false) const { return m_transformation.get_matrix(dont_translate, dont_rotate, dont_scale, dont_mirror); }
#endif // ENABLE_WORLD_COORDINATE
void set_new_unique_id() {
ObjectBase::set_new_unique_id();
@ -923,25 +943,41 @@ public:
const Geometry::Transformation& get_transformation() const { return m_transformation; }
void set_transformation(const Geometry::Transformation& transformation) { m_transformation = transformation; }
#if ENABLE_WORLD_COORDINATE
Vec3d get_offset() const { return m_transformation.get_offset(); }
#else
const Vec3d& get_offset() const { return m_transformation.get_offset(); }
#endif // ENABLE_WORLD_COORDINATE
double get_offset(Axis axis) const { return m_transformation.get_offset(axis); }
void set_offset(const Vec3d& offset) { m_transformation.set_offset(offset); }
void set_offset(Axis axis, double offset) { m_transformation.set_offset(axis, offset); }
#if ENABLE_WORLD_COORDINATE
Vec3d get_rotation() const { return m_transformation.get_rotation(); }
#else
const Vec3d& get_rotation() const { return m_transformation.get_rotation(); }
#endif // ENABLE_WORLD_COORDINATE
double get_rotation(Axis axis) const { return m_transformation.get_rotation(axis); }
void set_rotation(const Vec3d& rotation) { m_transformation.set_rotation(rotation); }
void set_rotation(Axis axis, double rotation) { m_transformation.set_rotation(axis, rotation); }
#if ENABLE_WORLD_COORDINATE
Vec3d get_scaling_factor() const { return m_transformation.get_scaling_factor(); }
#else
const Vec3d& get_scaling_factor() const { return m_transformation.get_scaling_factor(); }
#endif // ENABLE_WORLD_COORDINATE
double get_scaling_factor(Axis axis) const { return m_transformation.get_scaling_factor(axis); }
void set_scaling_factor(const Vec3d& scaling_factor) { m_transformation.set_scaling_factor(scaling_factor); }
void set_scaling_factor(Axis axis, double scaling_factor) { m_transformation.set_scaling_factor(axis, scaling_factor); }
#if ENABLE_WORLD_COORDINATE
Vec3d get_mirror() const { return m_transformation.get_mirror(); }
#else
const Vec3d& get_mirror() const { return m_transformation.get_mirror(); }
#endif // ENABLE_WORLD_COORDINATE
double get_mirror(Axis axis) const { return m_transformation.get_mirror(axis); }
bool is_left_handed() const { return m_transformation.is_left_handed(); }
@ -959,7 +995,12 @@ public:
// To be called on an external polygon. It does not translate the polygon, only rotates and scales.
void transform_polygon(Polygon* polygon) const;
#if ENABLE_WORLD_COORDINATE
const Transform3d& get_matrix() const { return m_transformation.get_matrix(); }
Transform3d get_matrix_no_offset() const { return m_transformation.get_matrix_no_offset(); }
#else
const Transform3d& get_matrix(bool dont_translate = false, bool dont_rotate = false, bool dont_scale = false, bool dont_mirror = false) const { return m_transformation.get_matrix(dont_translate, dont_rotate, dont_scale, dont_mirror); }
#endif // ENABLE_WORLD_COORDINATE
bool is_printable() const { return object->printable && printable && (print_volume_state == ModelInstancePVS_Inside); }

View File

@ -545,6 +545,10 @@ namespace cereal {
template<class Archive> void load(Archive& archive, Slic3r::Matrix2f &m) { archive.loadBinary((char*)m.data(), sizeof(float) * 4); }
template<class Archive> void save(Archive& archive, Slic3r::Matrix2f &m) { archive.saveBinary((char*)m.data(), sizeof(float) * 4); }
#if ENABLE_WORLD_COORDINATE
template<class Archive> void load(Archive& archive, Slic3r::Transform3d& m) { archive.loadBinary((char*)m.data(), sizeof(double) * 16); }
template<class Archive> void save(Archive& archive, const Slic3r::Transform3d& m) { archive.saveBinary((char*)m.data(), sizeof(double) * 16); }
#endif // ENABLE_WORLD_COORDINATE
}
// To be able to use Vec<> and Mat<> in range based for loops:

View File

@ -790,8 +790,13 @@ void update_volume_bboxes(
if (it != volumes_old.end() && it->volume_id == model_volume->id())
layer_range.volumes.emplace_back(*it);
} else
#if ENABLE_WORLD_COORDINATE
layer_range.volumes.push_back({ model_volume->id(),
transformed_its_bbox2d(model_volume->mesh().its, trafo_for_bbox(object_trafo, model_volume->get_matrix()), offset) });
#else
layer_range.volumes.push_back({ model_volume->id(),
transformed_its_bbox2d(model_volume->mesh().its, trafo_for_bbox(object_trafo, model_volume->get_matrix(false)), offset) });
#endif // ENABLE_WORLD_COORDINATE
}
} else {
std::vector<std::vector<PrintObjectRegions::VolumeExtents>> volumes_old;
@ -823,7 +828,11 @@ void update_volume_bboxes(
layer_range.volumes.emplace_back(*it);
}
} else {
#if ENABLE_WORLD_COORDINATE
transformed_its_bboxes_in_z_ranges(model_volume->mesh().its, trafo_for_bbox(object_trafo, model_volume->get_matrix()), ranges, bboxes, offset);
#else
transformed_its_bboxes_in_z_ranges(model_volume->mesh().its, trafo_for_bbox(object_trafo, model_volume->get_matrix(false)), ranges, bboxes, offset);
#endif // ENABLE_WORLD_COORDINATE
for (PrintObjectRegions::LayerRangeRegions &layer_range : layer_ranges)
if (auto &bbox = bboxes[&layer_range - layer_ranges.data()]; bbox.second)
layer_range.volumes.push_back({ model_volume->id(), bbox.first });

View File

@ -69,6 +69,8 @@
#define ENABLE_SHOW_TOOLPATHS_COG (1 && ENABLE_2_5_0_ALPHA1)
// Enable recalculating toolpaths when switching to/from volumetric rate visualization
#define ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC (1 && ENABLE_2_5_0_ALPHA1)
// Enable editing volumes transformation in world coordinates and instances in local coordinates
#define ENABLE_WORLD_COORDINATE (1 && ENABLE_2_5_0_ALPHA1)
// Enable modified camera control using mouse
#define ENABLE_NEW_CAMERA_MOVEMENTS (1 && ENABLE_2_5_0_ALPHA1)
// Enable modified rectangle selection

View File

@ -85,6 +85,8 @@ set(SLIC3R_GUI_SOURCES
GUI/GUI_App.hpp
GUI/GUI_Utils.cpp
GUI/GUI_Utils.hpp
GUI/GUI_Geometry.cpp
GUI/GUI_Geometry.hpp
GUI/I18N.cpp
GUI/I18N.hpp
GUI/MainFrame.cpp
@ -129,6 +131,8 @@ set(SLIC3R_GUI_SOURCES
GUI/2DBed.hpp
GUI/3DBed.cpp
GUI/3DBed.hpp
GUI/CoordAxes.cpp
GUI/CoordAxes.hpp
GUI/Camera.cpp
GUI/Camera.hpp
GUI/wxExtensions.cpp

View File

@ -102,6 +102,7 @@ const float* GeometryBuffer::get_vertices_data() const
}
#endif // !ENABLE_LEGACY_OPENGL_REMOVAL
#if !ENABLE_WORLD_COORDINATE
const float Bed3D::Axes::DefaultStemRadius = 0.5f;
const float Bed3D::Axes::DefaultStemLength = 25.0f;
const float Bed3D::Axes::DefaultTipRadius = 2.5f * Bed3D::Axes::DefaultStemRadius;
@ -179,6 +180,7 @@ void Bed3D::Axes::render()
glsafe(::glDisable(GL_DEPTH_TEST));
}
#endif // !ENABLE_WORLD_COORDINATE
bool Bed3D::set_shape(const Pointfs& bed_shape, const double max_print_height, const std::string& custom_texture, const std::string& custom_model, bool force_as_custom)
{
@ -341,7 +343,11 @@ BoundingBoxf3 Bed3D::calc_extended_bounding_box() const
out.max.z() = 0.0;
// extend to contain axes
out.merge(m_axes.get_origin() + m_axes.get_total_length() * Vec3d::Ones());
#if ENABLE_WORLD_COORDINATE
out.merge(out.min + Vec3d(-m_axes.get_tip_radius(), -m_axes.get_tip_radius(), out.max.z()));
#else
out.merge(out.min + Vec3d(-Axes::DefaultTipRadius, -Axes::DefaultTipRadius, out.max.z()));
#endif // ENABLE_WORLD_COORDINATE
// extend to contain model, if any
BoundingBoxf3 model_bb = m_model.get_bounding_box();
if (model_bb.defined) {
@ -539,7 +545,15 @@ std::tuple<Bed3D::Type, std::string, std::string> Bed3D::detect_type(const Point
void Bed3D::render_axes()
{
if (m_build_volume.valid())
#if ENABLE_WORLD_COORDINATE
#if ENABLE_GL_SHADERS_ATTRIBUTES
m_axes.render(Transform3d::Identity(), 0.25f);
#else
m_axes.render(0.25f);
#endif // ENABLE_GL_SHADERS_ATTRIBUTES
#else
m_axes.render();
#endif // ENABLE_WORLD_COORDINATE
}
#if ENABLE_GL_SHADERS_ATTRIBUTES

View File

@ -3,7 +3,11 @@
#include "GLTexture.hpp"
#include "3DScene.hpp"
#if ENABLE_WORLD_COORDINATE
#include "CoordAxes.hpp"
#else
#include "GLModel.hpp"
#endif // ENABLE_WORLD_COORDINATE
#include "libslic3r/BuildVolume.hpp"
#if ENABLE_LEGACY_OPENGL_REMOVAL
@ -44,6 +48,7 @@ public:
class Bed3D
{
#if !ENABLE_WORLD_COORDINATE
class Axes
{
public:
@ -67,6 +72,7 @@ class Bed3D
float get_total_length() const { return m_stem_length + DefaultTipLength; }
void render();
};
#endif // !ENABLE_WORLD_COORDINATE
public:
enum class Type : unsigned char
@ -107,7 +113,11 @@ private:
#if !ENABLE_LEGACY_OPENGL_REMOVAL
unsigned int m_vbo_id{ 0 };
#endif // !ENABLE_LEGACY_OPENGL_REMOVAL
#if ENABLE_WORLD_COORDINATE
CoordAxes m_axes;
#else
Axes m_axes;
#endif // ENABLE_WORLD_COORDINATE
float m_scale_factor{ 1.0f };

View File

@ -432,14 +432,23 @@ public:
const Geometry::Transformation& get_instance_transformation() const { return m_instance_transformation; }
void set_instance_transformation(const Geometry::Transformation& transformation) { m_instance_transformation = transformation; set_bounding_boxes_as_dirty(); }
#if ENABLE_WORLD_COORDINATE
void set_instance_transformation(const Transform3d& transform) { m_instance_transformation.set_matrix(transform); set_bounding_boxes_as_dirty(); }
Vec3d get_instance_offset() const { return m_instance_transformation.get_offset(); }
#else
const Vec3d& get_instance_offset() const { return m_instance_transformation.get_offset(); }
#endif // ENABLE_WORLD_COORDINATE
double get_instance_offset(Axis axis) const { return m_instance_transformation.get_offset(axis); }
void set_instance_offset(const Vec3d& offset) { m_instance_transformation.set_offset(offset); set_bounding_boxes_as_dirty(); }
void set_instance_offset(Axis axis, double offset) { m_instance_transformation.set_offset(axis, offset); set_bounding_boxes_as_dirty(); }
#if ENABLE_WORLD_COORDINATE
Vec3d get_instance_rotation() const { return m_instance_transformation.get_rotation(); }
#else
const Vec3d& get_instance_rotation() const { return m_instance_transformation.get_rotation(); }
#endif // ENABLE_WORLD_COORDINATE
double get_instance_rotation(Axis axis) const { return m_instance_transformation.get_rotation(axis); }
void set_instance_rotation(const Vec3d& rotation) { m_instance_transformation.set_rotation(rotation); set_bounding_boxes_as_dirty(); }
@ -451,7 +460,11 @@ public:
void set_instance_scaling_factor(const Vec3d& scaling_factor) { m_instance_transformation.set_scaling_factor(scaling_factor); set_bounding_boxes_as_dirty(); }
void set_instance_scaling_factor(Axis axis, double scaling_factor) { m_instance_transformation.set_scaling_factor(axis, scaling_factor); set_bounding_boxes_as_dirty(); }
#if ENABLE_WORLD_COORDINATE
Vec3d get_instance_mirror() const { return m_instance_transformation.get_mirror(); }
#else
const Vec3d& get_instance_mirror() const { return m_instance_transformation.get_mirror(); }
#endif // ENABLE_WORLD_COORDINATE
double get_instance_mirror(Axis axis) const { return m_instance_transformation.get_mirror(axis); }
void set_instance_mirror(const Vec3d& mirror) { m_instance_transformation.set_mirror(mirror); set_bounding_boxes_as_dirty(); }
@ -459,26 +472,43 @@ public:
const Geometry::Transformation& get_volume_transformation() const { return m_volume_transformation; }
void set_volume_transformation(const Geometry::Transformation& transformation) { m_volume_transformation = transformation; set_bounding_boxes_as_dirty(); }
#if ENABLE_WORLD_COORDINATE
void set_volume_transformation(const Transform3d& transform) { m_volume_transformation.set_matrix(transform); set_bounding_boxes_as_dirty(); }
Vec3d get_volume_offset() const { return m_volume_transformation.get_offset(); }
#else
const Vec3d& get_volume_offset() const { return m_volume_transformation.get_offset(); }
#endif // ENABLE_WORLD_COORDINATE
double get_volume_offset(Axis axis) const { return m_volume_transformation.get_offset(axis); }
void set_volume_offset(const Vec3d& offset) { m_volume_transformation.set_offset(offset); set_bounding_boxes_as_dirty(); }
void set_volume_offset(Axis axis, double offset) { m_volume_transformation.set_offset(axis, offset); set_bounding_boxes_as_dirty(); }
#if ENABLE_WORLD_COORDINATE
Vec3d get_volume_rotation() const { return m_volume_transformation.get_rotation(); }
#else
const Vec3d& get_volume_rotation() const { return m_volume_transformation.get_rotation(); }
#endif // ENABLE_WORLD_COORDINATE
double get_volume_rotation(Axis axis) const { return m_volume_transformation.get_rotation(axis); }
void set_volume_rotation(const Vec3d& rotation) { m_volume_transformation.set_rotation(rotation); set_bounding_boxes_as_dirty(); }
void set_volume_rotation(Axis axis, double rotation) { m_volume_transformation.set_rotation(axis, rotation); set_bounding_boxes_as_dirty(); }
#if ENABLE_WORLD_COORDINATE
Vec3d get_volume_scaling_factor() const { return m_volume_transformation.get_scaling_factor(); }
#else
const Vec3d& get_volume_scaling_factor() const { return m_volume_transformation.get_scaling_factor(); }
#endif // ENABLE_WORLD_COORDINATE
double get_volume_scaling_factor(Axis axis) const { return m_volume_transformation.get_scaling_factor(axis); }
void set_volume_scaling_factor(const Vec3d& scaling_factor) { m_volume_transformation.set_scaling_factor(scaling_factor); set_bounding_boxes_as_dirty(); }
void set_volume_scaling_factor(Axis axis, double scaling_factor) { m_volume_transformation.set_scaling_factor(axis, scaling_factor); set_bounding_boxes_as_dirty(); }
#if ENABLE_WORLD_COORDINATE
Vec3d get_volume_mirror() const { return m_volume_transformation.get_mirror(); }
#else
const Vec3d& get_volume_mirror() const { return m_volume_transformation.get_mirror(); }
#endif // ENABLE_WORLD_COORDINATE
double get_volume_mirror(Axis axis) const { return m_volume_transformation.get_mirror(axis); }
void set_volume_mirror(const Vec3d& mirror) { m_volume_transformation.set_mirror(mirror); set_bounding_boxes_as_dirty(); }

View File

@ -0,0 +1,104 @@
#include "libslic3r/libslic3r.h"
#include "CoordAxes.hpp"
#include "GUI_App.hpp"
#include "3DScene.hpp"
#if ENABLE_GL_SHADERS_ATTRIBUTES
#include "Plater.hpp"
#include "Camera.hpp"
#endif // ENABLE_GL_SHADERS_ATTRIBUTES
#include <GL/glew.h>
#if ENABLE_WORLD_COORDINATE
namespace Slic3r {
namespace GUI {
const float CoordAxes::DefaultStemRadius = 0.5f;
const float CoordAxes::DefaultStemLength = 25.0f;
const float CoordAxes::DefaultTipRadius = 2.5f * CoordAxes::DefaultStemRadius;
const float CoordAxes::DefaultTipLength = 5.0f;
#if ENABLE_GL_SHADERS_ATTRIBUTES
void CoordAxes::render(const Transform3d& trafo, float emission_factor)
#else
void CoordAxes::render(float emission_factor)
#endif // ENABLE_GL_SHADERS_ATTRIBUTES
{
#if ENABLE_GL_SHADERS_ATTRIBUTES
auto render_axis = [this](GLShaderProgram& shader, const Transform3d& transform) {
const Camera& camera = wxGetApp().plater()->get_camera();
const Transform3d matrix = camera.get_view_matrix() * transform;
shader.set_uniform("view_model_matrix", matrix);
shader.set_uniform("projection_matrix", camera.get_projection_matrix());
shader.set_uniform("normal_matrix", (Matrix3d)matrix.matrix().block(0, 0, 3, 3).inverse().transpose());
m_arrow.render();
#else
auto render_axis = [this](const Transform3f& transform) {
glsafe(::glPushMatrix());
glsafe(::glMultMatrixf(transform.data()));
m_arrow.render();
glsafe(::glPopMatrix());
#endif // ENABLE_GL_SHADERS_ATTRIBUTES
};
if (!m_arrow.is_initialized())
m_arrow.init_from(stilized_arrow(16, m_tip_radius, m_tip_length, m_stem_radius, m_stem_length));
GLShaderProgram* curr_shader = wxGetApp().get_current_shader();
GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light");
if (shader == nullptr)
return;
if (curr_shader != nullptr)
curr_shader->stop_using();
shader->start_using();
shader->set_uniform("emission_factor", emission_factor);
// x axis
#if ENABLE_LEGACY_OPENGL_REMOVAL
m_arrow.set_color(ColorRGBA::X());
#else
m_arrow.set_color(-1, ColorRGBA::X());
#endif // ENABLE_LEGACY_OPENGL_REMOVAL
#if ENABLE_GL_SHADERS_ATTRIBUTES
render_axis(*shader, trafo * Geometry::assemble_transform(m_origin, { 0.0, 0.5 * M_PI, 0.0 }));
#else
render_axis(Geometry::assemble_transform(m_origin, { 0.0, 0.5 * M_PI, 0.0 }).cast<float>());
#endif // ENABLE_GL_SHADERS_ATTRIBUTES
// y axis
#if ENABLE_LEGACY_OPENGL_REMOVAL
m_arrow.set_color(ColorRGBA::Y());
#else
m_arrow.set_color(-1, ColorRGBA::Y());
#endif // ENABLE_LEGACY_OPENGL_REMOVAL
#if ENABLE_GL_SHADERS_ATTRIBUTES
render_axis(*shader, trafo * Geometry::assemble_transform(m_origin, { -0.5 * M_PI, 0.0, 0.0 }));
#else
render_axis(Geometry::assemble_transform(m_origin, { -0.5 * M_PI, 0.0, 0.0 }).cast<float>());
#endif // ENABLE_GL_SHADERS_ATTRIBUTES
// z axis
#if ENABLE_LEGACY_OPENGL_REMOVAL
m_arrow.set_color(ColorRGBA::Z());
#else
m_arrow.set_color(-1, ColorRGBA::Z());
#endif // ENABLE_LEGACY_OPENGL_REMOVAL
#if ENABLE_GL_SHADERS_ATTRIBUTES
render_axis(*shader, trafo * Geometry::assemble_transform(m_origin));
#else
render_axis(Geometry::assemble_transform(m_origin).cast<float>());
#endif // ENABLE_GL_SHADERS_ATTRIBUTES
shader->stop_using();
if (curr_shader != nullptr)
curr_shader->start_using();
}
} // GUI
} // Slic3r
#endif // ENABLE_WORLD_COORDINATE

View File

@ -0,0 +1,64 @@
#ifndef slic3r_CoordAxes_hpp_
#define slic3r_CoordAxes_hpp_
#if ENABLE_WORLD_COORDINATE
#include "GLModel.hpp"
namespace Slic3r {
namespace GUI {
class CoordAxes
{
public:
static const float DefaultStemRadius;
static const float DefaultStemLength;
static const float DefaultTipRadius;
static const float DefaultTipLength;
private:
Vec3d m_origin{ Vec3d::Zero() };
float m_stem_radius{ DefaultStemRadius };
float m_stem_length{ DefaultStemLength };
float m_tip_radius{ DefaultTipRadius };
float m_tip_length{ DefaultTipLength };
GLModel m_arrow;
public:
const Vec3d& get_origin() const { return m_origin; }
void set_origin(const Vec3d& origin) { m_origin = origin; }
void set_stem_radius(float radius) {
m_stem_radius = radius;
m_arrow.reset();
}
void set_stem_length(float length) {
m_stem_length = length;
m_arrow.reset();
}
void set_tip_radius(float radius) {
m_tip_radius = radius;
m_arrow.reset();
}
void set_tip_length(float length) {
m_tip_length = length;
m_arrow.reset();
}
float get_stem_radius() const { return m_stem_radius; }
float get_stem_length() const { return m_stem_length; }
float get_tip_radius() const { return m_tip_radius; }
float get_tip_length() const { return m_tip_length; }
float get_total_length() const { return m_stem_length + m_tip_length; }
#if ENABLE_GL_SHADERS_ATTRIBUTES
void render(const Transform3d& trafo, float emission_factor = 0.0f);
#else
void render(float emission_factor = 0.0f);
#endif // ENABLE_GL_SHADERS_ATTRIBUTES
};
} // GUI
} // Slic3r
#endif // ENABLE_WORLD_COORDINATE
#endif // slic3r_CoordAxes_hpp_

View File

@ -1101,6 +1101,9 @@ wxDEFINE_EVENT(EVT_GLCANVAS_QUESTION_MARK, SimpleEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_INCREASE_INSTANCES, Event<int>);
wxDEFINE_EVENT(EVT_GLCANVAS_INSTANCE_MOVED, SimpleEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_INSTANCE_ROTATED, SimpleEvent);
#if ENABLE_WORLD_COORDINATE
wxDEFINE_EVENT(EVT_GLCANVAS_RESET_SKEW, SimpleEvent);
#endif // ENABLE_WORLD_COORDINATE
wxDEFINE_EVENT(EVT_GLCANVAS_INSTANCE_SCALED, SimpleEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_FORCE_UPDATE, SimpleEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_WIPETOWER_MOVED, Vec3dEvent);
@ -2914,7 +2917,13 @@ void GLCanvas3D::on_key(wxKeyEvent& evt)
else
displacement = multiplier * direction;
#if ENABLE_WORLD_COORDINATE
TransformationType trafo_type;
trafo_type.set_relative();
m_selection.translate(displacement, trafo_type);
#else
m_selection.translate(displacement);
#endif // ENABLE_WORLD_COORDINATE
m_dirty = true;
}
);
@ -3579,7 +3588,13 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
}
}
#if ENABLE_WORLD_COORDINATE
TransformationType trafo_type;
trafo_type.set_relative();
m_selection.translate(cur_pos - m_mouse.drag.start_position_3D, trafo_type);
#else
m_selection.translate(cur_pos - m_mouse.drag.start_position_3D);
#endif // ENABLE_WORLD_COORDINATE
if (current_printer_technology() == ptFFF && fff_print()->config().complete_objects)
update_sequential_clearance();
wxGetApp().obj_manipul()->set_dirty();
@ -3825,9 +3840,17 @@ void GLCanvas3D::do_move(const std::string& snapshot_type)
ModelObject* model_object = m_model->objects[object_idx];
if (model_object != nullptr) {
if (selection_mode == Selection::Instance)
#if ENABLE_WORLD_COORDINATE
model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
#else
model_object->instances[instance_idx]->set_offset(v->get_instance_offset());
#endif // ENABLE_WORLD_COORDINATE
else if (selection_mode == Selection::Volume)
#if ENABLE_WORLD_COORDINATE
model_object->volumes[volume_idx]->set_transformation(v->get_volume_transformation());
#else
model_object->volumes[volume_idx]->set_offset(v->get_volume_offset());
#endif // ENABLE_WORLD_COORDINATE
object_moved = true;
model_object->invalidate_bounding_box();
@ -3907,8 +3930,8 @@ void GLCanvas3D::do_rotate(const std::string& snapshot_type)
int object_idx = v->object_idx();
if (object_idx == 1000) { // the wipe tower
#endif // ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
Vec3d offset = v->get_volume_offset();
post_event(Vec3dEvent(EVT_GLCANVAS_WIPETOWER_ROTATED, Vec3d(offset(0), offset(1), v->get_volume_rotation()(2))));
const Vec3d offset = v->get_volume_offset();
post_event(Vec3dEvent(EVT_GLCANVAS_WIPETOWER_ROTATED, Vec3d(offset.x(), offset.y(), v->get_volume_rotation().z())));
}
#if ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
int object_idx = v->object_idx();
@ -3916,8 +3939,8 @@ void GLCanvas3D::do_rotate(const std::string& snapshot_type)
if (object_idx < 0 || (int)m_model->objects.size() <= object_idx)
continue;
int instance_idx = v->instance_idx();
int volume_idx = v->volume_idx();
const int instance_idx = v->instance_idx();
const int volume_idx = v->volume_idx();
done.insert(std::pair<int, int>(object_idx, instance_idx));
@ -3925,12 +3948,20 @@ void GLCanvas3D::do_rotate(const std::string& snapshot_type)
ModelObject* model_object = m_model->objects[object_idx];
if (model_object != nullptr) {
if (selection_mode == Selection::Instance) {
#if ENABLE_WORLD_COORDINATE
model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
#else
model_object->instances[instance_idx]->set_rotation(v->get_instance_rotation());
model_object->instances[instance_idx]->set_offset(v->get_instance_offset());
#endif // ENABLE_WORLD_COORDINATE
}
else if (selection_mode == Selection::Volume) {
#if ENABLE_WORLD_COORDINATE
model_object->volumes[volume_idx]->set_transformation(v->get_volume_transformation());
#else
model_object->volumes[volume_idx]->set_rotation(v->get_volume_rotation());
model_object->volumes[volume_idx]->set_offset(v->get_volume_offset());
#endif // ENABLE_WORLD_COORDINATE
}
model_object->invalidate_bounding_box();
}
@ -3980,12 +4011,12 @@ void GLCanvas3D::do_scale(const std::string& snapshot_type)
Selection::EMode selection_mode = m_selection.get_mode();
for (const GLVolume* v : m_volumes.volumes) {
int object_idx = v->object_idx();
const int object_idx = v->object_idx();
if (object_idx < 0 || (int)m_model->objects.size() <= object_idx)
continue;
int instance_idx = v->instance_idx();
int volume_idx = v->volume_idx();
const int instance_idx = v->instance_idx();
const int volume_idx = v->volume_idx();
done.insert(std::pair<int, int>(object_idx, instance_idx));
@ -3993,13 +4024,22 @@ void GLCanvas3D::do_scale(const std::string& snapshot_type)
ModelObject* model_object = m_model->objects[object_idx];
if (model_object != nullptr) {
if (selection_mode == Selection::Instance) {
#if ENABLE_WORLD_COORDINATE
model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
#else
model_object->instances[instance_idx]->set_scaling_factor(v->get_instance_scaling_factor());
model_object->instances[instance_idx]->set_offset(v->get_instance_offset());
#endif // ENABLE_WORLD_COORDINATE
}
else if (selection_mode == Selection::Volume) {
#if ENABLE_WORLD_COORDINATE
model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
model_object->volumes[volume_idx]->set_transformation(v->get_volume_transformation());
#else
model_object->instances[instance_idx]->set_offset(v->get_instance_offset());
model_object->volumes[volume_idx]->set_scaling_factor(v->get_volume_scaling_factor());
model_object->volumes[volume_idx]->set_offset(v->get_volume_offset());
#endif // ENABLE_WORLD_COORDINATE
}
model_object->invalidate_bounding_box();
}
@ -4008,10 +4048,10 @@ void GLCanvas3D::do_scale(const std::string& snapshot_type)
// 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);
const 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);
const Vec3d shift(0.0, 0.0, -shift_z);
m_selection.translate(i.first, i.second, shift);
m->translate_instance(i.second, shift);
}
@ -4061,9 +4101,17 @@ void GLCanvas3D::do_mirror(const std::string& snapshot_type)
ModelObject* model_object = m_model->objects[object_idx];
if (model_object != nullptr) {
if (selection_mode == Selection::Instance)
#if ENABLE_WORLD_COORDINATE
model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
#else
model_object->instances[instance_idx]->set_mirror(v->get_instance_mirror());
#endif // ENABLE_WORLD_COORDINATE
else if (selection_mode == Selection::Volume)
#if ENABLE_WORLD_COORDINATE
model_object->volumes[volume_idx]->set_transformation(v->get_volume_transformation());
#else
model_object->volumes[volume_idx]->set_mirror(v->get_volume_mirror());
#endif // ENABLE_WORLD_COORDINATE
model_object->invalidate_bounding_box();
}
@ -4087,6 +4135,44 @@ void GLCanvas3D::do_mirror(const std::string& snapshot_type)
m_dirty = true;
}
#if ENABLE_WORLD_COORDINATE
void GLCanvas3D::do_reset_skew(const std::string& snapshot_type)
{
if (m_model == nullptr)
return;
if (!snapshot_type.empty())
wxGetApp().plater()->take_snapshot(_(snapshot_type));
std::set<std::pair<int, int>> done; // keeps track of modified instances
const Selection::IndicesList& idxs = m_selection.get_volume_idxs();
for (unsigned int id : idxs) {
const GLVolume* v = m_volumes.volumes[id];
int object_idx = v->object_idx();
if (object_idx < 0 || (int)m_model->objects.size() <= object_idx)
continue;
int instance_idx = v->instance_idx();
int volume_idx = v->volume_idx();
done.insert(std::pair<int, int>(object_idx, instance_idx));
ModelObject* model_object = m_model->objects[object_idx];
if (model_object != nullptr) {
model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
model_object->volumes[volume_idx]->set_transformation(v->get_volume_transformation());
model_object->invalidate_bounding_box();
}
}
post_event(SimpleEvent(EVT_GLCANVAS_RESET_SKEW));
m_dirty = true;
}
#endif // ENABLE_WORLD_COORDINATE
void GLCanvas3D::update_gizmos_on_off_state()
{
set_as_dirty();

View File

@ -156,6 +156,9 @@ wxDECLARE_EVENT(EVT_GLCANVAS_INSTANCE_MOVED, SimpleEvent);
wxDECLARE_EVENT(EVT_GLCANVAS_FORCE_UPDATE, SimpleEvent);
wxDECLARE_EVENT(EVT_GLCANVAS_WIPETOWER_MOVED, Vec3dEvent);
wxDECLARE_EVENT(EVT_GLCANVAS_INSTANCE_ROTATED, SimpleEvent);
#if ENABLE_WORLD_COORDINATE
wxDECLARE_EVENT(EVT_GLCANVAS_RESET_SKEW, SimpleEvent);
#endif // ENABLE_WORLD_COORDINATE
wxDECLARE_EVENT(EVT_GLCANVAS_INSTANCE_SCALED, SimpleEvent);
wxDECLARE_EVENT(EVT_GLCANVAS_WIPETOWER_ROTATED, Vec3dEvent);
wxDECLARE_EVENT(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, Event<bool>);
@ -739,7 +742,11 @@ public:
void update_volumes_colors_by_extruder();
#if ENABLE_WORLD_COORDINATE
bool is_dragging() const { return m_gizmos.is_dragging() || (m_moving && !m_mouse.scene_position.isApprox(m_mouse.drag.start_position_3D)); }
#else
bool is_dragging() const { return m_gizmos.is_dragging() || m_moving; }
#endif // ENABLE_WORLD_COORDINATE
void render();
// printable_only == false -> render also non printable volumes as grayed
@ -807,6 +814,9 @@ public:
void do_rotate(const std::string& snapshot_type);
void do_scale(const std::string& snapshot_type);
void do_mirror(const std::string& snapshot_type);
#if ENABLE_WORLD_COORDINATE
void do_reset_skew(const std::string& snapshot_type);
#endif // ENABLE_WORLD_COORDINATE
void update_gizmos_on_off_state();
void reset_all_gizmos() { m_gizmos.reset_all_states(); }

View File

@ -0,0 +1,9 @@
#include "libslic3r/libslic3r.h"
#include "GUI_Geometry.hpp"
namespace Slic3r {
namespace GUI {
} // namespace Slic3r
} // namespace GUI

View File

@ -0,0 +1,81 @@
#ifndef slic3r_GUI_Geometry_hpp_
#define slic3r_GUI_Geometry_hpp_
namespace Slic3r {
namespace GUI {
#if ENABLE_WORLD_COORDINATE
enum class ECoordinatesType : unsigned char
{
World,
Instance,
Local
};
class TransformationType
{
public:
enum Enum {
// Transforming in a world coordinate system
World = 0,
// Transforming in a instance coordinate system
Instance = 1,
// Transforming in a local coordinate system
Local = 2,
// Absolute transformations, allowed in local coordinate system only.
Absolute = 0,
// Relative transformations, allowed in both local and world coordinate system.
Relative = 4,
// 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 = 8,
World_Relative_Joint = World | Relative | Joint,
World_Relative_Independent = World | Relative | Independent,
Instance_Absolute_Joint = Instance | Absolute | Joint,
Instance_Absolute_Independent = Instance | Absolute | Independent,
Instance_Relative_Joint = Instance | Relative | Joint,
Instance_Relative_Independent = Instance | 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(Instance); this->remove(Local); }
void set_instance() { this->remove(Local); this->add(Instance); }
void set_local() { this->remove(Instance); 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(Instance) && !this->has(Local); }
bool instance() const { return this->has(Instance); }
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;
};
#endif // ENABLE_WORLD_COORDINATE
} // namespace Slic3r
} // namespace GUI
#endif // slic3r_GUI_Geometry_hpp_

View File

@ -1530,9 +1530,13 @@ void ObjectList::load_modifier(const wxArrayString& input_files, ModelObject& mo
const BoundingBoxf3 instance_bb = model_object.instance_bounding_box(instance_idx);
// First (any) GLVolume of the selected instance. They all share the same instance matrix.
const GLVolume* v = selection.get_volume(*selection.get_volume_idxs().begin());
const GLVolume* v = selection.get_first_volume();
const Geometry::Transformation inst_transform = v->get_instance_transformation();
#if ENABLE_WORLD_COORDINATE
const Transform3d inv_inst_transform = inst_transform.get_matrix_no_offset().inverse();
#else
const Transform3d inv_inst_transform = inst_transform.get_matrix(true).inverse();
#endif // ENABLE_WORLD_COORDINATE
const Vec3d instance_offset = v->get_instance_offset();
for (size_t i = 0; i < input_files.size(); ++i) {
@ -1580,9 +1584,15 @@ void ObjectList::load_modifier(const wxArrayString& input_files, ModelObject& mo
new_volume->source.mesh_offset = model.objects.front()->volumes.front()->source.mesh_offset;
if (from_galery) {
#if ENABLE_WORLD_COORDINATE
// Transform the new modifier to be aligned with the print bed.
new_volume->set_transformation(v->get_instance_transformation().get_matrix_no_offset().inverse());
const BoundingBoxf3 mesh_bb = new_volume->mesh().bounding_box();
#else
// Transform the new modifier to be aligned with the print bed.
const BoundingBoxf3 mesh_bb = new_volume->mesh().bounding_box();
new_volume->set_transformation(Geometry::Transformation::volume_to_bed_transformation(inst_transform, mesh_bb));
#endif // ENABLE_WORLD_COORDINATE
// Set the modifier position.
// Translate the new modifier to be pickable: move to the left front corner of the instance's bounding box, lift to print bed.
const Vec3d offset = Vec3d(instance_bb.max.x(), instance_bb.min.y(), instance_bb.min.z()) + 0.5 * mesh_bb.size() - instance_offset;
@ -1650,17 +1660,27 @@ void ObjectList::load_generic_subobject(const std::string& type_name, const Mode
ModelVolume *new_volume = model_object.add_volume(std::move(mesh), type);
// First (any) GLVolume of the selected instance. They all share the same instance matrix.
const GLVolume* v = selection.get_volume(*selection.get_volume_idxs().begin());
const GLVolume* v = selection.get_first_volume();
#if ENABLE_WORLD_COORDINATE
// Transform the new modifier to be aligned with the print bed.
new_volume->set_transformation(v->get_instance_transformation().get_matrix_no_offset().inverse());
const BoundingBoxf3 mesh_bb = new_volume->mesh().bounding_box();
#else
// Transform the new modifier to be aligned with the print bed.
const BoundingBoxf3 mesh_bb = new_volume->mesh().bounding_box();
new_volume->set_transformation(Geometry::Transformation::volume_to_bed_transformation(v->get_instance_transformation(), mesh_bb));
#endif // ENABLE_WORLD_COORDINATE
// Set the modifier position.
auto offset = (type_name == "Slab") ?
// Slab: Lift to print bed
Vec3d(0., 0., 0.5 * mesh_bb.size().z() + instance_bb.min.z() - v->get_instance_offset().z()) :
// Translate the new modifier to be pickable: move to the left front corner of the instance's bounding box, lift to print bed.
Vec3d(instance_bb.max.x(), instance_bb.min.y(), instance_bb.min.z()) + 0.5 * mesh_bb.size() - v->get_instance_offset();
#if ENABLE_WORLD_COORDINATE
new_volume->set_offset(v->get_instance_transformation().get_matrix_no_offset().inverse() * offset);
#else
new_volume->set_offset(v->get_instance_transformation().get_matrix(true).inverse() * offset);
#endif // ENABLE_WORLD_COORDINATE
const wxString name = _L("Generic") + "-" + _(type_name);
new_volume->name = into_u8(name);
@ -2545,7 +2565,13 @@ void ObjectList::part_selection_changed()
Sidebar& panel = wxGetApp().sidebar();
panel.Freeze();
#if ENABLE_WORLD_COORDINATE
const ManipulationEditor* const editor = wxGetApp().obj_manipul()->get_focused_editor();
const std::string opt_key = (editor != nullptr) ? editor->get_full_opt_name() : "";
wxGetApp().plater()->canvas3D()->handle_sidebar_focus_event(opt_key, !opt_key.empty());
#else
wxGetApp().plater()->canvas3D()->handle_sidebar_focus_event("", false);
#endif // ENABLE_WORLD_COORDINATE
wxGetApp().obj_manipul() ->UpdateAndShow(update_and_show_manipulations);
wxGetApp().obj_settings()->UpdateAndShow(update_and_show_settings);
wxGetApp().obj_layers() ->UpdateAndShow(update_and_show_layers);
@ -3263,8 +3289,12 @@ void ObjectList::update_selections()
return;
sels.Add(m_objects_model->GetItemById(selection.get_object_idx()));
}
#if ENABLE_WORLD_COORDINATE
else if (selection.is_single_volume_or_modifier()) {
#else
else if (selection.is_single_volume() || selection.is_any_modifier()) {
const auto gl_vol = selection.get_volume(*selection.get_volume_idxs().begin());
#endif // ENABLE_WORLD_COORDINATE
const auto gl_vol = selection.get_first_volume();
if (m_objects_model->GetVolumeIdByItem(m_objects_model->GetParent(item)) == gl_vol->volume_idx())
return;
}

View File

@ -52,10 +52,17 @@ static choice_ctrl* create_word_local_combo(wxWindow *parent)
temp->SetFont(Slic3r::GUI::wxGetApp().normal_font());
if (!wxOSX) temp->SetBackgroundStyle(wxBG_STYLE_PAINT);
#if ENABLE_WORLD_COORDINATE
temp->Append(ObjectManipulation::coordinate_type_str(ECoordinatesType::World));
temp->Append(ObjectManipulation::coordinate_type_str(ECoordinatesType::Instance));
temp->Append(ObjectManipulation::coordinate_type_str(ECoordinatesType::Local));
temp->Select((int)ECoordinatesType::World);
#else
temp->Append(_L("World coordinates"));
temp->Append(_L("Local coordinates"));
temp->SetSelection(0);
temp->SetValue(temp->GetString(0));
#endif // ENABLE_WORLD_COORDINATE
temp->SetToolTip(_L("Select coordinate space, in which the transformation will be performed."));
return temp;
@ -81,8 +88,14 @@ void msw_rescale_word_local_combo(choice_ctrl* combo)
// Set rescaled size
combo->SetSize(size);
#if ENABLE_WORLD_COORDINATE
combo->Append(ObjectManipulation::coordinate_type_str(ECoordinatesType::World));
combo->Append(ObjectManipulation::coordinate_type_str(ECoordinatesType::Instance));
combo->Append(ObjectManipulation::coordinate_type_str(ECoordinatesType::Local));
#else
combo->Append(_L("World coordinates"));
combo->Append(_L("Local coordinates"));
#endif // ENABLE_WORLD_COORDINATE
combo->SetValue(selection);
#else
@ -101,6 +114,7 @@ static void set_font_and_background_style(wxWindow* win, const wxFont& font)
static const wxString axes_color_text[] = { "#990000", "#009900", "#000099" };
static const wxString axes_color_back[] = { "#f5dcdc", "#dcf5dc", "#dcdcf5" };
ObjectManipulation::ObjectManipulation(wxWindow* parent) :
OG_Settings(parent, true)
{
@ -157,7 +171,11 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
// Add world local combobox
m_word_local_combo = create_word_local_combo(parent);
m_word_local_combo->Bind(wxEVT_COMBOBOX, ([this](wxCommandEvent& evt) {
#if ENABLE_WORLD_COORDINATE
this->set_coordinates_type(evt.GetString());
#else
this->set_world_coordinates(evt.GetSelection() != 1);
#endif // ENABLE_WORLD_COORDINATE
}), m_word_local_combo->GetId());
// Small trick to correct layouting in different view_mode :
@ -264,8 +282,12 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
Selection& selection = canvas->get_selection();
#if ENABLE_WORLD_COORDINATE
if (selection.is_single_volume_or_modifier()) {
#else
if (selection.is_single_volume() || selection.is_single_modifier()) {
GLVolume* volume = const_cast<GLVolume*>(selection.get_volume(*selection.get_volume_idxs().begin()));
#endif // ENABLE_WORLD_COORDINATE
GLVolume* volume = const_cast<GLVolume*>(selection.get_first_volume());
volume->set_volume_mirror(axis, -volume->get_volume_mirror(axis));
}
else if (selection.is_single_full_instance()) {
@ -278,7 +300,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
return;
// Update mirroring at the GLVolumes.
selection.synchronize_unselected_instances(Selection::SYNC_ROTATION_GENERAL);
selection.synchronize_unselected_instances(Selection::SyncRotationType::GENERAL);
selection.synchronize_unselected_volumes();
// Copy mirroring values from GLVolumes into Model (ModelInstance / ModelVolume), trigger background processing.
canvas->do_mirror(L("Set Mirror"));
@ -327,28 +349,60 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
Selection& selection = canvas->get_selection();
if (selection.is_single_volume() || selection.is_single_modifier()) {
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
const Geometry::Transformation& instance_trafo = volume->get_instance_transformation();
const Vec3d diff = m_cache.position - instance_trafo.get_matrix(true).inverse() * Vec3d(0., 0., get_volume_min_z(*volume));
#if ENABLE_WORLD_COORDINATE
if (selection.is_single_volume_or_modifier()) {
const GLVolume* volume = selection.get_first_volume();
const double min_z = get_volume_min_z(*volume);
if (!is_world_coordinates()) {
const Vec3d diff = m_cache.position - volume->get_instance_transformation().get_matrix_no_offset().inverse() * (min_z * Vec3d::UnitZ());
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Drop to bed"));
change_position_value(0, diff.x());
change_position_value(1, diff.y());
change_position_value(2, diff.z());
}
else {
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Drop to bed"));
change_position_value(2, m_cache.position.z() - min_z);
}
#else
if (selection.is_single_volume() || selection.is_single_modifier()) {
const GLVolume* volume = selection.get_first_volume();
const Vec3d diff = m_cache.position - volume->get_instance_transformation().get_matrix(true).inverse() * (get_volume_min_z(*volume) * Vec3d::UnitZ());
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Drop to bed"));
change_position_value(0, diff.x());
change_position_value(1, diff.y());
change_position_value(2, diff.z());
#endif // ENABLE_WORLD_COORDINATE
}
else if (selection.is_single_full_instance()) {
#if ENABLE_WORLD_COORDINATE
const double min_z = selection.get_scaled_instance_bounding_box().min.z();
if (!is_world_coordinates()) {
const GLVolume* volume = selection.get_first_volume();
const Vec3d diff = m_cache.position - volume->get_instance_transformation().get_matrix_no_offset().inverse() * (min_z * Vec3d::UnitZ());
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Drop to bed"));
change_position_value(0, diff.x());
change_position_value(1, diff.y());
change_position_value(2, diff.z());
}
else {
#else
const ModelObjectPtrs& objects = wxGetApp().model().objects;
const int idx = selection.get_object_idx();
if (0 <= idx && idx < static_cast<int>(objects.size())) {
const ModelObject* mo = wxGetApp().model().objects[idx];
const double min_z = mo->bounding_box().min.z();
if (std::abs(min_z) > SINKING_Z_THRESHOLD) {
#endif // ENABLE_WORLD_COORDINATE
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Drop to bed"));
change_position_value(2, m_cache.position.z() - min_z);
}
#if !ENABLE_WORLD_COORDINATE
}
#endif // !ENABLE_WORLD_COORDINATE
}
});
editors_grid_sizer->Add(m_drop_to_bed_button);
@ -365,21 +419,22 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
Selection& selection = canvas->get_selection();
if (selection.is_single_volume() || selection.is_single_modifier()) {
GLVolume* volume = const_cast<GLVolume*>(selection.get_volume(*selection.get_volume_idxs().begin()));
volume->set_volume_rotation(Vec3d::Zero());
}
#if ENABLE_WORLD_COORDINATE
if (selection.is_single_volume_or_modifier())
#else
if (selection.is_single_volume() || selection.is_single_modifier())
#endif // ENABLE_WORLD_COORDINATE
const_cast<GLVolume*>(selection.get_first_volume())->set_volume_rotation(Vec3d::Zero());
else if (selection.is_single_full_instance()) {
for (unsigned int idx : selection.get_volume_idxs()) {
GLVolume* volume = const_cast<GLVolume*>(selection.get_volume(idx));
volume->set_instance_rotation(Vec3d::Zero());
const_cast<GLVolume*>(selection.get_volume(idx))->set_instance_rotation(Vec3d::Zero());
}
}
else
return;
// Update rotation at the GLVolumes.
selection.synchronize_unselected_instances(Selection::SYNC_ROTATION_GENERAL);
selection.synchronize_unselected_instances(Selection::SyncRotationType::GENERAL);
selection.synchronize_unselected_volumes();
// Copy rotation values from GLVolumes into Model (ModelInstance / ModelVolume), trigger background processing.
canvas->do_rotate(L("Reset Rotation"));
@ -397,10 +452,28 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
m_reset_scale_button = new ScalableButton(parent, wxID_ANY, ScalableBitmap(parent, "undo"));
m_reset_scale_button->SetToolTip(_L("Reset scale"));
m_reset_scale_button->Bind(wxEVT_BUTTON, [this](wxCommandEvent& e) {
#if ENABLE_WORLD_COORDINATE
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
Selection& selection = canvas->get_selection();
if (selection.is_single_volume_or_modifier())
const_cast<GLVolume*>(selection.get_first_volume())->set_volume_scaling_factor(Vec3d::Ones());
else if (selection.is_single_full_instance()) {
for (unsigned int idx : selection.get_volume_idxs()) {
const_cast<GLVolume*>(selection.get_volume(idx))->set_instance_scaling_factor(Vec3d::Ones());
}
}
else
return;
canvas->do_scale(L("Reset scale"));
UpdateAndShow(true);
#else
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Reset scale"));
change_scale_value(0, 100.);
change_scale_value(1, 100.);
change_scale_value(2, 100.);
#endif // ENABLE_WORLD_COORDINATE
});
editors_grid_sizer->Add(m_reset_scale_button);
@ -411,6 +484,25 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
m_main_grid_sizer->Add(editors_grid_sizer, 1, wxEXPAND);
#if ENABLE_WORLD_COORDINATE
m_skew_label = new wxStaticText(parent, wxID_ANY, _L("Skew"));
m_main_grid_sizer->Add(m_skew_label, 1, wxEXPAND);
m_reset_skew_button = new ScalableButton(parent, wxID_ANY, ScalableBitmap(parent, "undo"));
m_reset_skew_button->SetToolTip(_L("Reset skew"));
m_reset_skew_button->Bind(wxEVT_BUTTON, [this](wxCommandEvent& e) {
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
Selection& selection = canvas->get_selection();
if (selection.is_single_full_instance() || selection.is_single_volume_or_modifier()) {
selection.setup_cache();
selection.reset_skew();
canvas->do_reset_skew(L("Reset skew"));
UpdateAndShow(true);
}
});
m_main_grid_sizer->Add(m_reset_skew_button);
#endif // ENABLE_WORLD_COORDINATE
m_check_inch = new wxCheckBox(parent, wxID_ANY, _L("Inches"));
m_check_inch->SetFont(wxGetApp().normal_font());
@ -444,7 +536,26 @@ void ObjectManipulation::Show(const bool show)
if (show) {
// Show the "World Coordinates" / "Local Coordintes" Combo in Advanced / Expert mode only.
#if ENABLE_WORLD_COORDINATE
const Selection& selection = wxGetApp().plater()->canvas3D()->get_selection();
bool show_world_local_combo = wxGetApp().get_mode() != comSimple && (selection.is_single_full_instance() || selection.is_single_volume_or_modifier());
if (selection.is_single_volume_or_modifier() && m_word_local_combo->GetCount() < 3) {
#ifdef __linux__
m_word_local_combo->Insert(coordinate_type_str(ECoordinatesType::Instance), 1);
#else
m_word_local_combo->Insert(coordinate_type_str(ECoordinatesType::Instance), wxNullBitmap, 1);
#endif // __linux__
m_word_local_combo->Select((int)ECoordinatesType::World);
this->set_coordinates_type(m_word_local_combo->GetString(m_word_local_combo->GetSelection()));
}
else if (selection.is_single_full_instance() && m_word_local_combo->GetCount() > 2) {
m_word_local_combo->Delete(1);
m_word_local_combo->Select((int)ECoordinatesType::World);
this->set_coordinates_type(m_word_local_combo->GetString(m_word_local_combo->GetSelection()));
}
#else
bool show_world_local_combo = wxGetApp().plater()->canvas3D()->get_selection().is_single_full_instance() && wxGetApp().get_mode() != comSimple;
#endif // ENABLE_WORLD_COORDINATE
m_word_local_combo->Show(show_world_local_combo);
m_empty_str->Show(!show_world_local_combo);
}
@ -489,8 +600,7 @@ void ObjectManipulation::update_ui_from_settings()
}
m_check_inch->SetValue(m_imperial_units);
if (m_use_colors != (wxGetApp().app_config->get("color_mapinulation_panel") == "1"))
{
if (m_use_colors != (wxGetApp().app_config->get("color_mapinulation_panel") == "1")) {
m_use_colors = wxGetApp().app_config->get("color_mapinulation_panel") == "1";
// update colors for edit-boxes
int axis_id = 0;
@ -522,13 +632,16 @@ void ObjectManipulation::update_settings_value(const Selection& selection)
m_new_rotate_label_string = L("Rotation");
m_new_scale_label_string = L("Scale factors");
#if !ENABLE_WORLD_COORDINATE
if (wxGetApp().get_mode() == comSimple)
m_world_coordinates = true;
#endif // !ENABLE_WORLD_COORDINATE
ObjectList* obj_list = wxGetApp().obj_list();
if (selection.is_single_full_instance()) {
// all volumes in the selection belongs to the same instance, any of them contains the needed instance data, so we take the first one
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
const GLVolume* volume = selection.get_first_volume();
#if !ENABLE_WORLD_COORDINATE
m_new_position = volume->get_instance_offset();
// Verify whether the instance rotation is multiples of 90 degrees, so that the scaling in world coordinates is possible.
@ -538,17 +651,30 @@ void ObjectManipulation::update_settings_value(const Selection& selection)
m_uniform_scale = true;
m_lock_bnt->SetLock(true);
}
#endif // !ENABLE_WORLD_COORDINATE
#if ENABLE_WORLD_COORDINATE
if (is_world_coordinates()) {
m_new_position = volume->get_instance_offset();
#else
if (m_world_coordinates) {
#endif // ENABLE_WORLD_COORDINATE
m_new_rotate_label_string = L("Rotate");
m_new_rotation = Vec3d::Zero();
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.;
m_new_scale = m_new_size.cwiseQuotient(selection.get_unscaled_instance_bounding_box().size()) * 100.0;
}
else {
m_new_rotation = volume->get_instance_rotation() * (180. / M_PI);
#if ENABLE_WORLD_COORDINATE
m_new_move_label_string = L("Translate");
m_new_rotate_label_string = L("Rotate");
m_new_position = Vec3d::Zero();
m_new_rotation = Vec3d::Zero();
#else
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_scale = volume->get_instance_scaling_factor() * 100.;
m_new_scale = volume->get_instance_scaling_factor() * 100.0;
}
m_new_enabled = true;
@ -557,19 +683,52 @@ void ObjectManipulation::update_settings_value(const Selection& selection)
const BoundingBoxf3& box = selection.get_bounding_box();
m_new_position = box.center();
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_rotate_label_string = L("Rotate");
m_new_scale_label_string = L("Scale");
m_new_enabled = true;
}
#if ENABLE_WORLD_COORDINATE
else if (selection.is_single_volume_or_modifier()) {
#else
else if (selection.is_single_modifier() || selection.is_single_volume()) {
#endif // ENABLE_WORLD_COORDINATE
// the selection contains a single volume
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
const GLVolume* volume = selection.get_first_volume();
#if ENABLE_WORLD_COORDINATE
if (is_world_coordinates()) {
const Geometry::Transformation trafo(volume->world_matrix());
const Vec3d& offset = trafo.get_offset();
m_new_position = offset;
m_new_rotate_label_string = L("Rotate");
m_new_rotation = Vec3d::Zero();
m_new_size = volume->transformed_convex_hull_bounding_box(trafo.get_matrix()).size();
m_new_scale = m_new_size.cwiseQuotient(volume->transformed_convex_hull_bounding_box(volume->get_instance_transformation().get_matrix() * volume->get_volume_transformation().get_matrix_no_scaling_factor()).size()) * 100.0;
}
else if (is_local_coordinates()) {
m_new_move_label_string = L("Translate");
m_new_rotate_label_string = L("Rotate");
m_new_position = Vec3d::Zero();
m_new_rotation = Vec3d::Zero();
m_new_scale = volume->get_volume_scaling_factor() * 100.0;
m_new_size = volume->get_volume_scaling_factor().cwiseProduct(volume->bounding_box().size());
}
else {
#endif // ENABLE_WORLD_COORDINATE
m_new_position = volume->get_volume_offset();
m_new_rotation = volume->get_volume_rotation() * (180. / M_PI);
m_new_scale = volume->get_volume_scaling_factor() * 100.;
m_new_rotate_label_string = L("Rotate");
m_new_rotation = Vec3d::Zero();
#if ENABLE_WORLD_COORDINATE
m_new_size = volume->transformed_convex_hull_bounding_box(volume->get_volume_transformation().get_matrix()).size();
m_new_scale = m_new_size.cwiseQuotient(volume->transformed_convex_hull_bounding_box(volume->get_volume_transformation().get_matrix_no_scaling_factor()).size()) * 100.0;
}
#else
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()));
#endif // ENABLE_WORLD_COORDINATE
m_new_enabled = true;
}
else if (obj_list->multiple_selection() || obj_list->is_selected(itInstanceRoot)) {
@ -635,15 +794,18 @@ void ObjectManipulation::update_if_dirty()
update(m_cache.rotation, m_cache.rotation_rounded, meRotation, m_new_rotation);
}
#if !ENABLE_WORLD_COORDINATE
if (selection.requires_uniform_scale()) {
m_lock_bnt->SetLock(true);
m_lock_bnt->SetToolTip(_L("You cannot use non-uniform scaling mode for multiple objects/parts selection"));
m_lock_bnt->disable();
}
else {
#endif // !ENABLE_WORLD_COORDINATE
m_lock_bnt->SetLock(m_uniform_scale);
m_lock_bnt->SetToolTip(wxEmptyString);
m_lock_bnt->enable();
#if !ENABLE_WORLD_COORDINATE
}
{
@ -651,6 +813,7 @@ void ObjectManipulation::update_if_dirty()
if (m_word_local_combo->GetSelection() != new_selection)
m_word_local_combo->SetSelection(new_selection);
}
#endif // !ENABLE_WORLD_COORDINATE
if (m_new_enabled)
m_og->enable();
@ -677,29 +840,75 @@ void ObjectManipulation::update_reset_buttons_visibility()
bool show_rotation = false;
bool show_scale = false;
bool show_drop_to_bed = false;
#if ENABLE_WORLD_COORDINATE
bool show_skew = false;
if (selection.is_single_full_instance() || selection.is_single_volume_or_modifier()) {
const double min_z = selection.is_single_full_instance() ? selection.get_scaled_instance_bounding_box().min.z() :
get_volume_min_z(*selection.get_first_volume());
show_drop_to_bed = std::abs(min_z) > EPSILON;
const GLVolume* volume = selection.get_first_volume();
Transform3d rotation = Transform3d::Identity();
Transform3d scale = Transform3d::Identity();
Geometry::Transformation skew;
#else
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_first_volume();
Vec3d rotation;
Vec3d scale;
double min_z = 0.;
double min_z = 0.0;
#endif // ENABLE_WORLD_COORDINATE
if (selection.is_single_full_instance()) {
#if ENABLE_WORLD_COORDINATE
const Geometry::Transformation& trafo = volume->get_instance_transformation();
rotation = trafo.get_rotation_matrix();
scale = trafo.get_scaling_factor_matrix();
const Selection::IndicesList& idxs = selection.get_volume_idxs();
for (unsigned int id : idxs) {
const Geometry::Transformation world_trafo(selection.get_volume(id)->world_matrix());
if (world_trafo.has_skew()) {
skew = world_trafo;
break;
}
}
#else
rotation = volume->get_instance_rotation();
scale = volume->get_instance_scaling_factor();
min_z = wxGetApp().model().objects[volume->composite_id.object_id]->bounding_box().min.z();
min_z = selection.get_scaled_instance_bounding_box().min.z();
#endif // ENABLE_WORLD_COORDINATE
}
else {
#if ENABLE_WORLD_COORDINATE
const Geometry::Transformation& trafo = volume->get_volume_transformation();
rotation = trafo.get_rotation_matrix();
scale = trafo.get_scaling_factor_matrix();
const Geometry::Transformation world_trafo(volume->world_matrix());
if (world_trafo.has_skew())
skew = world_trafo;
#else
rotation = volume->get_volume_rotation();
scale = volume->get_volume_scaling_factor();
min_z = get_volume_min_z(*volume);
#endif // ENABLE_WORLD_COORDINATE
}
#if ENABLE_WORLD_COORDINATE
show_rotation = !rotation.isApprox(Transform3d::Identity());
show_scale = !scale.isApprox(Transform3d::Identity());
show_skew = skew.has_skew();
#else
show_rotation = !rotation.isApprox(Vec3d::Zero());
show_scale = !scale.isApprox(Vec3d::Ones());
show_drop_to_bed = std::abs(min_z) > SINKING_Z_THRESHOLD;
#endif // ENABLE_WORLD_COORDINATE
}
#if ENABLE_WORLD_COORDINATE
wxGetApp().CallAfter([this, show_rotation, show_scale, show_drop_to_bed, show_skew] {
#else
wxGetApp().CallAfter([this, show_rotation, show_scale, show_drop_to_bed] {
#endif // ENABLE_WORLD_COORDINATE
// There is a case (under OSX), when this function is called after the Manipulation panel is hidden
// So, let check if Manipulation panel is still shown for this moment
if (!this->IsShown())
@ -707,6 +916,10 @@ void ObjectManipulation::update_reset_buttons_visibility()
m_reset_rotation_button->Show(show_rotation);
m_reset_scale_button->Show(show_scale);
m_drop_to_bed_button->Show(show_drop_to_bed);
#if ENABLE_WORLD_COORDINATE
m_reset_skew_button->Show(show_skew);
m_skew_label->Show(show_skew);
#endif // ENABLE_WORLD_COORDINATE
// Because of CallAfter we need to layout sidebar after Show/hide of reset buttons one more time
Sidebar& panel = wxGetApp().sidebar();
@ -726,9 +939,17 @@ void ObjectManipulation::update_mirror_buttons_visibility()
Selection& selection = canvas->get_selection();
std::array<MirrorButtonState, 3> new_states = {mbHidden, mbHidden, mbHidden};
#if ENABLE_WORLD_COORDINATE
if (is_local_coordinates()) {
#else
if (!m_world_coordinates) {
#endif // ENABLE_WORLD_COORDINATE
#if ENABLE_WORLD_COORDINATE
if (selection.is_single_full_instance() || selection.is_single_volume_or_modifier()) {
#else
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());
#endif // ENABLE_WORLD_COORDINATE
const GLVolume* volume = selection.get_first_volume();
Vec3d mirror;
if (selection.is_single_full_instance())
@ -792,6 +1013,19 @@ void ObjectManipulation::update_warning_icon_state(const MeshErrorsInfo& warning
m_fix_throught_netfab_bitmap->SetToolTip(tooltip);
}
#if ENABLE_WORLD_COORDINATE
wxString ObjectManipulation::coordinate_type_str(ECoordinatesType type)
{
switch (type)
{
case ECoordinatesType::World: { return _L("World coordinates"); }
case ECoordinatesType::Instance: { return _L("Instance coordinates"); }
case ECoordinatesType::Local: { return _L("Local coordinates"); }
default: { assert(false); return _L("Unknown"); }
}
}
#endif // ENABLE_WORLD_COORDINATE
void ObjectManipulation::reset_settings_value()
{
m_new_position = Vec3d::Zero();
@ -815,7 +1049,19 @@ void ObjectManipulation::change_position_value(int axis, double value)
auto canvas = wxGetApp().plater()->canvas3D();
Selection& selection = canvas->get_selection();
selection.setup_cache();
#if ENABLE_WORLD_COORDINATE
TransformationType trafo_type;
trafo_type.set_relative();
switch (get_coordinates_type())
{
case ECoordinatesType::Instance: { trafo_type.set_instance(); break; }
case ECoordinatesType::Local: { trafo_type.set_local(); break; }
default: { break; }
}
selection.translate(position - m_cache.position, trafo_type);
#else
selection.translate(position - m_cache.position, selection.requires_local_axes());
#endif // ENABLE_WORLD_COORDINATE
canvas->do_move(L("Set Position"));
m_cache.position = position;
@ -834,6 +1080,18 @@ void ObjectManipulation::change_rotation_value(int axis, double value)
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
Selection& selection = canvas->get_selection();
#if ENABLE_WORLD_COORDINATE
TransformationType transformation_type;
transformation_type.set_relative();
if (selection.is_single_full_instance())
transformation_type.set_independent();
if (is_local_coordinates())
transformation_type.set_local();
if (is_instance_coordinates())
transformation_type.set_instance();
#else
TransformationType transformation_type(TransformationType::World_Relative_Joint);
if (selection.is_single_full_instance() || selection.requires_local_axes())
transformation_type.set_independent();
@ -842,6 +1100,7 @@ void ObjectManipulation::change_rotation_value(int axis, double value)
// transformation_type.set_absolute();
transformation_type.set_local();
}
#endif // ENABLE_WORLD_COORDINATE
selection.setup_cache();
selection.rotate(
@ -887,8 +1146,12 @@ void ObjectManipulation::change_size_value(int axis, double value)
const Selection& selection = wxGetApp().plater()->canvas3D()->get_selection();
Vec3d ref_size = m_cache.size;
#if ENABLE_WORLD_COORDINATE
if (selection.is_single_volume_or_modifier()) {
#else
if (selection.is_single_volume() || selection.is_single_modifier()) {
const GLVolume* v = selection.get_volume(*selection.get_volume_idxs().begin());
#endif // ENABLE_WORLD_COORDINATE
const GLVolume* v = selection.get_first_volume();
const Vec3d local_size = size.cwiseQuotient(v->get_instance_scaling_factor());
const Vec3d local_ref_size = v->bounding_box().size().cwiseProduct(v->get_volume_scaling_factor());
const Vec3d local_change = local_size.cwiseQuotient(local_ref_size);
@ -897,11 +1160,19 @@ void ObjectManipulation::change_size_value(int axis, double value)
ref_size = Vec3d::Ones();
}
else if (selection.is_single_full_instance())
#if ENABLE_WORLD_COORDINATE
ref_size = is_world_coordinates() ?
#else
ref_size = m_world_coordinates ?
#endif // ENABLE_WORLD_COORDINATE
selection.get_unscaled_instance_bounding_box().size() :
wxGetApp().model().objects[selection.get_volume(*selection.get_volume_idxs().begin())->object_idx()]->raw_mesh_bounding_box().size();
wxGetApp().model().objects[selection.get_first_volume()->object_idx()]->raw_mesh_bounding_box().size();
#if ENABLE_WORLD_COORDINATE
this->do_size(axis, size.cwiseQuotient(ref_size));
#else
this->do_scale(axis, size.cwiseQuotient(ref_size));
#endif // ENABLE_WORLD_COORDINATE
m_cache.size = size;
m_cache.size_rounded(axis) = DBL_MAX;
@ -911,8 +1182,22 @@ void ObjectManipulation::change_size_value(int axis, double value)
void ObjectManipulation::do_scale(int axis, const Vec3d &scale) const
{
Selection& selection = wxGetApp().plater()->canvas3D()->get_selection();
#if !ENABLE_WORLD_COORDINATE
Vec3d scaling_factor = scale;
#endif // !ENABLE_WORLD_COORDINATE
#if ENABLE_WORLD_COORDINATE
TransformationType transformation_type;
if (is_local_coordinates())
transformation_type.set_local();
else if (is_instance_coordinates())
transformation_type.set_instance();
if (!selection.is_single_full_instance() && !selection.is_single_volume_or_modifier())
transformation_type.set_relative();
const Vec3d scaling_factor = m_uniform_scale ? scale(axis) * Vec3d::Ones() : scale;
#else
TransformationType transformation_type(TransformationType::World_Relative_Joint);
if (selection.is_single_full_instance()) {
transformation_type.set_absolute();
@ -922,12 +1207,31 @@ void ObjectManipulation::do_scale(int axis, const Vec3d &scale) const
if (m_uniform_scale || selection.requires_uniform_scale())
scaling_factor = scale(axis) * Vec3d::Ones();
#endif // ENABLE_WORLD_COORDINATE
selection.setup_cache();
selection.scale(scaling_factor, transformation_type);
wxGetApp().plater()->canvas3D()->do_scale(L("Set Scale"));
}
#if ENABLE_WORLD_COORDINATE
void ObjectManipulation::do_size(int axis, const Vec3d& scale) const
{
Selection& selection = wxGetApp().plater()->canvas3D()->get_selection();
TransformationType transformation_type;
if (is_local_coordinates())
transformation_type.set_local();
else if (is_instance_coordinates())
transformation_type.set_instance();
const Vec3d scaling_factor = m_uniform_scale ? scale(axis) * Vec3d::Ones() : scale;
selection.setup_cache();
selection.scale(scaling_factor, transformation_type);
wxGetApp().plater()->canvas3D()->do_scale(L("Set Size"));
}
#endif // ENABLE_WORLD_COORDINATE
void ObjectManipulation::on_change(const std::string& opt_key, int axis, double new_value)
{
if (!m_cache.is_valid())
@ -962,13 +1266,22 @@ void ObjectManipulation::on_change(const std::string& opt_key, int axis, double
}
}
void ObjectManipulation::set_uniform_scaling(const bool new_value)
void ObjectManipulation::set_uniform_scaling(const bool use_uniform_scale)
{
#if ENABLE_WORLD_COORDINATE
if (!use_uniform_scale)
// Recalculate cached values at this panel, refresh the screen.
this->UpdateAndShow(true);
m_uniform_scale = use_uniform_scale;
set_dirty();
#else
const Selection& selection = wxGetApp().plater()->canvas3D()->get_selection();
if (selection.is_single_full_instance() && m_world_coordinates && !new_value) {
if (selection.is_single_full_instance() && m_world_coordinates && !use_uniform_scale) {
// Verify whether the instance rotation is multiples of 90 degrees, so that the scaling in world coordinates is possible.
// all volumes in the selection belongs to the same instance, any of them contains the needed instance data, so we take the first one
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
const GLVolume* volume = selection.get_first_volume();
// Is the angle close to a multiple of 90 degrees?
if (!Geometry::is_rotation_ninety_degrees(volume->get_instance_rotation())) {
// Cannot apply scaling in the world coordinate system.
@ -994,9 +1307,29 @@ void ObjectManipulation::set_uniform_scaling(const bool new_value)
this->UpdateAndShow(true);
}
}
m_uniform_scale = new_value;
m_uniform_scale = use_uniform_scale;
#endif // ENABLE_WORLD_COORDINATE
}
#if ENABLE_WORLD_COORDINATE
void ObjectManipulation::set_coordinates_type(ECoordinatesType type)
{
if (wxGetApp().get_mode() == comSimple)
type = ECoordinatesType::World;
if (m_coordinates_type == type)
return;
m_coordinates_type = type;
this->UpdateAndShow(true);
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
canvas->get_gizmos_manager().update_data();
canvas->set_as_dirty();
canvas->request_extra_frame();
}
#endif // ENABLE_WORLD_COORDINATE
void ObjectManipulation::msw_rescale()
{
const int em = wxGetApp().em_unit();
@ -1014,6 +1347,9 @@ void ObjectManipulation::msw_rescale()
m_mirror_bitmap_hidden.msw_rescale();
m_reset_scale_button->msw_rescale();
m_reset_rotation_button->msw_rescale();
#if ENABLE_WORLD_COORDINATE
m_reset_skew_button->msw_rescale();
#endif /// ENABLE_WORLD_COORDINATE
m_drop_to_bed_button->msw_rescale();
m_lock_bnt->msw_rescale();
@ -1053,6 +1389,9 @@ void ObjectManipulation::sys_color_changed()
m_mirror_bitmap_hidden.msw_rescale();
m_reset_scale_button->msw_rescale();
m_reset_rotation_button->msw_rescale();
#if ENABLE_WORLD_COORDINATE
m_reset_skew_button->msw_rescale();
#endif // ENABLE_WORLD_COORDINATE
m_drop_to_bed_button->msw_rescale();
m_lock_bnt->msw_rescale();
@ -1060,6 +1399,19 @@ void ObjectManipulation::sys_color_changed()
m_mirror_buttons[id].first->msw_rescale();
}
#if ENABLE_WORLD_COORDINATE
void ObjectManipulation::set_coordinates_type(const wxString& type_string)
{
ECoordinatesType type = ECoordinatesType::World;
if (type_string == coordinate_type_str(ECoordinatesType::Instance))
type = ECoordinatesType::Instance;
else if (type_string == coordinate_type_str(ECoordinatesType::Local))
type = ECoordinatesType::Local;
this->set_coordinates_type(type);
}
#endif // ENABLE_WORLD_COORDINATE
static const char axes[] = { 'x', 'y', 'z' };
ManipulationEditor::ManipulationEditor(ObjectManipulation* parent,
const std::string& opt_key,
@ -1101,8 +1453,8 @@ ManipulationEditor::ManipulationEditor(ObjectManipulation* parent,
parent->set_focused_editor(nullptr);
#if ENABLE_OBJECT_MANIPULATOR_FOCUS
// if the widgets exchanging focus are both manipulator fields, call kill_focus
if (dynamic_cast<ManipulationEditor*>(e.GetEventObject()) != nullptr && dynamic_cast<ManipulationEditor*>(e.GetWindow()) != nullptr)
// if the widgets loosing focus is a manipulator field, call kill_focus
if (dynamic_cast<ManipulationEditor*>(e.GetEventObject()) != nullptr)
#else
if (!m_enter_pressed)
#endif // ENABLE_OBJECT_MANIPULATOR_FOCUS

View File

@ -5,6 +5,9 @@
#include "GUI_ObjectSettings.hpp"
#include "GUI_ObjectList.hpp"
#if ENABLE_WORLD_COORDINATE
#include "GUI_Geometry.hpp"
#endif // ENABLE_WORLD_COORDINATE
#include "libslic3r/Point.hpp"
#include <float.h>
@ -57,6 +60,10 @@ public:
void set_value(const wxString& new_value);
void kill_focus(ObjectManipulation *parent);
#if ENABLE_WORLD_COORDINATE
const std::string& get_full_opt_name() const { return m_full_opt_name; }
#endif // ENABLE_WORLD_COORDINATE
private:
double get_value();
};
@ -113,9 +120,12 @@ private:
wxStaticText* m_empty_str = nullptr;
// Non-owning pointers to the reset buttons, so we can hide and show them.
ScalableButton* m_reset_scale_button = nullptr;
ScalableButton* m_reset_rotation_button = nullptr;
ScalableButton* m_drop_to_bed_button = nullptr;
ScalableButton* m_reset_scale_button{ nullptr };
ScalableButton* m_reset_rotation_button{ nullptr };
#if ENABLE_WORLD_COORDINATE
ScalableButton* m_reset_skew_button{ nullptr };
#endif // ENABLE_WORLD_COORDINATE
ScalableButton* m_drop_to_bed_button{ nullptr };
wxCheckBox* m_check_inch {nullptr};
@ -144,22 +154,35 @@ private:
Vec3d m_new_size;
bool m_new_enabled {true};
bool m_uniform_scale {true};
#if ENABLE_WORLD_COORDINATE
ECoordinatesType m_coordinates_type{ ECoordinatesType::World };
#else
// Does the object manipulation panel work in World or Local coordinates?
bool m_world_coordinates = true;
#endif // ENABLE_WORLD_COORDINATE
LockButton* m_lock_bnt{ nullptr };
choice_ctrl* m_word_local_combo { nullptr };
ScalableBitmap m_manifold_warning_bmp;
wxStaticBitmap* m_fix_throught_netfab_bitmap;
#if ENABLE_WORLD_COORDINATE
// Currently focused editor (nullptr if none)
ManipulationEditor* m_focused_editor{ nullptr };
#else
#ifndef __APPLE__
// Currently focused editor (nullptr if none)
ManipulationEditor* m_focused_editor {nullptr};
#endif // __APPLE__
#endif // ENABLE_WORLD_COORDINATE
wxFlexGridSizer* m_main_grid_sizer;
wxFlexGridSizer* m_labels_grid_sizer;
#if ENABLE_WORLD_COORDINATE
wxStaticText* m_skew_label{ nullptr };
#endif // ENABLE_WORLD_COORDINATE
// sizers, used for msw_rescale
wxBoxSizer* m_word_local_combo_sizer;
std::vector<wxBoxSizer*> m_rescalable_sizers;
@ -180,11 +203,19 @@ public:
// Called from the App to update the UI if dirty.
void update_if_dirty();
void set_uniform_scaling(const bool uniform_scale);
void set_uniform_scaling(const bool use_uniform_scale);
bool get_uniform_scaling() const { return m_uniform_scale; }
#if ENABLE_WORLD_COORDINATE
void set_coordinates_type(ECoordinatesType type);
ECoordinatesType get_coordinates_type() const { return m_coordinates_type; }
bool is_world_coordinates() const { return m_coordinates_type == ECoordinatesType::World; }
bool is_instance_coordinates() const { return m_coordinates_type == ECoordinatesType::Instance; }
bool is_local_coordinates() const { return m_coordinates_type == ECoordinatesType::Local; }
#else
// Does the object manipulation panel work in World or Local coordinates?
void set_world_coordinates(const bool world_coordinates) { m_world_coordinates = world_coordinates; this->UpdateAndShow(true); }
bool get_world_coordinates() const { return m_world_coordinates; }
#endif // ENABLE_WORLD_COORDINATE
void reset_cache() { m_cache.reset(); }
#ifndef __APPLE__
@ -200,11 +231,23 @@ public:
void sys_color_changed();
void on_change(const std::string& opt_key, int axis, double new_value);
void set_focused_editor(ManipulationEditor* focused_editor) {
#if ENABLE_WORLD_COORDINATE
m_focused_editor = focused_editor;
#else
#ifndef __APPLE__
m_focused_editor = focused_editor;
#endif // __APPLE__
#endif // ENABLE_WORLD_COORDINATE
}
#if ENABLE_WORLD_COORDINATE
ManipulationEditor* get_focused_editor() { return m_focused_editor; }
#endif // ENABLE_WORLD_COORDINATE
#if ENABLE_WORLD_COORDINATE
static wxString coordinate_type_str(ECoordinatesType type);
#endif // ENABLE_WORLD_COORDINATE
private:
void reset_settings_value();
void update_settings_value(const Selection& selection);
@ -220,6 +263,11 @@ private:
void change_scale_value(int axis, double value);
void change_size_value(int axis, double value);
void do_scale(int axis, const Vec3d &scale) const;
#if ENABLE_WORLD_COORDINATE
void do_size(int axis, const Vec3d& scale) const;
void set_coordinates_type(const wxString& type_string);
#endif // ENABLE_WORLD_COORDINATE
};
}}

View File

@ -333,7 +333,11 @@ bool GLGizmoBase::use_grabbers(const wxMouseEvent &mouse_event) {
wxGetApp().obj_manipul()->set_dirty();
m_parent.set_as_dirty();
return true;
} else if (mouse_event.LeftUp() || is_leaving || is_dragging_finished) {
}
else if (mouse_event.LeftUp() || is_leaving || is_dragging_finished) {
#if ENABLE_WORLD_COORDINATE
do_stop_dragging(is_leaving);
#else
for (auto &grabber : m_grabbers) grabber.dragging = false;
m_dragging = false;
@ -356,12 +360,41 @@ bool GLGizmoBase::use_grabbers(const wxMouseEvent &mouse_event) {
m_parent.post_event(SimpleEvent(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED));
// updates camera target constraints
m_parent.refresh_camera_scene_box();
#endif // ENABLE_WORLD_COORDINATE
return true;
}
}
return false;
}
#if ENABLE_WORLD_COORDINATE
void GLGizmoBase::do_stop_dragging(bool perform_mouse_cleanup)
{
for (auto& grabber : m_grabbers) grabber.dragging = false;
m_dragging = false;
// NOTE: This should be part of GLCanvas3D
// Reset hover_id when leave window
if (perform_mouse_cleanup) m_parent.mouse_up_cleanup();
on_stop_dragging();
// There is prediction that after draggign, data are changed
// Data are updated twice also by canvas3D::reload_scene.
// Should be fixed.
m_parent.get_gizmos_manager().update_data();
wxGetApp().obj_manipul()->set_dirty();
// Let the plater know that the dragging finished, so a delayed
// refresh of the scene with the background processing data should
// be performed.
m_parent.post_event(SimpleEvent(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED));
// updates camera target constraints
m_parent.refresh_camera_scene_box();
}
#endif // ENABLE_WORLD_COORDINATE
std::string GLGizmoBase::format(float value, unsigned int decimals) const
{
return Slic3r::string_printf("%.*f", decimals, value);

View File

@ -227,6 +227,11 @@ protected:
/// <param name="mouse_event">Keep information about mouse click</param>
/// <returns>same as on_mouse</returns>
bool use_grabbers(const wxMouseEvent &mouse_event);
#if ENABLE_WORLD_COORDINATE
void do_stop_dragging(bool perform_mouse_cleanup);
#endif // ENABLE_WORLD_COORDINATE
private:
// Flag for dirty visible state of Gizmo
// When True then need new rendering

View File

@ -312,7 +312,7 @@ void GLGizmoCut::perform_cut(const Selection& selection)
wxCHECK_RET(instance_idx >= 0 && object_idx >= 0, "GLGizmoCut: Invalid object selection");
// m_cut_z is the distance from the bed. Subtract possible SLA elevation.
const GLVolume* first_glvolume = selection.get_volume(*selection.get_volume_idxs().begin());
const GLVolume* first_glvolume = selection.get_first_volume();
const double object_cut_z = m_cut_z - first_glvolume->get_sla_shift_z();
if (0.0 < object_cut_z && object_cut_z < m_max_z)
@ -365,7 +365,7 @@ BoundingBoxf3 GLGizmoCut::bounding_box() const
void GLGizmoCut::update_contours()
{
const Selection& selection = m_parent.get_selection();
const GLVolume* first_glvolume = selection.get_volume(*selection.get_volume_idxs().begin());
const GLVolume* first_glvolume = selection.get_first_volume();
const BoundingBoxf3& box = first_glvolume->transformed_convex_hull_bounding_box();
const ModelObject* model_object = wxGetApp().model().objects[selection.get_object_idx()];

View File

@ -341,7 +341,11 @@ void GLGizmoFdmSupports::select_facets_by_angle(float threshold_deg, bool block)
++mesh_id;
#if ENABLE_WORLD_COORDINATE
const Transform3d trafo_matrix = mi->get_matrix_no_offset() * mv->get_matrix_no_offset();
#else
const Transform3d trafo_matrix = mi->get_matrix(true) * mv->get_matrix(true);
#endif // ENABLE_WORLD_COORDINATE
Vec3f down = (trafo_matrix.inverse() * (-Vec3d::UnitZ())).cast<float>().normalized();
Vec3f limit = (trafo_matrix.inverse() * Vec3d(std::sin(threshold), 0, -std::cos(threshold))).cast<float>().normalized();

View File

@ -118,17 +118,17 @@ void GLGizmoFlatten::on_render()
glsafe(::glEnable(GL_BLEND));
if (selection.is_single_full_instance()) {
const Transform3d& m = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix();
const Transform3d& m = selection.get_first_volume()->get_instance_transformation().get_matrix();
#if ENABLE_GL_SHADERS_ATTRIBUTES
const Camera& camera = wxGetApp().plater()->get_camera();
const Transform3d view_model_matrix = camera.get_view_matrix() *
Geometry::assemble_transform(selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z() * Vec3d::UnitZ()) * m;
Geometry::assemble_transform(selection.get_first_volume()->get_sla_shift_z() * Vec3d::UnitZ()) * m;
shader->set_uniform("view_model_matrix", view_model_matrix);
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
#else
glsafe(::glPushMatrix());
glsafe(::glTranslatef(0.f, 0.f, selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z()));
glsafe(::glTranslatef(0.f, 0.f, selection.get_first_volume()->get_sla_shift_z()));
glsafe(::glMultMatrixd(m.data()));
#endif // ENABLE_GL_SHADERS_ATTRIBUTES
if (this->is_plane_update_necessary())
@ -172,17 +172,17 @@ void GLGizmoFlatten::on_render_for_picking()
glsafe(::glDisable(GL_BLEND));
if (selection.is_single_full_instance() && !wxGetKeyState(WXK_CONTROL)) {
const Transform3d& m = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix();
const Transform3d& m = selection.get_first_volume()->get_instance_transformation().get_matrix();
#if ENABLE_GL_SHADERS_ATTRIBUTES
const Camera& camera = wxGetApp().plater()->get_camera();
const Transform3d view_model_matrix = camera.get_view_matrix() *
Geometry::assemble_transform(selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z() * Vec3d::UnitZ()) * m;
Geometry::assemble_transform(selection.get_first_volume()->get_sla_shift_z() * Vec3d::UnitZ()) * m;
shader->set_uniform("view_model_matrix", view_model_matrix);
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
#else
glsafe(::glPushMatrix());
glsafe(::glTranslatef(0.f, 0.f, selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z()));
glsafe(::glTranslatef(0.f, 0.f, selection.get_first_volume()->get_sla_shift_z()));
glsafe(::glMultMatrixd(m.data()));
#endif // ENABLE_GL_SHADERS_ATTRIBUTES
if (this->is_plane_update_necessary())
@ -228,7 +228,11 @@ void GLGizmoFlatten::update_planes()
}
ch = ch.convex_hull_3d();
m_planes.clear();
#if ENABLE_WORLD_COORDINATE
const Transform3d inst_matrix = mo->instances.front()->get_matrix_no_offset();
#else
const Transform3d& inst_matrix = mo->instances.front()->get_matrix(true);
#endif // ENABLE_WORLD_COORDINATE
// Following constants are used for discarding too small polygons.
const float minimal_area = 5.f; // in square mm (world coordinates)

View File

@ -94,7 +94,7 @@ void GLGizmoHollow::on_render_for_picking()
{
const Selection& selection = m_parent.get_selection();
//#if ENABLE_RENDER_PICKING_PASS
// m_z_shift = selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z();
// m_z_shift = selection.get_first_volume()->get_sla_shift_z();
//#endif
glsafe(::glEnable(GL_DEPTH_TEST));
@ -117,12 +117,16 @@ void GLGizmoHollow::render_points(const Selection& selection, bool picking)
ScopeGuard guard([shader]() { if (shader) shader->stop_using(); });
#endif // ENABLE_LEGACY_OPENGL_REMOVAL
const GLVolume* vol = selection.get_volume(*selection.get_volume_idxs().begin());
const GLVolume* vol = selection.get_first_volume();
Geometry::Transformation trafo = vol->get_instance_transformation() * vol->get_volume_transformation();
#if ENABLE_GL_SHADERS_ATTRIBUTES
#if ENABLE_WORLD_COORDINATE
const Transform3d instance_scaling_matrix_inverse = vol->get_instance_transformation().get_scaling_factor_matrix().inverse();
#else
const Transform3d instance_scaling_matrix_inverse = vol->get_instance_transformation().get_matrix(true, true, false, true).inverse();
const Transform3d instance_matrix = Geometry::assemble_transform(m_c->selection_info()->get_sla_shift() * Vec3d::UnitZ()) * trafo.get_matrix();
#endif // ENABLE_WORLD_COORDINATE
const Transform3d instance_matrix = Geometry::translation_transform(m_c->selection_info()->get_sla_shift() * Vec3d::UnitZ()) * trafo.get_matrix();
const Camera& camera = wxGetApp().plater()->get_camera();
const Transform3d& view_matrix = camera.get_view_matrix();
@ -238,7 +242,7 @@ bool GLGizmoHollow::unproject_on_mesh(const Vec2d& mouse_pos, std::pair<Vec3f, V
const Camera& camera = wxGetApp().plater()->get_camera();
const Selection& selection = m_parent.get_selection();
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
const GLVolume* volume = selection.get_first_volume();
Geometry::Transformation trafo = volume->get_instance_transformation() * volume->get_volume_transformation();
trafo.set_offset(trafo.get_offset() + Vec3d(0., 0., m_c->selection_info()->get_sla_shift()));

View File

@ -2,6 +2,9 @@
#include "GLGizmoMove.hpp"
#include "slic3r/GUI/GLCanvas3D.hpp"
#include "slic3r/GUI/GUI_App.hpp"
#if ENABLE_WORLD_COORDINATE
#include "slic3r/GUI/GUI_ObjectManipulation.hpp"
#endif // ENABLE_WORLD_COORDINATE
#if ENABLE_GL_SHADERS_ATTRIBUTES
#include "slic3r/GUI/Plater.hpp"
#endif // ENABLE_GL_SHADERS_ATTRIBUTES
@ -21,18 +24,29 @@ GLGizmoMove3D::GLGizmoMove3D(GLCanvas3D& parent, const std::string& icon_filenam
std::string GLGizmoMove3D::get_tooltip() const
{
#if ENABLE_WORLD_COORDINATE
if (m_hover_id == 0)
return "X: " + format(m_displacement.x(), 2);
else if (m_hover_id == 1)
return "Y: " + format(m_displacement.y(), 2);
else if (m_hover_id == 2)
return "Z: " + format(m_displacement.z(), 2);
else
return "";
#else
const Selection& selection = m_parent.get_selection();
bool show_position = selection.is_single_full_instance();
const bool show_position = selection.is_single_full_instance();
const Vec3d& position = selection.get_bounding_box().center();
if (m_hover_id == 0 || m_grabbers[0].dragging)
return "X: " + format(show_position ? position(0) : m_displacement(0), 2);
return "X: " + format(show_position ? position.x() : m_displacement.x(), 2);
else if (m_hover_id == 1 || m_grabbers[1].dragging)
return "Y: " + format(show_position ? position(1) : m_displacement(1), 2);
return "Y: " + format(show_position ? position.y() : m_displacement.y(), 2);
else if (m_hover_id == 2 || m_grabbers[2].dragging)
return "Z: " + format(show_position ? position(2) : m_displacement(2), 2);
return "Z: " + format(show_position ? position.z() : m_displacement.z(), 2);
else
return "";
#endif // ENABLE_WORLD_COORDINATE
}
bool GLGizmoMove3D::on_mouse(const wxMouseEvent &mouse_event) {
@ -40,9 +54,7 @@ bool GLGizmoMove3D::on_mouse(const wxMouseEvent &mouse_event) {
}
void GLGizmoMove3D::data_changed() {
const Selection &selection = m_parent.get_selection();
bool is_wipe_tower = selection.is_wipe_tower();
m_grabbers[2].enabled = !is_wipe_tower;
m_grabbers[2].enabled = !m_parent.get_selection().is_wipe_tower();
}
bool GLGizmoMove3D::on_init()
@ -79,11 +91,29 @@ void GLGizmoMove3D::on_start_dragging()
assert(m_hover_id != -1);
m_displacement = Vec3d::Zero();
#if ENABLE_WORLD_COORDINATE
const Selection& selection = m_parent.get_selection();
const ECoordinatesType coordinates_type = wxGetApp().obj_manipul()->get_coordinates_type();
if (coordinates_type == ECoordinatesType::World)
m_starting_drag_position = m_center + m_grabbers[m_hover_id].center;
else if (coordinates_type == ECoordinatesType::Local && selection.is_single_volume_or_modifier()) {
const GLVolume& v = *selection.get_first_volume();
m_starting_drag_position = m_center + v.get_instance_transformation().get_rotation_matrix() * v.get_volume_transformation().get_rotation_matrix() * m_grabbers[m_hover_id].center;
}
else {
const GLVolume& v = *selection.get_first_volume();
m_starting_drag_position = m_center + v.get_instance_transformation().get_rotation_matrix() * m_grabbers[m_hover_id].center;
}
m_starting_box_center = m_center;
m_starting_box_bottom_center = m_center;
m_starting_box_bottom_center.z() = m_bounding_box.min.z();
#else
const BoundingBoxf3& box = m_parent.get_selection().get_bounding_box();
m_starting_drag_position = m_grabbers[m_hover_id].center;
m_starting_box_center = box.center();
m_starting_box_bottom_center = box.center();
m_starting_box_bottom_center(2) = box.min(2);
m_starting_box_bottom_center.z() = box.min.z();
#endif // ENABLE_WORLD_COORDINATE
}
void GLGizmoMove3D::on_stop_dragging()
@ -102,7 +132,19 @@ void GLGizmoMove3D::on_dragging(const UpdateData& data)
m_displacement.z() = calc_projection(data);
Selection &selection = m_parent.get_selection();
#if ENABLE_WORLD_COORDINATE
TransformationType trafo_type;
trafo_type.set_relative();
switch (wxGetApp().obj_manipul()->get_coordinates_type())
{
case ECoordinatesType::Instance: { trafo_type.set_instance(); break; }
case ECoordinatesType::Local: { trafo_type.set_local(); break; }
default: { break; }
}
selection.translate(m_displacement, trafo_type);
#else
selection.translate(m_displacement);
#endif // ENABLE_WORLD_COORDINATE
}
void GLGizmoMove3D::on_render()
@ -112,11 +154,39 @@ void GLGizmoMove3D::on_render()
m_cone.init_from(its_make_cone(1.0, 1.0, double(PI) / 18.0));
#endif // !ENABLE_GIZMO_GRABBER_REFACTOR
const Selection& selection = m_parent.get_selection();
glsafe(::glClear(GL_DEPTH_BUFFER_BIT));
glsafe(::glEnable(GL_DEPTH_TEST));
#if ENABLE_WORLD_COORDINATE
#if !ENABLE_GL_SHADERS_ATTRIBUTES
glsafe(::glPushMatrix());
#endif // !ENABLE_GL_SHADERS_ATTRIBUTES
calc_selection_box_and_center();
#if ENABLE_GL_SHADERS_ATTRIBUTES
const Transform3d base_matrix = local_transform(m_parent.get_selection());
for (int i = 0; i < 3; ++i) {
m_grabbers[i].matrix = base_matrix;
}
#else
transform_to_local(m_parent.get_selection());
#endif // ENABLE_GL_SHADERS_ATTRIBUTES
const Vec3d zero = Vec3d::Zero();
const Vec3d half_box_size = 0.5 * m_bounding_box.size();
// x axis
m_grabbers[0].center = { half_box_size.x() + Offset, 0.0, 0.0 };
m_grabbers[0].color = AXES_COLOR[0];
// y axis
m_grabbers[1].center = { 0.0, half_box_size.y() + Offset, 0.0 };
m_grabbers[1].color = AXES_COLOR[1];
// z axis
m_grabbers[2].center = { 0.0, 0.0, half_box_size.z() + Offset };
m_grabbers[2].color = AXES_COLOR[2];
#else
const Selection& selection = m_parent.get_selection();
const BoundingBoxf3& box = selection.get_bounding_box();
const Vec3d& center = box.center();
@ -131,14 +201,24 @@ void GLGizmoMove3D::on_render()
// z axis
m_grabbers[2].center = { center.x(), center.y(), box.max.z() + Offset };
m_grabbers[2].color = AXES_COLOR[2];
#endif // ENABLE_WORLD_COORDINATE
glsafe(::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f));
#if ENABLE_LEGACY_OPENGL_REMOVAL
#if ENABLE_WORLD_COORDINATE
auto render_grabber_connection = [this, &zero](unsigned int id) {
#else
auto render_grabber_connection = [this, &center](unsigned int id) {
#endif // ENABLE_WORLD_COORDINATE
if (m_grabbers[id].enabled) {
#if ENABLE_WORLD_COORDINATE
if (!m_grabber_connections[id].model.is_initialized() || !m_grabber_connections[id].old_center.isApprox(m_grabbers[id].center)) {
m_grabber_connections[id].old_center = m_grabbers[id].center;
#else
if (!m_grabber_connections[id].model.is_initialized() || !m_grabber_connections[id].old_center.isApprox(center)) {
m_grabber_connections[id].old_center = center;
#endif // ENABLE_WORLD_COORDINATE
m_grabber_connections[id].model.reset();
GLModel::Geometry init_data;
@ -148,7 +228,11 @@ void GLGizmoMove3D::on_render()
init_data.reserve_indices(2);
// vertices
#if ENABLE_WORLD_COORDINATE
init_data.add_vertex((Vec3f)zero.cast<float>());
#else
init_data.add_vertex((Vec3f)center.cast<float>());
#endif // ENABLE_WORLD_COORDINATE
init_data.add_vertex((Vec3f)m_grabbers[id].center.cast<float>());
// indices
@ -171,7 +255,11 @@ void GLGizmoMove3D::on_render()
#if ENABLE_GL_SHADERS_ATTRIBUTES
const Camera& camera = wxGetApp().plater()->get_camera();
#if ENABLE_WORLD_COORDINATE
shader->set_uniform("view_model_matrix", camera.get_view_matrix() * base_matrix);
#else
shader->set_uniform("view_model_matrix", camera.get_view_matrix());
#endif // ENABLE_WORLD_COORDINATE
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
#endif // ENABLE_GL_SHADERS_ATTRIBUTES
@ -183,7 +271,11 @@ void GLGizmoMove3D::on_render()
if (m_grabbers[i].enabled) {
glsafe(::glColor4fv(AXES_COLOR[i].data()));
::glBegin(GL_LINES);
#if ENABLE_WORLD_COORDINATE
::glVertex3dv(zero.data());
#else
::glVertex3dv(center.data());
#endif // ENABLE_WORLD_COORDINATE
::glVertex3dv(m_grabbers[i].center.data());
glsafe(::glEnd());
}
@ -196,6 +288,19 @@ void GLGizmoMove3D::on_render()
#endif // ENABLE_LEGACY_OPENGL_REMOVAL
// draw grabbers
#if ENABLE_WORLD_COORDINATE
render_grabbers(m_bounding_box);
#if !ENABLE_GIZMO_GRABBER_REFACTOR
for (unsigned int i = 0; i < 3; ++i) {
if (m_grabbers[i].enabled)
#if ENABLE_GL_SHADERS_ATTRIBUTES
render_grabber_extension((Axis)i, base_matrix, m_bounding_box, false);
#else
render_grabber_extension((Axis)i, m_bounding_box, false);
#endif // ENABLE_GL_SHADERS_ATTRIBUTES
}
#endif // !ENABLE_GIZMO_GRABBER_REFACTOR
#else
render_grabbers(box);
#if !ENABLE_GIZMO_GRABBER_REFACTOR
for (unsigned int i = 0; i < 3; ++i) {
@ -203,6 +308,7 @@ void GLGizmoMove3D::on_render()
render_grabber_extension((Axis)i, box, false);
}
#endif // !ENABLE_GIZMO_GRABBER_REFACTOR
#endif // ENABLE_WORLD_COORDINATE
}
else {
// draw axis
@ -213,7 +319,11 @@ void GLGizmoMove3D::on_render()
#if ENABLE_GL_SHADERS_ATTRIBUTES
const Camera& camera = wxGetApp().plater()->get_camera();
#if ENABLE_WORLD_COORDINATE
shader->set_uniform("view_model_matrix", camera.get_view_matrix()* base_matrix);
#else
shader->set_uniform("view_model_matrix", camera.get_view_matrix());
#endif // ENABLE_WORLD_COORDINATE
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
#endif // ENABLE_GL_SHADERS_ATTRIBUTES
@ -225,7 +335,11 @@ void GLGizmoMove3D::on_render()
#else
glsafe(::glColor4fv(AXES_COLOR[m_hover_id].data()));
::glBegin(GL_LINES);
#if ENABLE_WORLD_COORDINATE
::glVertex3dv(zero.data());
#else
::glVertex3dv(center.data());
#endif // ENABLE_WORLD_COORDINATE
::glVertex3dv(m_grabbers[m_hover_id].center.data());
glsafe(::glEnd());
@ -235,20 +349,65 @@ void GLGizmoMove3D::on_render()
shader->start_using();
shader->set_uniform("emission_factor", 0.1f);
// draw grabber
const float mean_size = (float)((box.size().x() + box.size().y() + box.size().z()) / 3.0);
#if ENABLE_WORLD_COORDINATE
const Vec3d box_size = m_bounding_box.size();
#else
const Vec3d box_size = box.size();
#endif // ENABLE_WORLD_COORDINATE
const float mean_size = (float)((box_size.x() + box_size.y() + box_size.z()) / 3.0);
m_grabbers[m_hover_id].render(true, mean_size);
shader->stop_using();
}
#if !ENABLE_GIZMO_GRABBER_REFACTOR
#if ENABLE_WORLD_COORDINATE
#if ENABLE_GL_SHADERS_ATTRIBUTES
render_grabber_extension((Axis)m_hover_id, base_matrix, m_bounding_box, false);
#else
render_grabber_extension((Axis)m_hover_id, m_bounding_box, false);
#endif // ENABLE_GL_SHADERS_ATTRIBUTES
#else
render_grabber_extension((Axis)m_hover_id, box, false);
#endif // ENABLE_WORLD_COORDINATE
#endif // !ENABLE_GIZMO_GRABBER_REFACTOR
}
#if ENABLE_WORLD_COORDINATE
#if !ENABLE_GL_SHADERS_ATTRIBUTES
glsafe(::glPopMatrix());
#endif // !ENABLE_GL_SHADERS_ATTRIBUTES
#endif // ENABLE_WORLD_COORDINATE
}
void GLGizmoMove3D::on_render_for_picking()
{
glsafe(::glDisable(GL_DEPTH_TEST));
#if ENABLE_WORLD_COORDINATE
#if ENABLE_GL_SHADERS_ATTRIBUTES
const Transform3d base_matrix = local_transform(m_parent.get_selection());
for (int i = 0; i < 3; ++i) {
m_grabbers[i].matrix = base_matrix;
}
#else
glsafe(::glPushMatrix());
transform_to_local(m_parent.get_selection());
#endif // ENABLE_GL_SHADERS_ATTRIBUTES
render_grabbers_for_picking(m_bounding_box);
#if ENABLE_GL_SHADERS_ATTRIBUTES
#if !ENABLE_GIZMO_GRABBER_REFACTOR
render_grabber_extension(X, base_matrix, m_bounding_box, true);
render_grabber_extension(Y, base_matrix, m_bounding_box, true);
render_grabber_extension(Z, base_matrix, m_bounding_box, true);
#endif // !ENABLE_GIZMO_GRABBER_REFACTOR
#else
#if !ENABLE_GIZMO_GRABBER_REFACTOR
render_grabber_extension(X, m_bounding_box, true);
render_grabber_extension(Y, m_bounding_box, true);
render_grabber_extension(Z, m_bounding_box, true);
#endif // !ENABLE_GIZMO_GRABBER_REFACTOR
glsafe(::glPopMatrix());
#endif // ENABLE_GL_SHADERS_ATTRIBUTES
#else
const BoundingBoxf3& box = m_parent.get_selection().get_bounding_box();
render_grabbers_for_picking(box);
#if !ENABLE_GIZMO_GRABBER_REFACTOR
@ -256,23 +415,24 @@ void GLGizmoMove3D::on_render_for_picking()
render_grabber_extension(Y, box, true);
render_grabber_extension(Z, box, true);
#endif // !ENABLE_GIZMO_GRABBER_REFACTOR
#endif // ENABLE_WORLD_COORDINATE
}
double GLGizmoMove3D::calc_projection(const UpdateData& data) const
{
double projection = 0.0;
Vec3d starting_vec = m_starting_drag_position - m_starting_box_center;
double len_starting_vec = starting_vec.norm();
const Vec3d starting_vec = m_starting_drag_position - m_starting_box_center;
const double len_starting_vec = starting_vec.norm();
if (len_starting_vec != 0.0) {
Vec3d mouse_dir = data.mouse_ray.unit_vector();
const Vec3d mouse_dir = data.mouse_ray.unit_vector();
// finds the intersection of the mouse ray with the plane parallel to the camera viewport and passing throught the starting position
// use ray-plane intersection see i.e. https://en.wikipedia.org/wiki/Line%E2%80%93plane_intersection algebric form
// in our case plane normal and ray direction are the same (orthogonal view)
// when moving to perspective camera the negative z unit axis of the camera needs to be transformed in world space and used as plane normal
Vec3d inters = data.mouse_ray.a + (m_starting_drag_position - data.mouse_ray.a).dot(mouse_dir) / mouse_dir.squaredNorm() * mouse_dir;
const Vec3d inters = data.mouse_ray.a + (m_starting_drag_position - data.mouse_ray.a).dot(mouse_dir) / mouse_dir.squaredNorm() * mouse_dir;
// vector from the starting position to the found intersection
Vec3d inters_vec = inters - m_starting_drag_position;
const Vec3d inters_vec = inters - m_starting_drag_position;
// finds projection of the vector along the staring direction
projection = inters_vec.dot(starting_vec.normalized());
@ -285,9 +445,14 @@ double GLGizmoMove3D::calc_projection(const UpdateData& data) const
}
#if !ENABLE_GIZMO_GRABBER_REFACTOR
#if ENABLE_WORLD_COORDINATE && ENABLE_GL_SHADERS_ATTRIBUTES
void GLGizmoMove3D::render_grabber_extension(Axis axis, const Transform3d& base_matrix, const BoundingBoxf3& box, bool picking)
#else
void GLGizmoMove3D::render_grabber_extension(Axis axis, const BoundingBoxf3& box, bool picking)
#endif // ENABLE_WORLD_COORDINATE && ENABLE_GL_SHADERS_ATTRIBUTES
{
const float mean_size = float((box.size().x() + box.size().y() + box.size().z()) / 3.0);
const Vec3d box_size = box.size();
const float mean_size = float((box_size.x() + box_size.y() + box_size.z()) / 3.0);
const double size = m_dragging ? double(m_grabbers[axis].get_dragging_half_size(mean_size)) : double(m_grabbers[axis].get_half_size(mean_size));
#if ENABLE_LEGACY_OPENGL_REMOVAL
@ -312,7 +477,7 @@ void GLGizmoMove3D::render_grabber_extension(Axis axis, const BoundingBoxf3& box
#if ENABLE_GL_SHADERS_ATTRIBUTES
const Camera& camera = wxGetApp().plater()->get_camera();
Transform3d view_model_matrix = camera.get_view_matrix() * Geometry::assemble_transform(m_grabbers[axis].center);
Transform3d view_model_matrix = camera.get_view_matrix() * base_matrix * Geometry::assemble_transform(m_grabbers[axis].center);
if (axis == X)
view_model_matrix = view_model_matrix * Geometry::assemble_transform(Vec3d::Zero(), 0.5 * PI * Vec3d::UnitY());
else if (axis == Y)
@ -345,5 +510,62 @@ void GLGizmoMove3D::render_grabber_extension(Axis axis, const BoundingBoxf3& box
}
#endif // !ENABLE_GIZMO_GRABBER_REFACTOR
#if ENABLE_WORLD_COORDINATE
#if ENABLE_GL_SHADERS_ATTRIBUTES
Transform3d GLGizmoMove3D::local_transform(const Selection& selection) const
{
Transform3d ret = Geometry::assemble_transform(m_center);
if (!wxGetApp().obj_manipul()->is_world_coordinates()) {
const GLVolume& v = *selection.get_first_volume();
Transform3d orient_matrix = v.get_instance_transformation().get_rotation_matrix();
if (selection.is_single_volume_or_modifier() && wxGetApp().obj_manipul()->is_local_coordinates())
orient_matrix = orient_matrix * v.get_volume_transformation().get_rotation_matrix();
ret = ret * orient_matrix;
}
return ret;
}
#else
void GLGizmoMove3D::transform_to_local(const Selection& selection) const
{
glsafe(::glTranslated(m_center.x(), m_center.y(), m_center.z()));
if (!wxGetApp().obj_manipul()->is_world_coordinates()) {
const GLVolume& v = *selection.get_first_volume();
Transform3d orient_matrix = v.get_instance_transformation().get_matrix(true, false, true, true);
if (selection.is_single_volume_or_modifier() && wxGetApp().obj_manipul()->is_local_coordinates())
orient_matrix = orient_matrix * v.get_volume_transformation().get_matrix(true, false, true, true);
glsafe(::glMultMatrixd(orient_matrix.data()));
}
}
#endif // ENABLE_GL_SHADERS_ATTRIBUTES
void GLGizmoMove3D::calc_selection_box_and_center()
{
const Selection& selection = m_parent.get_selection();
const ECoordinatesType coordinates_type = wxGetApp().obj_manipul()->get_coordinates_type();
if (coordinates_type == ECoordinatesType::World) {
m_bounding_box = selection.get_bounding_box();
m_center = m_bounding_box.center();
}
else if (coordinates_type == ECoordinatesType::Local && selection.is_single_volume_or_modifier()) {
const GLVolume& v = *selection.get_first_volume();
m_bounding_box = v.transformed_convex_hull_bounding_box(
v.get_instance_transformation().get_scaling_factor_matrix() * v.get_volume_transformation().get_scaling_factor_matrix());
m_center = v.world_matrix() * m_bounding_box.center();
}
else {
m_bounding_box.reset();
const Selection::IndicesList& ids = selection.get_volume_idxs();
for (unsigned int id : ids) {
const GLVolume& v = *selection.get_volume(id);
m_bounding_box.merge(v.transformed_convex_hull_bounding_box(v.get_volume_transformation().get_matrix()));
}
const Geometry::Transformation inst_trafo = selection.get_first_volume()->get_instance_transformation();
m_bounding_box = m_bounding_box.transformed(inst_trafo.get_scaling_factor_matrix());
m_center = inst_trafo.get_matrix_no_scaling_factor() * m_bounding_box.center();
}
}
#endif // ENABLE_WORLD_COORDINATE
} // namespace GUI
} // namespace Slic3r

View File

@ -7,11 +7,19 @@
namespace Slic3r {
namespace GUI {
#if ENABLE_WORLD_COORDINATE
class Selection;
#endif // ENABLE_WORLD_COORDINATE
class GLGizmoMove3D : public GLGizmoBase
{
static const double Offset;
Vec3d m_displacement{ Vec3d::Zero() };
#if ENABLE_WORLD_COORDINATE
Vec3d m_center{ Vec3d::Zero() };
BoundingBoxf3 m_bounding_box;
#endif // ENABLE_WORLD_COORDINATE
double m_snap_step{ 1.0 };
Vec3d m_starting_drag_position{ Vec3d::Zero() };
Vec3d m_starting_box_center{ Vec3d::Zero() };
@ -49,7 +57,6 @@ public:
/// Detect reduction of move for wipetover on selection change
/// </summary>
void data_changed() override;
protected:
bool on_init() override;
std::string on_get_name() const override;
@ -62,11 +69,25 @@ protected:
private:
double calc_projection(const UpdateData& data) const;
#if ENABLE_WORLD_COORDINATE
#if ENABLE_GL_SHADERS_ATTRIBUTES
Transform3d local_transform(const Selection& selection) const;
#else
void transform_to_local(const Selection& selection) const;
#endif // ENABLE_GL_SHADERS_ATTRIBUTES
void calc_selection_box_and_center();
#endif // ENABLE_WORLD_COORDINATE
#if !ENABLE_GIZMO_GRABBER_REFACTOR
#if ENABLE_WORLD_COORDINATE && ENABLE_GL_SHADERS_ATTRIBUTES
void render_grabber_extension(Axis axis, const Transform3d& base_matrix, const BoundingBoxf3& box, bool picking);
#else
void render_grabber_extension(Axis axis, const BoundingBoxf3& box, bool picking);
#endif // ENABLE_WORLD_COORDINATE && ENABLE_GL_SHADERS_ATTRIBUTES
#endif // !ENABLE_GIZMO_GRABBER_REFACTOR
};
} // namespace GUI
} // namespace Slic3r

View File

@ -291,7 +291,11 @@ void GLGizmoPainterBase::render_cursor_sphere(const Transform3d& trafo) const
return;
#endif // ENABLE_LEGACY_OPENGL_REMOVAL
#if ENABLE_WORLD_COORDINATE
const Transform3d complete_scaling_matrix_inverse = Geometry::Transformation(trafo).get_scaling_factor_matrix().inverse();
#else
const Transform3d complete_scaling_matrix_inverse = Geometry::Transformation(trafo).get_matrix(true, true, false, true).inverse();
#endif // ENABLE_WORLD_COORDINATE
const bool is_left_handed = Geometry::Transformation(trafo).is_left_handed();
#if !ENABLE_GL_SHADERS_ATTRIBUTES
@ -508,7 +512,11 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
const Selection &selection = m_parent.get_selection();
const ModelObject *mo = m_c->selection_info()->model_object();
const ModelInstance *mi = mo->instances[selection.get_instance_idx()];
#if ENABLE_WORLD_COORDINATE
const Transform3d trafo_matrix_not_translate = mi->get_transformation().get_matrix_no_offset() * mo->volumes[m_rr.mesh_id]->get_matrix_no_offset();
#else
const Transform3d trafo_matrix_not_translate = mi->get_transformation().get_matrix(true) * mo->volumes[m_rr.mesh_id]->get_matrix(true);
#endif // ENABLE_WORLD_COORDINATE
const Transform3d trafo_matrix = mi->get_transformation().get_matrix() * mo->volumes[m_rr.mesh_id]->get_matrix();
m_triangle_selectors[m_rr.mesh_id]->seed_fill_select_triangles(m_rr.hit, int(m_rr.facet), trafo_matrix_not_translate, this->get_clipping_plane_in_volume_coordinates(trafo_matrix), m_smart_fill_angle,
m_paint_on_overhangs_only ? m_highlight_by_angle_threshold_deg : 0.f, true);
@ -547,7 +555,11 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
const ModelObject *mo = m_c->selection_info()->model_object();
const ModelInstance *mi = mo->instances[selection.get_instance_idx()];
const Transform3d instance_trafo = mi->get_transformation().get_matrix();
#if ENABLE_WORLD_COORDINATE
const Transform3d instance_trafo_not_translate = mi->get_transformation().get_matrix_no_offset();
#else
const Transform3d instance_trafo_not_translate = mi->get_transformation().get_matrix(true);
#endif // ENABLE_WORLD_COORDINATE
// Precalculate transformations of individual meshes.
std::vector<Transform3d> trafo_matrices;
@ -555,7 +567,11 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
for (const ModelVolume *mv : mo->volumes)
if (mv->is_model_part()) {
trafo_matrices.emplace_back(instance_trafo * mv->get_matrix());
#if ENABLE_WORLD_COORDINATE
trafo_matrices_not_translate.emplace_back(instance_trafo_not_translate * mv->get_matrix_no_offset());
#else
trafo_matrices_not_translate.emplace_back(instance_trafo_not_translate * mv->get_matrix(true));
#endif // ENABLE_WORLD_COORDINATE
}
std::vector<std::vector<ProjectedMousePosition>> projected_mouse_positions_by_mesh = get_projected_mouse_positions(mouse_position, 1., trafo_matrices);
@ -637,7 +653,11 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
const ModelObject *mo = m_c->selection_info()->model_object();
const ModelInstance *mi = mo->instances[selection.get_instance_idx()];
const Transform3d instance_trafo = mi->get_transformation().get_matrix();
#if ENABLE_WORLD_COORDINATE
const Transform3d instance_trafo_not_translate = mi->get_transformation().get_matrix_no_offset();
#else
const Transform3d instance_trafo_not_translate = mi->get_transformation().get_matrix(true);
#endif // ENABLE_WORLD_COORDINATE
// Precalculate transformations of individual meshes.
std::vector<Transform3d> trafo_matrices;
@ -645,7 +665,11 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
for (const ModelVolume *mv : mo->volumes)
if (mv->is_model_part()) {
trafo_matrices.emplace_back(instance_trafo * mv->get_matrix());
#if ENABLE_WORLD_COORDINATE
trafo_matrices_not_translate.emplace_back(instance_trafo_not_translate * mv->get_matrix_no_offset());
#else
trafo_matrices_not_translate.emplace_back(instance_trafo_not_translate * mv->get_matrix(true));
#endif // ENABLE_WORLD_COORDINATE
}
// Now "click" into all the prepared points and spill paint around them.

View File

@ -2,15 +2,18 @@
#include "GLGizmoRotate.hpp"
#include "slic3r/GUI/GLCanvas3D.hpp"
#include "slic3r/GUI/ImGuiWrapper.hpp"
#include <GL/glew.h>
#if ENABLE_WORLD_COORDINATE
#include "slic3r/GUI/GUI_ObjectManipulation.hpp"
#endif // ENABLE_WORLD_COORDINATE
#include "slic3r/GUI/GUI_App.hpp"
#include "slic3r/GUI/GUI.hpp"
#include "slic3r/GUI/Plater.hpp"
#include "slic3r/GUI/Jobs/RotoptimizeJob.hpp"
#include "libslic3r/PresetBundle.hpp"
#include "slic3r/GUI/Jobs/RotoptimizeJob.hpp"
#include <GL/glew.h>
namespace Slic3r {
namespace GUI {
@ -99,6 +102,9 @@ bool GLGizmoRotate::on_init()
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();
m_center = box.center();
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_fine_in_radius = m_radius;
m_snap_fine_out_radius = m_snap_fine_in_radius + m_radius * ScaleLongTooth;
#endif // ENABLE_WORLD_COORDINATE
}
void GLGizmoRotate::on_dragging(const UpdateData &data)
@ -151,15 +158,21 @@ void GLGizmoRotate::on_render()
#endif // !ENABLE_GIZMO_GRABBER_REFACTOR
const Selection& selection = m_parent.get_selection();
#if !ENABLE_WORLD_COORDINATE
const BoundingBoxf3& box = selection.get_bounding_box();
#endif // !ENABLE_WORLD_COORDINATE
if (m_hover_id != 0 && !m_grabbers.front().dragging) {
#if ENABLE_WORLD_COORDINATE
init_data_from_selection(selection);
#else
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_radius * (1.0f + ScaleLongTooth);
#endif // ENABLE_WORLD_COORDINATE
}
const double grabber_radius = (double)m_radius * (1.0 + (double)GrabberOffset);
@ -223,10 +236,17 @@ void GLGizmoRotate::on_render()
render_angle();
#endif // ENABLE_LEGACY_OPENGL_REMOVAL
#if ENABLE_WORLD_COORDINATE
render_grabber(m_bounding_box);
#if !ENABLE_GIZMO_GRABBER_REFACTOR
render_grabber_extension(m_bounding_box, false);
#endif // !ENABLE_GIZMO_GRABBER_REFACTOR
#else
render_grabber(box);
#if !ENABLE_GIZMO_GRABBER_REFACTOR
render_grabber_extension(box, false);
#endif // !ENABLE_GIZMO_GRABBER_REFACTOR
#endif // ENABLE_WORLD_COORDINATE
#if !ENABLE_GL_SHADERS_ATTRIBUTES
glsafe(::glPopMatrix());
@ -246,17 +266,73 @@ void GLGizmoRotate::on_render_for_picking()
transform_to_local(selection);
#endif // ENABLE_GL_SHADERS_ATTRIBUTES
#if ENABLE_WORLD_COORDINATE
render_grabbers_for_picking(m_bounding_box);
#if !ENABLE_GIZMO_GRABBER_REFACTOR
render_grabber_extension(m_bounding_box, true);
#endif // !ENABLE_GIZMO_GRABBER_REFACTOR
#else
const BoundingBoxf3& box = selection.get_bounding_box();
render_grabbers_for_picking(box);
#if !ENABLE_GIZMO_GRABBER_REFACTOR
render_grabber_extension(box, true);
#endif // !ENABLE_GIZMO_GRABBER_REFACTOR
#endif // ENABLE_WORLD_COORDINATE
#if !ENABLE_GL_SHADERS_ATTRIBUTES
glsafe(::glPopMatrix());
#endif // !ENABLE_GL_SHADERS_ATTRIBUTES
}
#if ENABLE_WORLD_COORDINATE
void GLGizmoRotate::init_data_from_selection(const Selection& selection)
{
ECoordinatesType coordinates_type;
if (selection.is_wipe_tower())
coordinates_type = ECoordinatesType::Local;
else
coordinates_type = wxGetApp().obj_manipul()->get_coordinates_type();
if (coordinates_type == ECoordinatesType::World) {
m_bounding_box = selection.get_bounding_box();
m_center = m_bounding_box.center();
}
else if (coordinates_type == ECoordinatesType::Local && selection.is_single_volume_or_modifier()) {
const GLVolume& v = *selection.get_first_volume();
m_bounding_box = v.transformed_convex_hull_bounding_box(
v.get_instance_transformation().get_scaling_factor_matrix() * v.get_volume_transformation().get_scaling_factor_matrix());
m_center = v.world_matrix() * m_bounding_box.center();
}
else {
m_bounding_box.reset();
const Selection::IndicesList& ids = selection.get_volume_idxs();
for (unsigned int id : ids) {
const GLVolume& v = *selection.get_volume(id);
m_bounding_box.merge(v.transformed_convex_hull_bounding_box(v.get_volume_transformation().get_matrix()));
}
const Geometry::Transformation inst_trafo = selection.get_first_volume()->get_instance_transformation();
m_bounding_box = m_bounding_box.transformed(inst_trafo.get_scaling_factor_matrix());
m_center = inst_trafo.get_matrix_no_scaling_factor() * m_bounding_box.center();
}
m_radius = Offset + m_bounding_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 (coordinates_type == ECoordinatesType::World)
m_orient_matrix = Transform3d::Identity();
else if (coordinates_type == ECoordinatesType::Local && (selection.is_wipe_tower() || selection.is_single_volume_or_modifier())) {
const GLVolume& v = *selection.get_first_volume();
m_orient_matrix = v.get_instance_transformation().get_rotation_matrix() * v.get_volume_transformation().get_rotation_matrix();
}
else {
const GLVolume& v = *selection.get_first_volume();
m_orient_matrix = v.get_instance_transformation().get_rotation_matrix();
}
}
#endif // ENABLE_WORLD_COORDINATE
void GLGizmoRotate3D::on_render_input_window(float x, float y, float bottom_limit)
{
if (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA)
@ -317,10 +393,10 @@ void GLGizmoRotate::render_circle() const
#else
::glBegin(GL_LINE_LOOP);
for (unsigned int i = 0; i < ScaleStepsCount; ++i) {
float angle = (float)i * ScaleStepRad;
float x = ::cos(angle) * m_radius;
float y = ::sin(angle) * m_radius;
float z = 0.0f;
const float angle = float(i) * ScaleStepRad;
const float x = ::cos(angle) * m_radius;
const float y = ::sin(angle) * m_radius;
const float z = 0.0f;
::glVertex3f((GLfloat)x, (GLfloat)y, (GLfloat)z);
}
glsafe(::glEnd());
@ -519,10 +595,10 @@ void GLGizmoRotate::render_angle() const
#else
::glBegin(GL_LINE_STRIP);
for (unsigned int i = 0; i <= AngleResolution; ++i) {
float angle = (float)i * step_angle;
float x = ::cos(angle) * ex_radius;
float y = ::sin(angle) * ex_radius;
float z = 0.0f;
const float angle = float(i) * step_angle;
const float x = ::cos(angle) * ex_radius;
const float y = ::sin(angle) * ex_radius;
const float z = 0.0f;
::glVertex3f((GLfloat)x, (GLfloat)y, (GLfloat)z);
}
glsafe(::glEnd());
@ -661,12 +737,20 @@ Transform3d GLGizmoRotate::local_transform(const Selection& selection) const
{
case X:
{
ret = Geometry::assemble_transform(Vec3d::Zero(), Vec3d(0.0, 0.5 * PI, 0.0)) * Geometry::assemble_transform(Vec3d::Zero(), Vec3d(0.0, 0.0, -0.5 * PI));
#if ENABLE_WORLD_COORDINATE
ret = Geometry::rotation_transform(0.5 * PI * Vec3d::UnitY()) * Geometry::rotation_transform(-0.5 * PI * Vec3d::UnitZ());
#else
ret = Geometry::assemble_transform(Vec3d::Zero(), 0.5 * PI * Vec3d::UnitY()) * Geometry::assemble_transform(Vec3d::Zero(), -0.5 * PI * Vec3d::UnitZ());
#endif // ENABLE_WORLD_COORDINATE
break;
}
case Y:
{
ret = Geometry::assemble_transform(Vec3d::Zero(), Vec3d(0.0, 0.0, -0.5 * PI)) * Geometry::assemble_transform(Vec3d::Zero(), Vec3d(0.0, -0.5 * PI, 0.0));
#if ENABLE_WORLD_COORDINATE
ret = Geometry::rotation_transform(-0.5 * PI * Vec3d::UnitZ()) * Geometry::rotation_transform(-0.5 * PI * Vec3d::UnitY());
#else
ret = Geometry::assemble_transform(Vec3d::Zero(), -0.5 * PI * Vec3d::UnitZ()) * Geometry::assemble_transform(Vec3d::Zero(), -0.5 * PI * Vec3d::UnitY());
#endif // ENABLE_WORLD_COORDINATE
break;
}
default:
@ -677,20 +761,28 @@ Transform3d GLGizmoRotate::local_transform(const Selection& selection) const
}
}
#if ENABLE_WORLD_COORDINATE
return Geometry::translation_transform(m_center) * m_orient_matrix * ret;
#else
if (selection.is_single_volume() || selection.is_single_modifier() || selection.requires_local_axes())
ret = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(true, false, true, true) * ret;
ret = selection.get_first_volume()->get_instance_transformation().get_matrix(true, false, true, true) * ret;
return Geometry::assemble_transform(m_center) * ret;
#endif // ENABLE_WORLD_COORDINATE
}
#else
void GLGizmoRotate::transform_to_local(const Selection& selection) const
{
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()) {
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_first_volume()->get_instance_transformation().get_matrix(true, false, true, true);
glsafe(::glMultMatrixd(orient_matrix.data()));
}
#endif // ENABLE_WORLD_COORDINATE
switch (m_axis)
{
@ -744,8 +836,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())
m = m * selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(true, false, true, true).inverse();
m = m * selection.get_first_volume()->get_instance_transformation().get_matrix(true, false, true, true).inverse();
#endif // ENABLE_WORLD_COORDINATE
m.translate(-m_center);
@ -766,31 +862,51 @@ bool GLGizmoRotate3D::on_mouse(const wxMouseEvent &mouse_event)
{
if (mouse_event.Dragging() && m_dragging) {
// Apply new temporary rotations
TransformationType transformation_type(
TransformationType::World_Relative_Joint);
if (mouse_event.AltDown()) transformation_type.set_independent();
#if ENABLE_WORLD_COORDINATE
TransformationType transformation_type;
if (m_parent.get_selection().is_wipe_tower())
transformation_type = TransformationType::Instance_Relative_Joint;
else {
switch (wxGetApp().obj_manipul()->get_coordinates_type())
{
default:
case ECoordinatesType::World: { transformation_type = TransformationType::World_Relative_Joint; break; }
case ECoordinatesType::Instance: { transformation_type = TransformationType::Instance_Relative_Joint; break; }
case ECoordinatesType::Local: { transformation_type = TransformationType::Local_Relative_Joint; break; }
}
}
#else
TransformationType transformation_type(TransformationType::World_Relative_Joint);
#endif // ENABLE_WORLD_COORDINATE
if (mouse_event.AltDown())
transformation_type.set_independent();
m_parent.get_selection().rotate(get_rotation(), transformation_type);
}
return use_grabbers(mouse_event);
}
void GLGizmoRotate3D::data_changed() {
const Selection &selection = m_parent.get_selection();
bool is_wipe_tower = selection.is_wipe_tower();
if (is_wipe_tower) {
DynamicPrintConfig& config = wxGetApp().preset_bundle->prints.get_edited_preset().config;
float wipe_tower_rotation_angle =
if (m_parent.get_selection().is_wipe_tower()) {
#if !ENABLE_WORLD_COORDINATE
const DynamicPrintConfig& config = wxGetApp().preset_bundle->prints.get_edited_preset().config;
const float wipe_tower_rotation_angle =
dynamic_cast<const ConfigOptionFloat*>(
config.option("wipe_tower_rotation_angle"))
->value;
config.option("wipe_tower_rotation_angle"))->value;
set_rotation(Vec3d(0., 0., (M_PI / 180.) * wipe_tower_rotation_angle));
#endif // !ENABLE_WORLD_COORDINATE
m_gizmos[0].disable_grabber();
m_gizmos[1].disable_grabber();
} else {
}
else {
#if !ENABLE_WORLD_COORDINATE
set_rotation(Vec3d::Zero());
#endif // !ENABLE_WORLD_COORDINATE
m_gizmos[0].enable_grabber();
m_gizmos[1].enable_grabber();
}
#if ENABLE_WORLD_COORDINATE
set_rotation(Vec3d::Zero());
#endif // ENABLE_WORLD_COORDINATE
}
bool GLGizmoRotate3D::on_init()

View File

@ -34,6 +34,10 @@ private:
float m_snap_coarse_out_radius{ 0.0f };
float m_snap_fine_in_radius{ 0.0f };
float m_snap_fine_out_radius{ 0.0f };
#if ENABLE_WORLD_COORDINATE
BoundingBoxf3 m_bounding_box;
Transform3d m_orient_matrix{ Transform3d::Identity() };
#endif // ENABLE_WORLD_COORDINATE
#if !ENABLE_GIZMO_GRABBER_REFACTOR
GLModel m_cone;
@ -119,6 +123,10 @@ private:
// 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;
#if ENABLE_WORLD_COORDINATE
void init_data_from_selection(const Selection& selection);
#endif // ENABLE_WORLD_COORDINATE
};
class GLGizmoRotate3D : public GLGizmoBase
@ -129,7 +137,7 @@ public:
GLGizmoRotate3D(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id);
Vec3d get_rotation() const { return Vec3d(m_gizmos[X].get_angle(), m_gizmos[Y].get_angle(), m_gizmos[Z].get_angle()); }
void set_rotation(const Vec3d& rotation) { m_gizmos[X].set_angle(rotation(0)); m_gizmos[Y].set_angle(rotation(1)); m_gizmos[Z].set_angle(rotation(2)); }
void set_rotation(const Vec3d& rotation) { m_gizmos[X].set_angle(rotation.x()); m_gizmos[Y].set_angle(rotation.y()); m_gizmos[Z].set_angle(rotation.z()); }
std::string get_tooltip() const override {
std::string tooltip = m_gizmos[X].get_tooltip();

View File

@ -2,6 +2,9 @@
#include "GLGizmoScale.hpp"
#include "slic3r/GUI/GLCanvas3D.hpp"
#include "slic3r/GUI/GUI_App.hpp"
#if ENABLE_WORLD_COORDINATE
#include "slic3r/GUI/GUI_ObjectManipulation.hpp"
#endif // ENABLE_WORLD_COORDINATE
#if ENABLE_GL_SHADERS_ATTRIBUTES
#include "slic3r/GUI/Plater.hpp"
#endif // ENABLE_GL_SHADERS_ATTRIBUTES
@ -14,7 +17,7 @@ namespace Slic3r {
namespace GUI {
const float GLGizmoScale3D::Offset = 5.0f;
const double GLGizmoScale3D::Offset = 5.0;
GLGizmoScale3D::GLGizmoScale3D(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id)
: GLGizmoBase(parent, icon_filename, sprite_id)
@ -38,16 +41,17 @@ GLGizmoScale3D::GLGizmoScale3D(GLCanvas3D& parent, const std::string& icon_filen
std::string GLGizmoScale3D::get_tooltip() const
{
#if ENABLE_WORLD_COORDINATE
const Vec3d scale = 100.0 * m_scale;
#else
const Selection& selection = m_parent.get_selection();
bool single_instance = selection.is_single_full_instance();
bool single_volume = selection.is_single_modifier() || selection.is_single_volume();
Vec3f scale = 100.0f * Vec3f::Ones();
if (single_instance)
scale = 100.0f * selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_scaling_factor().cast<float>();
else if (single_volume)
scale = 100.0f * selection.get_volume(*selection.get_volume_idxs().begin())->get_volume_scaling_factor().cast<float>();
Vec3d scale = 100.0 * Vec3d::Ones();
if (selection.is_single_full_instance())
scale = 100.0 * selection.get_first_volume()->get_instance_scaling_factor();
else if (selection.is_single_modifier() || selection.is_single_volume())
scale = 100.0 * selection.get_first_volume()->get_volume_scaling_factor();
#endif // ENABLE_WORLD_COORDINATE
if (m_hover_id == 0 || m_hover_id == 1 || m_grabbers[0].dragging || m_grabbers[1].dragging)
return "X: " + format(scale.x(), 4) + "%";
@ -72,12 +76,28 @@ bool GLGizmoScale3D::on_mouse(const wxMouseEvent &mouse_event)
if (mouse_event.Dragging()) {
if (m_dragging) {
// Apply new temporary scale factors
TransformationType transformation_type(TransformationType::Local_Absolute_Joint);
if (mouse_event.AltDown()) transformation_type.set_independent();
#if ENABLE_WORLD_COORDINATE
TransformationType transformation_type;
if (wxGetApp().obj_manipul()->is_local_coordinates())
transformation_type.set_local();
else if (wxGetApp().obj_manipul()->is_instance_coordinates())
transformation_type.set_instance();
transformation_type.set_relative();
#else
TransformationType transformation_type(TransformationType::Local_Absolute_Joint);
#endif // ENABLE_WORLD_COORDINATE
if (mouse_event.AltDown())
transformation_type.set_independent();
#if ENABLE_WORLD_COORDINATE
m_parent.get_selection().scale_and_translate(m_scale, m_offset, transformation_type);
#else
Selection& selection = m_parent.get_selection();
selection.scale(get_scale(), transformation_type);
selection.scale(m_scale, transformation_type);
if (mouse_event.CmdDown()) selection.translate(m_offset, true);
#endif // ENABLE_WORLD_COORDINATE
}
}
return use_grabbers(mouse_event);
@ -85,26 +105,29 @@ bool GLGizmoScale3D::on_mouse(const wxMouseEvent &mouse_event)
void GLGizmoScale3D::data_changed()
{
#if ENABLE_WORLD_COORDINATE
set_scale(Vec3d::Ones());
#else
const Selection& selection = m_parent.get_selection();
bool enable_scale_xyz = selection.is_single_full_instance() ||
selection.is_single_volume() ||
selection.is_single_modifier();
for (unsigned int i = 0; i < 6; ++i)
m_grabbers[i].enabled = enable_scale_xyz;
if (enable_scale_xyz) {
// all volumes in the selection belongs to the same instance, any of
// them contains the needed data, so we take the first
const GLVolume *volume = selection.get_volume(*selection.get_volume_idxs().begin());
if (selection.is_single_full_instance()) {
const GLVolume* volume = selection.get_first_volume();
if (selection.is_single_full_instance())
set_scale(volume->get_instance_scaling_factor());
} else if (selection.is_single_volume() ||
selection.is_single_modifier()) {
else if (selection.is_single_volume() || selection.is_single_modifier())
set_scale(volume->get_volume_scaling_factor());
}
} else {
else
set_scale(Vec3d::Ones());
}
#endif // ENABLE_WORLD_COORDINATE
}
bool GLGizmoScale3D::on_init()
@ -113,15 +136,17 @@ bool GLGizmoScale3D::on_init()
m_grabbers.push_back(Grabber());
}
#if !ENABLE_WORLD_COORDINATE
double half_pi = 0.5 * (double)PI;
// x axis
m_grabbers[0].angles(1) = half_pi;
m_grabbers[1].angles(1) = half_pi;
m_grabbers[0].angles.y() = half_pi;
m_grabbers[1].angles.y() = half_pi;
// y axis
m_grabbers[2].angles(0) = half_pi;
m_grabbers[3].angles(0) = half_pi;
m_grabbers[2].angles.x() = half_pi;
m_grabbers[3].angles.x() = half_pi;
#endif // !ENABLE_WORLD_COORDINATE
m_shortcut_key = WXK_CONTROL_S;
@ -142,9 +167,15 @@ bool GLGizmoScale3D::on_is_activable() const
void GLGizmoScale3D::on_start_dragging()
{
assert(m_hover_id != -1);
m_starting.drag_position = m_grabbers[m_hover_id].center;
m_starting.ctrl_down = wxGetKeyState(WXK_CONTROL);
m_starting.box = (m_starting.ctrl_down && (m_hover_id < 6)) ? m_box : m_parent.get_selection().get_bounding_box();
#if ENABLE_WORLD_COORDINATE
m_starting.drag_position = m_grabbers_transform * m_grabbers[m_hover_id].center;
m_starting.box = m_bounding_box;
m_starting.center = m_center;
m_starting.instance_center = m_instance_center;
#else
m_starting.drag_position = m_grabbers[m_hover_id].center;
m_starting.box = (m_starting.ctrl_down && m_hover_id < 6) ? m_bounding_box : m_parent.get_selection().get_bounding_box();
const Vec3d& center = m_starting.box.center();
m_starting.pivots[0] = m_transform * Vec3d(m_starting.box.max.x(), center.y(), center.z());
@ -153,6 +184,7 @@ void GLGizmoScale3D::on_start_dragging()
m_starting.pivots[3] = m_transform * Vec3d(center.x(), m_starting.box.min.y(), center.z());
m_starting.pivots[4] = m_transform * Vec3d(center.x(), center.y(), m_starting.box.max.z());
m_starting.pivots[5] = m_transform * Vec3d(center.x(), center.y(), m_starting.box.min.z());
#endif // ENABLE_WORLD_COORDINATE
}
void GLGizmoScale3D::on_stop_dragging() {
@ -175,78 +207,156 @@ void GLGizmoScale3D::on_render()
{
const Selection& selection = m_parent.get_selection();
bool single_instance = selection.is_single_full_instance();
bool single_volume = selection.is_single_modifier() || selection.is_single_volume();
glsafe(::glClear(GL_DEPTH_BUFFER_BIT));
glsafe(::glEnable(GL_DEPTH_TEST));
m_box.reset();
m_bounding_box.reset();
#if ENABLE_WORLD_COORDINATE
m_grabbers_transform = Transform3d::Identity();
m_center = Vec3d::Zero();
m_instance_center = Vec3d::Zero();
if (selection.is_single_full_instance() && !wxGetApp().obj_manipul()->is_world_coordinates()) {
#else
m_transform = Transform3d::Identity();
// Transforms grabbers' offsets to world refefence system
Transform3d offsets_transform = Transform3d::Identity();
m_offsets_transform = Transform3d::Identity();
Vec3d angles = Vec3d::Zero();
if (single_instance) {
if (selection.is_single_full_instance()) {
#endif // ENABLE_WORLD_COORDINATE
// calculate bounding box in instance local reference system
const Selection::IndicesList& idxs = selection.get_volume_idxs();
for (unsigned int idx : idxs) {
const GLVolume* vol = selection.get_volume(idx);
m_box.merge(vol->bounding_box().transformed(vol->get_volume_transformation().get_matrix()));
const GLVolume& v = *selection.get_volume(idx);
m_bounding_box.merge(v.transformed_convex_hull_bounding_box(v.get_volume_transformation().get_matrix()));
}
#if ENABLE_WORLD_COORDINATE
m_bounding_box = m_bounding_box.transformed(selection.get_first_volume()->get_instance_transformation().get_scaling_factor_matrix());
#endif // ENABLE_WORLD_COORDINATE
// gets transform from first selected volume
const GLVolume* v = selection.get_volume(*idxs.begin());
m_transform = v->get_instance_transformation().get_matrix();
const GLVolume& v = *selection.get_first_volume();
#if ENABLE_WORLD_COORDINATE
const Transform3d inst_trafo = v.get_instance_transformation().get_matrix_no_scaling_factor();
m_grabbers_transform = inst_trafo * Geometry::translation_transform(m_bounding_box.center());
m_center = inst_trafo * m_bounding_box.center();
m_instance_center = v.get_instance_offset();
}
else if (selection.is_single_volume_or_modifier() && wxGetApp().obj_manipul()->is_instance_coordinates()) {
#else
m_transform = v.get_instance_transformation().get_matrix();
// gets angles from first selected volume
angles = v->get_instance_rotation();
angles = v.get_instance_rotation();
// consider rotation+mirror only components of the transform for offsets
offsets_transform = Geometry::assemble_transform(Vec3d::Zero(), angles, Vec3d::Ones(), v->get_instance_mirror());
offsets_transform = Geometry::assemble_transform(Vec3d::Zero(), angles, Vec3d::Ones(), v.get_instance_mirror());
m_offsets_transform = offsets_transform;
}
else if (single_volume) {
const GLVolume* v = selection.get_volume(*selection.get_volume_idxs().begin());
m_box = v->bounding_box();
m_transform = v->world_matrix();
else if (selection.is_single_modifier() || selection.is_single_volume()) {
#endif // ENABLE_WORLD_COORDINATE
const GLVolume& v = *selection.get_first_volume();
#if ENABLE_WORLD_COORDINATE
m_bounding_box.merge(v.transformed_convex_hull_bounding_box(
v.get_instance_transformation().get_scaling_factor_matrix() * v.get_volume_transformation().get_matrix_no_offset()));
Geometry::Transformation trafo(v.get_instance_transformation().get_rotation_matrix());
trafo.set_offset(v.world_matrix().translation());
m_grabbers_transform = trafo.get_matrix();
m_center = v.world_matrix() * m_bounding_box.center();
m_instance_center = m_center;
}
else if (selection.is_single_volume_or_modifier() && wxGetApp().obj_manipul()->is_local_coordinates()) {
const GLVolume& v = *selection.get_first_volume();
m_bounding_box.merge(v.transformed_convex_hull_bounding_box(
v.get_instance_transformation().get_scaling_factor_matrix() * v.get_volume_transformation().get_scaling_factor_matrix()));
Geometry::Transformation trafo(v.get_instance_transformation().get_rotation_matrix() * v.get_volume_transformation().get_rotation_matrix());
trafo.set_offset(v.world_matrix().translation());
m_grabbers_transform = trafo.get_matrix();
m_center = v.world_matrix() * m_bounding_box.center();
m_instance_center = m_center;
}
else {
m_bounding_box = selection.get_bounding_box();
m_grabbers_transform = Geometry::assemble_transform(m_bounding_box.center());
m_center = m_bounding_box.center();
m_instance_center = selection.is_single_full_instance() ? selection.get_first_volume()->get_instance_offset() : m_center;
}
#else
m_bounding_box = v.bounding_box();
m_transform = v.world_matrix();
angles = Geometry::extract_euler_angles(m_transform);
// consider rotation+mirror only components of the transform for offsets
offsets_transform = Geometry::assemble_transform(Vec3d::Zero(), angles, Vec3d::Ones(), v->get_instance_mirror());
m_offsets_transform = Geometry::assemble_transform(Vec3d::Zero(), v->get_volume_rotation(), Vec3d::Ones(), v->get_volume_mirror());
offsets_transform = Geometry::assemble_transform(Vec3d::Zero(), angles, Vec3d::Ones(), v.get_instance_mirror());
m_offsets_transform = Geometry::assemble_transform(Vec3d::Zero(), v.get_volume_rotation(), Vec3d::Ones(), v.get_volume_mirror());
}
else
m_box = selection.get_bounding_box();
m_bounding_box = selection.get_bounding_box();
const Vec3d& center = m_box.center();
const Vec3d& center = m_bounding_box.center();
const Vec3d offset_x = offsets_transform * Vec3d((double)Offset, 0.0, 0.0);
const Vec3d offset_y = offsets_transform * Vec3d(0.0, (double)Offset, 0.0);
const Vec3d offset_z = offsets_transform * Vec3d(0.0, 0.0, (double)Offset);
const bool ctrl_down = (m_dragging && m_starting.ctrl_down) || (!m_dragging && wxGetKeyState(WXK_CONTROL));
#endif // ENABLE_WORLD_COORDINATE
#if ENABLE_WORLD_COORDINATE
// x axis
m_grabbers[0].center = m_transform * Vec3d(m_box.min.x(), center.y(), center.z()) - offset_x;
const Vec3d box_half_size = 0.5 * m_bounding_box.size();
bool use_constrain = wxGetKeyState(WXK_CONTROL) && (selection.is_single_full_instance() || selection.is_single_volume_or_modifier());
m_grabbers[0].center = { -(box_half_size.x() + Offset), 0.0, 0.0 };
m_grabbers[0].color = (use_constrain && m_hover_id == 1) ? CONSTRAINED_COLOR : AXES_COLOR[0];
m_grabbers[1].center = { box_half_size.x() + Offset, 0.0, 0.0 };
m_grabbers[1].color = (use_constrain && m_hover_id == 0) ? CONSTRAINED_COLOR : AXES_COLOR[0];
// y axis
m_grabbers[2].center = { 0.0, -(box_half_size.y() + Offset), 0.0 };
m_grabbers[2].color = (use_constrain && m_hover_id == 3) ? CONSTRAINED_COLOR : AXES_COLOR[1];
m_grabbers[3].center = { 0.0, box_half_size.y() + Offset, 0.0 };
m_grabbers[3].color = (use_constrain && m_hover_id == 2) ? CONSTRAINED_COLOR : AXES_COLOR[1];
// z axis
m_grabbers[4].center = { 0.0, 0.0, -(box_half_size.z() + Offset) };
m_grabbers[4].color = (use_constrain && m_hover_id == 5) ? CONSTRAINED_COLOR : AXES_COLOR[2];
m_grabbers[5].center = { 0.0, 0.0, box_half_size.z() + Offset };
m_grabbers[5].color = (use_constrain && m_hover_id == 4) ? CONSTRAINED_COLOR : AXES_COLOR[2];
// uniform
m_grabbers[6].center = { -(box_half_size.x() + Offset), -(box_half_size.y() + Offset), 0.0 };
m_grabbers[6].color = (use_constrain && m_hover_id == 8) ? CONSTRAINED_COLOR : m_highlight_color;
m_grabbers[7].center = { box_half_size.x() + Offset, -(box_half_size.y() + Offset), 0.0 };
m_grabbers[7].color = (use_constrain && m_hover_id == 9) ? CONSTRAINED_COLOR : m_highlight_color;
m_grabbers[8].center = { box_half_size.x() + Offset, box_half_size.y() + Offset, 0.0 };
m_grabbers[8].color = (use_constrain && m_hover_id == 6) ? CONSTRAINED_COLOR : m_highlight_color;
m_grabbers[9].center = { -(box_half_size.x() + Offset), box_half_size.y() + Offset, 0.0 };
m_grabbers[9].color = (use_constrain && m_hover_id == 7) ? CONSTRAINED_COLOR : m_highlight_color;
#else
// x axis
m_grabbers[0].center = m_transform * Vec3d(m_bounding_box.min.x(), center.y(), center.z()) - offset_x;
m_grabbers[0].color = (ctrl_down && m_hover_id == 1) ? CONSTRAINED_COLOR : AXES_COLOR[0];
m_grabbers[1].center = m_transform * Vec3d(m_box.max.x(), center.y(), center.z()) + offset_x;
m_grabbers[1].center = m_transform * Vec3d(m_bounding_box.max.x(), center.y(), center.z()) + offset_x;
m_grabbers[1].color = (ctrl_down && m_hover_id == 0) ? CONSTRAINED_COLOR : AXES_COLOR[0];
// y axis
m_grabbers[2].center = m_transform * Vec3d(center.x(), m_box.min.y(), center.z()) - offset_y;
m_grabbers[2].center = m_transform * Vec3d(center.x(), m_bounding_box.min.y(), center.z()) - offset_y;
m_grabbers[2].color = (ctrl_down && m_hover_id == 3) ? CONSTRAINED_COLOR : AXES_COLOR[1];
m_grabbers[3].center = m_transform * Vec3d(center.x(), m_box.max.y(), center.z()) + offset_y;
m_grabbers[3].center = m_transform * Vec3d(center.x(), m_bounding_box.max.y(), center.z()) + offset_y;
m_grabbers[3].color = (ctrl_down && m_hover_id == 2) ? CONSTRAINED_COLOR : AXES_COLOR[1];
// z axis
m_grabbers[4].center = m_transform * Vec3d(center.x(), center.y(), m_box.min.z()) - offset_z;
m_grabbers[4].center = m_transform * Vec3d(center.x(), center.y(), m_bounding_box.min.z()) - offset_z;
m_grabbers[4].color = (ctrl_down && m_hover_id == 5) ? CONSTRAINED_COLOR : AXES_COLOR[2];
m_grabbers[5].center = m_transform * Vec3d(center.x(), center.y(), m_box.max.z()) + offset_z;
m_grabbers[5].center = m_transform * Vec3d(center.x(), center.y(), m_bounding_box.max.z()) + offset_z;
m_grabbers[5].color = (ctrl_down && m_hover_id == 4) ? CONSTRAINED_COLOR : AXES_COLOR[2];
// uniform
m_grabbers[6].center = m_transform * Vec3d(m_box.min.x(), m_box.min.y(), center.z()) - offset_x - offset_y;
m_grabbers[7].center = m_transform * Vec3d(m_box.max.x(), m_box.min.y(), center.z()) + offset_x - offset_y;
m_grabbers[8].center = m_transform * Vec3d(m_box.max.x(), m_box.max.y(), center.z()) + offset_x + offset_y;
m_grabbers[9].center = m_transform * Vec3d(m_box.min.x(), m_box.max.y(), center.z()) - offset_x + offset_y;
m_grabbers[6].center = m_transform * Vec3d(m_bounding_box.min.x(), m_bounding_box.min.y(), center.z()) - offset_x - offset_y;
m_grabbers[7].center = m_transform * Vec3d(m_bounding_box.max.x(), m_bounding_box.min.y(), center.z()) + offset_x - offset_y;
m_grabbers[8].center = m_transform * Vec3d(m_bounding_box.max.x(), m_bounding_box.max.y(), center.z()) + offset_x + offset_y;
m_grabbers[9].center = m_transform * Vec3d(m_bounding_box.min.x(), m_bounding_box.max.y(), center.z()) - offset_x + offset_y;
for (int i = 6; i < 10; ++i) {
m_grabbers[i].color = m_highlight_color;
}
@ -255,12 +365,25 @@ void GLGizmoScale3D::on_render()
for (int i = 0; i < 10; ++i) {
m_grabbers[i].angles = angles;
}
#endif // ENABLE_WORLD_COORDINATE
glsafe(::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f));
#if ENABLE_WORLD_COORDINATE
#if ENABLE_GL_SHADERS_ATTRIBUTES
const Transform3d base_matrix = local_transform(selection);
for (int i = 0; i < 10; ++i) {
m_grabbers[i].matrix = base_matrix;
}
#else
glsafe(::glPushMatrix());
transform_to_local(selection);
#endif // ENABLE_GL_SHADERS_ATTRIBUTES
const float grabber_mean_size = (float)((m_bounding_box.size().x() + m_bounding_box.size().y() + m_bounding_box.size().z()) / 3.0);
#else
const BoundingBoxf3& selection_box = selection.get_bounding_box();
const float grabber_mean_size = (float)((selection_box.size().x() + selection_box.size().y() + selection_box.size().z()) / 3.0);
#endif // ENABLE_WORLD_COORDINATE
if (m_hover_id == -1) {
#if ENABLE_LEGACY_OPENGL_REMOVAL
@ -270,7 +393,11 @@ void GLGizmoScale3D::on_render()
shader->start_using();
#if ENABLE_GL_SHADERS_ATTRIBUTES
const Camera& camera = wxGetApp().plater()->get_camera();
#if ENABLE_WORLD_COORDINATE
shader->set_uniform("view_model_matrix", camera.get_view_matrix() * base_matrix);
#else
shader->set_uniform("view_model_matrix", camera.get_view_matrix());
#endif // ENABLE_WORLD_COORDINATE
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
#endif // ENABLE_GL_SHADERS_ATTRIBUTES
if (m_grabbers[0].enabled && m_grabbers[1].enabled)
@ -317,7 +444,11 @@ void GLGizmoScale3D::on_render()
shader->start_using();
#if ENABLE_GL_SHADERS_ATTRIBUTES
const Camera& camera = wxGetApp().plater()->get_camera();
#if ENABLE_WORLD_COORDINATE
shader->set_uniform("view_model_matrix", camera.get_view_matrix() * base_matrix);
#else
shader->set_uniform("view_model_matrix", camera.get_view_matrix());
#endif // ENABLE_WORLD_COORDINATE
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
#endif // ENABLE_GL_SHADERS_ATTRIBUTES
render_grabbers_connection(0, 1, m_grabbers[0].color);
@ -328,7 +459,7 @@ void GLGizmoScale3D::on_render()
shader = wxGetApp().get_shader("gouraud_light");
#else
// draw connection
glsafe(::glColor4fv(m_grabbers[0].color.data()));
glsafe(::glColor4fv(AXES_COLOR[0].data()));
render_grabbers_connection(0, 1);
// draw grabbers
@ -350,7 +481,11 @@ void GLGizmoScale3D::on_render()
shader->start_using();
#if ENABLE_GL_SHADERS_ATTRIBUTES
const Camera& camera = wxGetApp().plater()->get_camera();
#if ENABLE_WORLD_COORDINATE
shader->set_uniform("view_model_matrix", camera.get_view_matrix() * base_matrix);
#else
shader->set_uniform("view_model_matrix", camera.get_view_matrix());
#endif // ENABLE_WORLD_COORDINATE
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
#endif // ENABLE_GL_SHADERS_ATTRIBUTES
render_grabbers_connection(2, 3, m_grabbers[2].color);
@ -361,7 +496,7 @@ void GLGizmoScale3D::on_render()
shader = wxGetApp().get_shader("gouraud_light");
#else
// draw connection
glsafe(::glColor4fv(m_grabbers[2].color.data()));
glsafe(::glColor4fv(AXES_COLOR[1].data()));
render_grabbers_connection(2, 3);
// draw grabbers
@ -383,7 +518,11 @@ void GLGizmoScale3D::on_render()
shader->start_using();
#if ENABLE_GL_SHADERS_ATTRIBUTES
const Camera& camera = wxGetApp().plater()->get_camera();
#if ENABLE_WORLD_COORDINATE
shader->set_uniform("view_model_matrix", camera.get_view_matrix() * base_matrix);
#else
shader->set_uniform("view_model_matrix", camera.get_view_matrix());
#endif // ENABLE_WORLD_COORDINATE
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
#endif // ENABLE_GL_SHADERS_ATTRIBUTES
render_grabbers_connection(4, 5, m_grabbers[4].color);
@ -394,7 +533,7 @@ void GLGizmoScale3D::on_render()
shader = wxGetApp().get_shader("gouraud_light");
#else
// draw connection
glsafe(::glColor4fv(m_grabbers[4].color.data()));
glsafe(::glColor4fv(AXES_COLOR[2].data()));
render_grabbers_connection(4, 5);
// draw grabbers
@ -416,7 +555,11 @@ void GLGizmoScale3D::on_render()
shader->start_using();
#if ENABLE_GL_SHADERS_ATTRIBUTES
const Camera& camera = wxGetApp().plater()->get_camera();
#if ENABLE_WORLD_COORDINATE
shader->set_uniform("view_model_matrix", camera.get_view_matrix() * base_matrix);
#else
shader->set_uniform("view_model_matrix", camera.get_view_matrix());
#endif // ENABLE_WORLD_COORDINATE
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
#endif // ENABLE_GL_SHADERS_ATTRIBUTES
render_grabbers_connection(6, 7, m_drag_color);
@ -448,12 +591,34 @@ void GLGizmoScale3D::on_render()
shader->stop_using();
}
}
#if ENABLE_WORLD_COORDINATE
#if !ENABLE_GL_SHADERS_ATTRIBUTES
glsafe(::glPopMatrix());
#endif // !ENABLE_GL_SHADERS_ATTRIBUTES
#endif // ENABLE_WORLD_COORDINATE
}
void GLGizmoScale3D::on_render_for_picking()
{
glsafe(::glDisable(GL_DEPTH_TEST));
#if ENABLE_WORLD_COORDINATE
#if ENABLE_GL_SHADERS_ATTRIBUTES
const Transform3d base_matrix = local_transform(m_parent.get_selection());
for (int i = 0; i < 10; ++i) {
m_grabbers[i].matrix = base_matrix;
}
#else
glsafe(::glPushMatrix());
transform_to_local(m_parent.get_selection());
#endif // ENABLE_GL_SHADERS_ATTRIBUTES
render_grabbers_for_picking(m_bounding_box);
#if !ENABLE_GL_SHADERS_ATTRIBUTES
glsafe(::glPopMatrix());
#endif // !ENABLE_GL_SHADERS_ATTRIBUTES
#else
render_grabbers_for_picking(m_parent.get_selection().get_bounding_box());
#endif // ENABLE_WORLD_COORDINATE
}
#if ENABLE_LEGACY_OPENGL_REMOVAL
@ -509,13 +674,67 @@ void GLGizmoScale3D::render_grabbers_connection(unsigned int id_1, unsigned int
}
#endif // ENABLE_LEGACY_OPENGL_REMOVAL
#if ENABLE_WORLD_COORDINATE
void GLGizmoScale3D::do_scale_along_axis(Axis axis, const UpdateData& data)
{
double ratio = calc_ratio(data);
if (ratio > 0.0) {
Vec3d curr_scale = m_scale;
Vec3d starting_scale = m_starting.scale;
const Selection& selection = m_parent.get_selection();
const ECoordinatesType coordinates_type = wxGetApp().obj_manipul()->get_coordinates_type();
curr_scale(axis) = starting_scale(axis) * ratio;
m_scale = curr_scale;
if (m_starting.ctrl_down && (selection.is_single_full_instance() || selection.is_single_volume_or_modifier())) {
double local_offset = 0.5 * (ratio - 1.0) * m_starting.box.size()(axis);
if (m_hover_id == 2 * axis)
local_offset *= -1.0;
Vec3d center_offset = m_starting.instance_center - m_starting.center; // world coordinates (== Vec3d::Zero() for single volume selection)
if (selection.is_single_full_instance() && coordinates_type == ECoordinatesType::Local)
// from world coordinates to instance coordinates
center_offset = selection.get_first_volume()->get_instance_transformation().get_rotation_matrix().inverse() * center_offset;
local_offset += (ratio - 1.0) * center_offset(axis);
switch (axis)
{
case X: { m_offset = local_offset * Vec3d::UnitX(); break; }
case Y: { m_offset = local_offset * Vec3d::UnitY(); break; }
case Z: { m_offset = local_offset * Vec3d::UnitZ(); break; }
default: { m_offset = Vec3d::Zero(); break; }
}
if (selection.is_single_full_instance() && coordinates_type == ECoordinatesType::Local)
// from instance coordinates to world coordinates
m_offset = selection.get_first_volume()->get_instance_transformation().get_rotation_matrix() * m_offset;
if (selection.is_single_volume_or_modifier()) {
if (coordinates_type == ECoordinatesType::Instance)
m_offset = selection.get_first_volume()->get_instance_transformation().get_scaling_factor_matrix().inverse() * m_offset;
else if (coordinates_type == ECoordinatesType::Local) {
m_offset = selection.get_first_volume()->get_instance_transformation().get_scaling_factor_matrix().inverse() *
selection.get_first_volume()->get_volume_transformation().get_rotation_matrix() * m_offset;
}
}
}
else
m_offset = Vec3d::Zero();
}
}
#else
void GLGizmoScale3D::do_scale_along_axis(Axis axis, const UpdateData& data)
{
const double ratio = calc_ratio(data);
if (ratio > 0.0) {
m_scale(axis) = m_starting.scale(axis) * ratio;
if (m_starting.ctrl_down) {
double local_offset = 0.5 * (m_scale(axis) - m_starting.scale(axis)) * m_starting.box.size()(axis);
if (m_hover_id == 2 * axis)
local_offset *= -1.0;
@ -534,36 +753,86 @@ void GLGizmoScale3D::do_scale_along_axis(Axis axis, const UpdateData& data)
m_offset = Vec3d::Zero();
}
}
#endif // ENABLE_WORLD_COORDINATE
#if ENABLE_WORLD_COORDINATE
void GLGizmoScale3D::do_scale_uniform(const UpdateData & data)
{
double ratio = calc_ratio(data);
const double ratio = calc_ratio(data);
if (ratio > 0.0) {
m_scale = m_starting.scale * ratio;
const Selection& selection = m_parent.get_selection();
const ECoordinatesType coordinates_type = wxGetApp().obj_manipul()->get_coordinates_type();
if (m_starting.ctrl_down && (selection.is_single_full_instance() || selection.is_single_volume_or_modifier())) {
m_offset = 0.5 * (ratio - 1.0) * m_starting.box.size();
if (m_hover_id == 6 || m_hover_id == 9)
m_offset.x() *= -1.0;
if (m_hover_id == 6 || m_hover_id == 7)
m_offset.y() *= -1.0;
Vec3d center_offset = m_starting.instance_center - m_starting.center; // world coordinates (== Vec3d::Zero() for single volume selection)
if (selection.is_single_full_instance() && coordinates_type == ECoordinatesType::Local)
// from world coordinates to instance coordinates
center_offset = selection.get_first_volume()->get_instance_transformation().get_rotation_matrix().inverse() * center_offset;
m_offset += (ratio - 1.0) * center_offset;
if (selection.is_single_full_instance() && coordinates_type == ECoordinatesType::Local)
// from instance coordinates to world coordinates
m_offset = selection.get_first_volume()->get_instance_transformation().get_rotation_matrix() * m_offset;
if (selection.is_single_volume_or_modifier()) {
if (coordinates_type == ECoordinatesType::Instance)
m_offset = selection.get_first_volume()->get_instance_transformation().get_scaling_factor_matrix().inverse() * m_offset;
else if (coordinates_type == ECoordinatesType::Local) {
m_offset = selection.get_first_volume()->get_instance_transformation().get_scaling_factor_matrix().inverse() *
selection.get_first_volume()->get_volume_transformation().get_rotation_matrix() * m_offset;
}
}
}
else
m_offset = Vec3d::Zero();
}
}
#else
void GLGizmoScale3D::do_scale_uniform(const UpdateData& data)
{
const double ratio = calc_ratio(data);
if (ratio > 0.0) {
m_scale = m_starting.scale * ratio;
m_offset = Vec3d::Zero();
}
}
#endif // ENABLE_WORLD_COORDINATE
double GLGizmoScale3D::calc_ratio(const UpdateData& data) const
{
double ratio = 0.0;
Vec3d pivot = (m_starting.ctrl_down && m_hover_id < 6) ? m_starting.pivots[m_hover_id] : m_starting.box.center();
#if ENABLE_WORLD_COORDINATE
const Vec3d starting_vec = m_starting.drag_position - m_starting.center;
#else
const Vec3d pivot = (m_starting.ctrl_down && m_hover_id < 6) ? m_starting.pivots[m_hover_id] : m_starting.box.center();
const Vec3d starting_vec = m_starting.drag_position - pivot;
#endif // ENABLE_WORLD_COORDINATE
const double len_starting_vec = starting_vec.norm();
Vec3d starting_vec = m_starting.drag_position - pivot;
double len_starting_vec = starting_vec.norm();
if (len_starting_vec != 0.0) {
Vec3d mouse_dir = data.mouse_ray.unit_vector();
const Vec3d mouse_dir = data.mouse_ray.unit_vector();
// finds the intersection of the mouse ray with the plane parallel to the camera viewport and passing throught the starting position
// use ray-plane intersection see i.e. https://en.wikipedia.org/wiki/Line%E2%80%93plane_intersection algebric form
// in our case plane normal and ray direction are the same (orthogonal view)
// when moving to perspective camera the negative z unit axis of the camera needs to be transformed in world space and used as plane normal
Vec3d inters = data.mouse_ray.a + (m_starting.drag_position - data.mouse_ray.a).dot(mouse_dir) / mouse_dir.squaredNorm() * mouse_dir;
const Vec3d inters = data.mouse_ray.a + (m_starting.drag_position - data.mouse_ray.a).dot(mouse_dir) / mouse_dir.squaredNorm() * mouse_dir;
// vector from the starting position to the found intersection
Vec3d inters_vec = inters - m_starting.drag_position;
const Vec3d inters_vec = inters - m_starting.drag_position;
// finds projection of the vector along the staring direction
double proj = inters_vec.dot(starting_vec.normalized());
const double proj = inters_vec.dot(starting_vec.normalized());
ratio = (len_starting_vec + proj) / len_starting_vec;
}
@ -574,5 +843,34 @@ double GLGizmoScale3D::calc_ratio(const UpdateData& data) const
return ratio;
}
#if ENABLE_WORLD_COORDINATE
#if ENABLE_GL_SHADERS_ATTRIBUTES
Transform3d GLGizmoScale3D::local_transform(const Selection& selection) const
{
Transform3d ret = Geometry::assemble_transform(m_center);
if (!wxGetApp().obj_manipul()->is_world_coordinates()) {
const GLVolume& v = *selection.get_first_volume();
Transform3d orient_matrix = v.get_instance_transformation().get_rotation_matrix();
if (selection.is_single_volume_or_modifier() && wxGetApp().obj_manipul()->is_local_coordinates())
orient_matrix = orient_matrix * v.get_volume_transformation().get_rotation_matrix();
ret = ret * orient_matrix;
}
return ret;
}
#else
void GLGizmoScale3D::transform_to_local(const Selection& selection) const
{
glsafe(::glTranslated(m_center.x(), m_center.y(), m_center.z()));
if (!wxGetApp().obj_manipul()->is_world_coordinates()) {
Transform3d orient_matrix = selection.get_first_volume()->get_instance_transformation().get_matrix(true, false, true, true);
if (selection.is_single_volume_or_modifier() && wxGetApp().obj_manipul()->is_local_coordinates())
orient_matrix = orient_matrix * selection.get_first_volume()->get_volume_transformation().get_matrix(true, false, true, true);
glsafe(::glMultMatrixd(orient_matrix.data()));
}
}
#endif // ENABLE_GL_SHADERS_ATTRIBUTES
#endif // ENABLE_WORLD_COORDINATE
} // namespace GUI
} // namespace Slic3r

View File

@ -3,31 +3,46 @@
#include "GLGizmoBase.hpp"
#if !ENABLE_WORLD_COORDINATE
#include "libslic3r/BoundingBox.hpp"
#endif // !ENABLE_WORLD_COORDINATE
namespace Slic3r {
namespace GUI {
#if ENABLE_WORLD_COORDINATE
class Selection;
#endif // ENABLE_WORLD_COORDINATE
class GLGizmoScale3D : public GLGizmoBase
{
static const float Offset;
static const double Offset;
struct StartingData
{
Vec3d scale;
Vec3d drag_position;
bool ctrl_down{ false };
Vec3d scale{ Vec3d::Ones() };
Vec3d drag_position{ Vec3d::Zero() };
#if ENABLE_WORLD_COORDINATE
Vec3d center{ Vec3d::Zero() };
Vec3d instance_center{ Vec3d::Zero() };
#endif // ENABLE_WORLD_COORDINATE
BoundingBoxf3 box;
Vec3d pivots[6];
bool ctrl_down;
StartingData() : scale(Vec3d::Ones()), drag_position(Vec3d::Zero()), ctrl_down(false) { for (int i = 0; i < 5; ++i) { pivots[i] = Vec3d::Zero(); } }
#if !ENABLE_WORLD_COORDINATE
std::array<Vec3d, 6> pivots{ Vec3d::Zero(), Vec3d::Zero(), Vec3d::Zero(), Vec3d::Zero(), Vec3d::Zero(), Vec3d::Zero() };
#endif // !ENABLE_WORLD_COORDINATE
};
mutable BoundingBoxf3 m_box;
mutable Transform3d m_transform;
BoundingBoxf3 m_bounding_box;
#if ENABLE_WORLD_COORDINATE
Transform3d m_grabbers_transform;
Vec3d m_center{ Vec3d::Zero() };
Vec3d m_instance_center{ Vec3d::Zero() };
#else
Transform3d m_transform;
// Transforms grabbers offsets to the proper reference system (world for instances, instance for volumes)
mutable Transform3d m_offsets_transform;
Transform3d m_offsets_transform;
#endif // ENABLE_WORLD_COORDINATE
Vec3d m_scale{ Vec3d::Ones() };
Vec3d m_offset{ Vec3d::Zero() };
double m_snap_step{ 0.05 };
@ -54,7 +69,11 @@ public:
void set_snap_step(double step) { m_snap_step = step; }
const Vec3d& get_scale() const { return m_scale; }
#if ENABLE_WORLD_COORDINATE
void set_scale(const Vec3d& scale) { m_starting.scale = scale; m_scale = scale; m_offset = Vec3d::Zero(); }
#else
void set_scale(const Vec3d& scale) { m_starting.scale = scale; m_scale = scale; }
#endif // ENABLE_WORLD_COORDINATE
std::string get_tooltip() const override;
@ -87,6 +106,13 @@ private:
void do_scale_uniform(const UpdateData& data);
double calc_ratio(const UpdateData& data) const;
#if ENABLE_WORLD_COORDINATE
#if ENABLE_GL_SHADERS_ATTRIBUTES
Transform3d local_transform(const Selection& selection) const;
#else
void transform_to_local(const Selection& selection) const;
#endif // ENABLE_GL_SHADERS_ATTRIBUTES
#endif // ENABLE_WORLD_COORDINATE
};

View File

@ -146,9 +146,13 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking)
});
#endif // ENABLE_LEGACY_OPENGL_REMOVAL
const GLVolume* vol = selection.get_volume(*selection.get_volume_idxs().begin());
const GLVolume* vol = selection.get_first_volume();
Geometry::Transformation transformation(vol->get_instance_transformation().get_matrix() * vol->get_volume_transformation().get_matrix());
#if ENABLE_WORLD_COORDINATE
const Transform3d instance_scaling_matrix_inverse = transformation.get_scaling_factor_matrix().inverse();
#else
const Transform3d& instance_scaling_matrix_inverse = transformation.get_matrix(true, true, false, true).inverse();
#endif // ENABLE_WORLD_COORDINATE
#if ENABLE_GL_SHADERS_ATTRIBUTES
const Transform3d instance_matrix = Geometry::assemble_transform(m_c->selection_info()->get_sla_shift() * Vec3d::UnitZ()) * transformation.get_matrix();
const Camera& camera = wxGetApp().plater()->get_camera();
@ -357,7 +361,7 @@ bool GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse_pos, std::pair<Vec
const Camera& camera = wxGetApp().plater()->get_camera();
const Selection& selection = m_parent.get_selection();
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
const GLVolume* volume = selection.get_first_volume();
Geometry::Transformation trafo = volume->get_instance_transformation() * volume->get_volume_transformation();
trafo.set_offset(trafo.get_offset() + Vec3d(0., 0., m_c->selection_info()->get_sla_shift()));

View File

@ -119,7 +119,7 @@ void SelectionInfo::on_update()
const Selection& selection = get_pool()->get_canvas()->get_selection();
if (selection.is_single_full_instance()) {
m_model_object = selection.get_model()->objects[selection.get_object_idx()];
m_z_shift = selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z();
m_z_shift = selection.get_first_volume()->get_sla_shift_z();
}
else
m_model_object = nullptr;

View File

@ -408,7 +408,8 @@ bool GLGizmosManager::gizmos_toolbar_on_mouse(const wxMouseEvent &mouse_event) {
// at this moment is enebled to process mouse move under gizmo
// tools bar e.g. Do not interupt dragging.
return false;
} else if (mc.exist_tooltip) {
}
else if (mc.exist_tooltip) {
// first move out of gizmo tool bar - unselect tooltip
mc.exist_tooltip = false;
update_hover_state(Undefined);
@ -423,10 +424,12 @@ bool GLGizmosManager::gizmos_toolbar_on_mouse(const wxMouseEvent &mouse_event) {
mc.left = true;
open_gizmo(gizmo);
return true;
} else if (mouse_event.RightDown()) {
}
else if (mouse_event.RightDown()) {
mc.right = true;
return true;
} else if (mouse_event.MiddleDown()) {
}
else if (mouse_event.MiddleDown()) {
mc.middle = true;
return true;
}
@ -442,13 +445,16 @@ bool GLGizmosManager::gizmos_toolbar_on_mouse(const wxMouseEvent &mouse_event) {
}
// draging start on toolbar so no propagation into scene
return true;
} else if (mc.left && mouse_event.LeftUp()) {
}
else if (mc.left && mouse_event.LeftUp()) {
mc.left = false;
return true;
} else if (mc.right && mouse_event.RightUp()) {
}
else if (mc.right && mouse_event.RightUp()) {
mc.right = false;
return true;
} else if (mc.middle && mouse_event.MiddleUp()) {
}
else if (mc.middle && mouse_event.MiddleUp()) {
mc.middle = false;
return true;
}

View File

@ -112,7 +112,11 @@ void MeshClipper::render_cut()
void MeshClipper::recalculate_triangles()
{
#if ENABLE_WORLD_COORDINATE
const Transform3f instance_matrix_no_translation_no_scaling = m_trafo.get_rotation_matrix().cast<float>();
#else
const Transform3f& instance_matrix_no_translation_no_scaling = m_trafo.get_matrix(true,false,true).cast<float>();
#endif // ENABLE_WORLD_COORDINATE
// Calculate clipping plane normal in mesh coordinates.
const Vec3f up_noscale = instance_matrix_no_translation_no_scaling.inverse() * m_plane.get_normal().cast<float>();
const Vec3d up = up_noscale.cast<double>().cwiseProduct(m_trafo.get_scaling_factor());
@ -303,7 +307,11 @@ std::vector<unsigned> MeshRaycaster::get_unobscured_idxs(const Geometry::Transfo
{
std::vector<unsigned> out;
#if ENABLE_WORLD_COORDINATE
const Transform3d instance_matrix_no_translation_no_scaling = trafo.get_rotation_matrix();
#else
const Transform3d& instance_matrix_no_translation_no_scaling = trafo.get_matrix(true,false,true);
#endif // ENABLE_WORLD_COORDINATE
Vec3d direction_to_camera = -camera.get_dir_forward();
Vec3d direction_to_camera_mesh = (instance_matrix_no_translation_no_scaling.inverse() * direction_to_camera).normalized().eval();
direction_to_camera_mesh = direction_to_camera_mesh.cwiseProduct(trafo.get_scaling_factor());

View File

@ -57,6 +57,9 @@
#include "GUI_ObjectManipulation.hpp"
#include "GUI_ObjectLayers.hpp"
#include "GUI_Utils.hpp"
#if ENABLE_WORLD_COORDINATE
#include "GUI_Geometry.hpp"
#endif // ENABLE_WORLD_COORDINATE
#include "GUI_Factories.hpp"
#include "wxExtensions.hpp"
#include "MainFrame.hpp"
@ -1514,6 +1517,11 @@ void Sidebar::update_mode()
wxWindowUpdateLocker noUpdates(this);
#if ENABLE_WORLD_COORDINATE
if (m_mode == comSimple)
p->object_manipulation->set_coordinates_type(ECoordinatesType::World);
#endif // ENABLE_WORLD_COORDINATE
p->object_list->get_sizer()->Show(m_mode > comSimple);
p->object_list->unselect_objects();
@ -2077,6 +2085,9 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
view3D_canvas->Bind(EVT_GLCANVAS_WIPETOWER_MOVED, &priv::on_wipetower_moved, this);
view3D_canvas->Bind(EVT_GLCANVAS_WIPETOWER_ROTATED, &priv::on_wipetower_rotated, this);
view3D_canvas->Bind(EVT_GLCANVAS_INSTANCE_ROTATED, [this](SimpleEvent&) { update(); });
#if ENABLE_WORLD_COORDINATE
view3D_canvas->Bind(EVT_GLCANVAS_RESET_SKEW, [this](SimpleEvent&) { update(); });
#endif // ENABLE_WORLD_COORDINATE
view3D_canvas->Bind(EVT_GLCANVAS_INSTANCE_SCALED, [this](SimpleEvent&) { update(); });
view3D_canvas->Bind(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, [this](Event<bool>& evt) { this->sidebar->enable_buttons(evt.data); });
view3D_canvas->Bind(EVT_GLCANVAS_UPDATE_GEOMETRY, &priv::on_update_geometry, this);
@ -2922,7 +2933,7 @@ int Plater::priv::get_selected_volume_idx() const
if ((0 > idx) || (idx > 1000))
#endif // ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
return-1;
const GLVolume* v = selection.get_volume(*selection.get_volume_idxs().begin());
const GLVolume* v = selection.get_first_volume();
if (model.objects[idx]->volumes.size() > 1)
return v->volume_idx();
return -1;
@ -3484,7 +3495,11 @@ bool Plater::priv::replace_volume_with_stl(int object_idx, int volume_idx, const
new_volume->set_type(old_volume->type());
new_volume->set_material_id(old_volume->material_id());
new_volume->set_transformation(old_volume->get_transformation());
#if ENABLE_WORLD_COORDINATE
new_volume->translate(new_volume->get_transformation().get_matrix_no_offset() * (new_volume->source.mesh_offset - old_volume->source.mesh_offset));
#else
new_volume->translate(new_volume->get_transformation().get_matrix(true) * (new_volume->source.mesh_offset - old_volume->source.mesh_offset));
#endif // ENABLE_WORLD_COORDINATE
assert(!old_volume->source.is_converted_from_inches || !old_volume->source.is_converted_from_meters);
if (old_volume->source.is_converted_from_inches)
new_volume->convert_from_imperial_units();
@ -3521,7 +3536,7 @@ void Plater::priv::replace_with_stl()
if (selection.is_wipe_tower() || get_selection().get_volume_idxs().size() != 1)
return;
const GLVolume* v = selection.get_volume(*selection.get_volume_idxs().begin());
const GLVolume* v = selection.get_first_volume();
int object_idx = v->object_idx();
int volume_idx = v->volume_idx();
@ -3839,10 +3854,16 @@ void Plater::priv::reload_from_disk()
new_volume->config.apply(old_volume->config);
new_volume->set_type(old_volume->type());
new_volume->set_material_id(old_volume->material_id());
#if ENABLE_WORLD_COORDINATE
new_volume->set_transformation(Geometry::translation_transform(old_volume->source.transform.get_offset()) *
old_volume->get_transformation().get_matrix_no_offset() * old_volume->source.transform.get_matrix_no_offset());
new_volume->translate(new_volume->get_transformation().get_matrix_no_offset() * (new_volume->source.mesh_offset - old_volume->source.mesh_offset));
#else
new_volume->set_transformation(Geometry::assemble_transform(old_volume->source.transform.get_offset()) *
old_volume->get_transformation().get_matrix(true) *
old_volume->source.transform.get_matrix(true));
new_volume->translate(new_volume->get_transformation().get_matrix(true) * (new_volume->source.mesh_offset - old_volume->source.mesh_offset));
#endif // ENABLE_WORLD_COORDINATE
new_volume->source.object_idx = old_volume->source.object_idx;
new_volume->source.volume_idx = old_volume->source.volume_idx;
assert(!old_volume->source.is_converted_from_inches || !old_volume->source.is_converted_from_meters);
@ -4448,7 +4469,11 @@ void Plater::priv::on_right_click(RBtnEvent& evt)
const bool is_some_full_instances = selection.is_single_full_instance() ||
selection.is_single_full_object() ||
selection.is_multiple_full_instance();
#if ENABLE_WORLD_COORDINATE
const bool is_part = selection.is_single_volume_or_modifier();
#else
const bool is_part = selection.is_single_volume() || selection.is_single_modifier();
#endif // ENABLE_WORLD_COORDINATE
menu = is_some_full_instances ? menus.object_menu() :
is_part ? menus.part_menu() : menus.multi_selection_menu();
}
@ -6030,7 +6055,7 @@ void Plater::export_stl_obj(bool extended, bool selection_only)
if (selection.get_mode() == Selection::Instance)
mesh = mesh_to_export(*model_object, (selection.is_single_full_object() && model_object->instances.size() > 1) ? -1 : selection.get_instance_idx());
else {
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
const GLVolume* volume = selection.get_first_volume();
mesh = model_object->volumes[volume->volume_idx()]->mesh();
mesh.transform(volume->get_volume_transformation().get_matrix(), true);
}

File diff suppressed because it is too large Load Diff

View File

@ -2,7 +2,12 @@
#define slic3r_GUI_Selection_hpp_
#include "libslic3r/Geometry.hpp"
#if ENABLE_WORLD_COORDINATE
#include "GUI_Geometry.hpp"
#include "CoordAxes.hpp"
#else
#include "GLModel.hpp"
#endif // ENABLE_WORLD_COORDINATE
#include <set>
#include <optional>
@ -24,6 +29,7 @@ using ModelObjectPtrs = std::vector<ModelObject*>;
namespace GUI {
#if !ENABLE_WORLD_COORDINATE
class TransformationType
{
public:
@ -76,6 +82,7 @@ private:
Enum m_value;
};
#endif // !ENABLE_WORLD_COORDINATE
class Selection
{
@ -110,16 +117,19 @@ private:
private:
struct TransformCache
{
Vec3d position;
Vec3d rotation;
Vec3d scaling_factor;
Vec3d mirror;
Transform3d rotation_matrix;
Transform3d scale_matrix;
Transform3d mirror_matrix;
Transform3d full_matrix;
Vec3d position{ Vec3d::Zero() };
Vec3d rotation{ Vec3d::Zero() };
Vec3d scaling_factor{ Vec3d::Ones() };
Vec3d mirror{ Vec3d::Ones() };
Transform3d rotation_matrix{ Transform3d::Identity() };
Transform3d scale_matrix{ Transform3d::Identity() };
Transform3d mirror_matrix{ Transform3d::Identity() };
Transform3d full_matrix{ Transform3d::Identity() };
#if ENABLE_WORLD_COORDINATE
Geometry::Transformation transform;
#endif // ENABLE_WORLD_COORDINATE
TransformCache();
TransformCache() = default;
explicit TransformCache(const Geometry::Transformation& transform);
};
@ -131,13 +141,18 @@ private:
VolumeCache(const Geometry::Transformation& volume_transform, const Geometry::Transformation& instance_transform);
const Vec3d& get_volume_position() const { return m_volume.position; }
#if !ENABLE_WORLD_COORDINATE
const Vec3d& get_volume_rotation() const { return m_volume.rotation; }
const Vec3d& get_volume_scaling_factor() const { return m_volume.scaling_factor; }
const Vec3d& get_volume_mirror() const { return m_volume.mirror; }
#endif // !ENABLE_WORLD_COORDINATE
const Transform3d& get_volume_rotation_matrix() const { return m_volume.rotation_matrix; }
const Transform3d& get_volume_scale_matrix() const { return m_volume.scale_matrix; }
const Transform3d& get_volume_mirror_matrix() const { return m_volume.mirror_matrix; }
const Transform3d& get_volume_full_matrix() const { return m_volume.full_matrix; }
#if ENABLE_WORLD_COORDINATE
const Geometry::Transformation& get_volume_transform() const { return m_volume.transform; }
#endif // ENABLE_WORLD_COORDINATE
const Vec3d& get_instance_position() const { return m_instance.position; }
const Vec3d& get_instance_rotation() const { return m_instance.rotation; }
@ -147,6 +162,9 @@ private:
const Transform3d& get_instance_scale_matrix() const { return m_instance.scale_matrix; }
const Transform3d& get_instance_mirror_matrix() const { return m_instance.mirror_matrix; }
const Transform3d& get_instance_full_matrix() const { return m_instance.full_matrix; }
#if ENABLE_WORLD_COORDINATE
const Geometry::Transformation& get_instance_transform() const { return m_instance.transform; }
#endif // ENABLE_WORLD_COORDINATE
};
public:
@ -207,15 +225,32 @@ private:
Cache m_cache;
Clipboard m_clipboard;
std::optional<BoundingBoxf3> m_bounding_box;
// Bounding box of a selection, with no instance scaling applied. This bounding box
// is useful for absolute scaling of tilted objects in world coordinate space.
// Bounding box of a single full instance selection, in world coordinates, with no instance scaling applied.
// This bounding box is useful for absolute scaling of tilted objects in world coordinate space.
// Modifiers are NOT taken in account
std::optional<BoundingBoxf3> m_unscaled_instance_bounding_box;
// Bounding box of a single full instance selection, in world coordinates.
// Modifiers are NOT taken in account
std::optional<BoundingBoxf3> m_scaled_instance_bounding_box;
#if ENABLE_WORLD_COORDINATE
// Bounding box of a single full instance selection, in world coordinates, with no instance scaling applied.
// Modifiers are taken in account
std::optional<BoundingBoxf3> m_full_unscaled_instance_bounding_box;
// Bounding box of a single full instance selection, in world coordinates.
// Modifiers are taken in account
std::optional<BoundingBoxf3> m_full_scaled_instance_bounding_box;
// Bounding box of a single full instance selection, in local coordinates, with no instance scaling applied.
// Modifiers are taken in account
std::optional<BoundingBoxf3> m_full_unscaled_instance_local_bounding_box;
#endif // ENABLE_WORLD_COORDINATE
#if ENABLE_RENDER_SELECTION_CENTER
GLModel m_vbo_sphere;
#endif // ENABLE_RENDER_SELECTION_CENTER
#if ENABLE_WORLD_COORDINATE
CoordAxes m_axes;
#endif // ENABLE_WORLD_COORDINATE
GLModel m_arrow;
GLModel m_curved_arrow;
#if ENABLE_LEGACY_OPENGL_REMOVAL
@ -290,6 +325,9 @@ public:
bool is_from_single_object() const;
bool is_sla_compliant() const;
bool is_instance_mode() const { return m_mode == Instance; }
#if ENABLE_WORLD_COORDINATE
bool is_single_volume_or_modifier() const { return is_single_volume() || is_single_modifier(); }
#endif // ENABLE_WORLD_COORDINATE
bool contains_volume(unsigned int volume_idx) const { return m_list.find(volume_idx) != m_list.end(); }
// returns true if the selection contains all the given indices
@ -299,7 +337,18 @@ public:
// returns true if the selection contains all and only the given indices
bool matches(const std::vector<unsigned int>& volume_idxs) const;
#if ENABLE_WORLD_COORDINATE
enum class EUniformScaleRequiredReason : unsigned char
{
NotRequired,
InstanceNotAxisAligned_World,
VolumeNotAxisAligned_World,
VolumeNotAxisAligned_Instance,
MultipleSelection,
};
#else
bool requires_uniform_scale() const;
#endif // ENABLE_WORLD_COORDINATE
// Returns the the object id if the selection is from a single object, otherwise is -1
int get_object_idx() const;
@ -311,28 +360,60 @@ public:
const IndicesList& get_volume_idxs() const { return m_list; }
const GLVolume* get_volume(unsigned int volume_idx) const;
const GLVolume* get_first_volume() const { return get_volume(*m_list.begin()); }
const ObjectIdxsToInstanceIdxsMap& get_content() const { return m_cache.content; }
unsigned int volumes_count() const { return (unsigned int)m_list.size(); }
const BoundingBoxf3& get_bounding_box() const;
// Bounding box of a selection, with no instance scaling applied. This bounding box
// is useful for absolute scaling of tilted objects in world coordinate space.
// Bounding box of a single full instance selection, in world coordinates, with no instance scaling applied.
// This bounding box is useful for absolute scaling of tilted objects in world coordinate space.
// Modifiers are NOT taken in account
const BoundingBoxf3& get_unscaled_instance_bounding_box() const;
// Bounding box of a single full instance selection, in world coordinates.
// Modifiers are NOT taken in account
const BoundingBoxf3& get_scaled_instance_bounding_box() const;
#if ENABLE_WORLD_COORDINATE
// Bounding box of a single full instance selection, in world coordinates, with no instance scaling applied.
// Modifiers are taken in account
const BoundingBoxf3& get_full_unscaled_instance_bounding_box() const;
// Bounding box of a single full instance selection, in world coordinates.
// Modifiers are taken in account
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.
// Modifiers are taken in account
const BoundingBoxf3& get_full_unscaled_instance_local_bounding_box() const;
#endif // ENABLE_WORLD_COORDINATE
void setup_cache();
#if ENABLE_WORLD_COORDINATE
void translate(const Vec3d& displacement, TransformationType transformation_type);
#else
void translate(const Vec3d& displacement, bool local = false);
#endif // ENABLE_WORLD_COORDINATE
void rotate(const Vec3d& rotation, TransformationType transformation_type);
void flattening_rotate(const Vec3d& normal);
void scale(const Vec3d& scale, TransformationType transformation_type);
void scale_to_fit_print_volume(const BuildVolume& volume);
void mirror(Axis axis);
#if ENABLE_WORLD_COORDINATE
void scale_and_translate(const Vec3d& scale, const Vec3d& translation, TransformationType transformation_type);
void reset_skew();
#else
void translate(unsigned int object_idx, const Vec3d& displacement);
#endif // ENABLE_WORLD_COORDINATE
void translate(unsigned int object_idx, unsigned int instance_idx, const Vec3d& displacement);
#if ENABLE_WORLD_COORDINATE
// returns:
// -1 if the user refused to proceed with baking when asked
// 0 if the baking was performed
// 1 if no baking was needed
int bake_transform_if_needed() const;
#endif // ENABLE_WORLD_COORDINATE
void erase();
void render(float scale_factor = 1.0);
@ -368,10 +449,23 @@ private:
void do_remove_volume(unsigned int volume_idx);
void do_remove_instance(unsigned int object_idx, unsigned int instance_idx);
void do_remove_object(unsigned int object_idx);
#if ENABLE_WORLD_COORDINATE
void set_bounding_boxes_dirty() {
m_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_local_bounding_box.reset();;
}
#else
void set_bounding_boxes_dirty() { m_bounding_box.reset(); m_unscaled_instance_bounding_box.reset(); m_scaled_instance_bounding_box.reset(); }
#endif // ENABLE_WORLD_COORDINATE
void render_synchronized_volumes();
#if ENABLE_LEGACY_OPENGL_REMOVAL
#if ENABLE_WORLD_COORDINATE
void render_bounding_box(const BoundingBoxf3& box, const Transform3d& trafo, const ColorRGB& color);
#else
void render_bounding_box(const BoundingBoxf3& box, const ColorRGB& color);
#endif // ENABLE_WORLD_COORDINATE
#else
void render_selected_volumes() const;
void render_bounding_box(const BoundingBoxf3& box, float* color) const;
@ -389,11 +483,15 @@ private:
#endif // ENABLE_GL_SHADERS_ATTRIBUTES
public:
enum SyncRotationType {
enum class SyncRotationType {
// 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.
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_volumes();
@ -405,6 +503,11 @@ private:
void paste_volumes_from_clipboard();
void paste_objects_from_clipboard();
#if ENABLE_WORLD_COORDINATE
void transform_volume_relative(GLVolume& volume, const VolumeCache& volume_data, TransformationType transformation_type,
const Transform3d& transform);
#endif // ENABLE_WORLD_COORDINATE
};
} // namespace GUI

View File

@ -581,8 +581,12 @@ void LockButton::OnButton(wxCommandEvent& event)
if (m_disabled)
return;
#if ENABLE_WORLD_COORDINATE
SetLock(!m_is_pushed);
#else
m_is_pushed = !m_is_pushed;
update_button_bitmaps();
#endif // ENABLE_WORLD_COORDINATE
event.Skip();
}