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; 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) 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 angles1 = Vec3d::Zero();
Vec3d angles2 = Vec3d::Zero(); Vec3d angles2 = Vec3d::Zero();
if (std::abs(std::abs(rotation_matrix(2, 0)) - 1.0) < 1e-5) { 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); 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 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); 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; m_dirty = true;
} }
} }
#endif // ENABLE_WORLD_COORDINATE
void Transformation::set_rotation(const Vec3d& rotation) 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(X, rotation.x());
set_rotation(Y, rotation.y()); set_rotation(Y, rotation.y());
set_rotation(Z, rotation.z()); set_rotation(Z, rotation.z());
#endif // ENABLE_WORLD_COORDINATE
} }
void Transformation::set_rotation(Axis axis, double rotation) 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))) if (is_approx(std::abs(rotation), 2.0 * double(PI)))
rotation = 0.0; 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) { if (m_rotation(axis) != rotation) {
m_rotation(axis) = rotation; m_rotation(axis) = rotation;
m_dirty = true; 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) 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(X, scaling_factor.x());
set_scaling_factor(Y, scaling_factor.y()); set_scaling_factor(Y, scaling_factor.y());
set_scaling_factor(Z, scaling_factor.z()); set_scaling_factor(Z, scaling_factor.z());
#endif // ENABLE_WORLD_COORDINATE
} }
void Transformation::set_scaling_factor(Axis axis, double scaling_factor) 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)) { if (m_scaling_factor(axis) != std::abs(scaling_factor)) {
m_scaling_factor(axis) = std::abs(scaling_factor); m_scaling_factor(axis) = std::abs(scaling_factor);
m_dirty = true; 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) 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(X, mirror.x());
set_mirror(Y, mirror.y()); set_mirror(Y, mirror.y());
set_mirror(Z, mirror.z()); set_mirror(Z, mirror.z());
#endif // ENABLE_WORLD_COORDINATE
} }
void Transformation::set_mirror(Axis axis, double mirror) 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) else if (abs_mirror != 1.0)
mirror /= abs_mirror; 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) { if (m_mirror(axis) != mirror) {
m_mirror(axis) = mirror; m_mirror(axis) = mirror;
m_dirty = true; 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) void Transformation::set_from_transform(const Transform3d& transform)
{ {
// offset // offset
@ -493,17 +685,62 @@ void Transformation::set_from_transform(const Transform3d& transform)
// if (!m_matrix.isApprox(transform)) // if (!m_matrix.isApprox(transform))
// std::cout << "something went wrong in extracting data from matrix" << std::endl; // std::cout << "something went wrong in extracting data from matrix" << std::endl;
} }
#endif // ENABLE_WORLD_COORDINATE
void Transformation::reset() void Transformation::reset()
{ {
#if !ENABLE_WORLD_COORDINATE
m_offset = Vec3d::Zero(); m_offset = Vec3d::Zero();
m_rotation = Vec3d::Zero(); m_rotation = Vec3d::Zero();
m_scaling_factor = Vec3d::Ones(); m_scaling_factor = Vec3d::Ones();
m_mirror = Vec3d::Ones(); m_mirror = Vec3d::Ones();
#endif // !ENABLE_WORLD_COORDINATE
m_matrix = Transform3d::Identity(); m_matrix = Transform3d::Identity();
#if !ENABLE_WORLD_COORDINATE
m_dirty = false; 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 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)) { 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; return m_matrix;
} }
#endif // ENABLE_WORLD_COORDINATE
Transformation Transformation::operator * (const Transformation& other) const Transformation Transformation::operator * (const Transformation& other) const
{ {
return Transformation(get_matrix() * other.get_matrix()); 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 Transformation::volume_to_bed_transformation(const Transformation& instance_transformation, const BoundingBoxf3& bbox)
{ {
Transformation out; 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_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)); 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. // 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. // 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. // Scale it to get the required size.
@ -581,6 +819,7 @@ Transformation Transformation::volume_to_bed_transformation(const Transformation
return out; return out;
} }
#endif // !ENABLE_WORLD_COORDINATE
// For parsing a transformation matrix from 3MF / AMF. // For parsing a transformation matrix from 3MF / AMF.
Transform3d transform3d_from_string(const std::string& transform_str) 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) double rotation_diff_z(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to)
{ {
const Eigen::AngleAxisd angle_axis(rotation_xyz_diff(rot_xyz_from, rot_xyz_to)); const Eigen::AngleAxisd angle_axis(rotation_xyz_diff(rot_xyz_from, rot_xyz_to));
const Vec3d axis = angle_axis.axis(); const Vec3d& axis = angle_axis.axis();
const double angle = angle_axis.angle(); const double angle = angle_axis.angle();
#ifndef NDEBUG #ifndef NDEBUG
if (std::abs(angle) > 1e-8) { if (std::abs(angle) > 1e-8) {

View File

@ -323,7 +323,8 @@ bool arrange(
// 4) rotate Y // 4) rotate Y
// 5) rotate Z // 5) rotate Z
// 6) translate // 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: // Returns the transform obtained by assembling the given transformations in the following order:
// 1) mirror // 1) mirror
@ -332,7 +333,43 @@ void assemble_transform(Transform3d& transform, const Vec3d& translation = Vec3d
// 4) rotate Y // 4) rotate Y
// 5) rotate Z // 5) rotate Z
// 6) translate // 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 // Returns the euler angles extracted from the given rotation matrix
// Warning -> The matrix should not contain any scale or shear !!! // Warning -> The matrix should not contain any scale or shear !!!
@ -344,6 +381,9 @@ Vec3d extract_euler_angles(const Transform3d& transform);
class Transformation class Transformation
{ {
#if ENABLE_WORLD_COORDINATE
Transform3d m_matrix{ Transform3d::Identity() };
#else
struct Flags struct Flags
{ {
bool dont_translate{ true }; bool dont_translate{ true };
@ -363,8 +403,26 @@ class Transformation
mutable Transform3d m_matrix{ Transform3d::Identity() }; mutable Transform3d m_matrix{ Transform3d::Identity() };
mutable Flags m_flags; mutable Flags m_flags;
mutable bool m_dirty{ false }; mutable bool m_dirty{ false };
#endif // ENABLE_WORLD_COORDINATE
public: 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(); Transformation();
explicit Transformation(const Transform3d& transform); explicit Transformation(const Transform3d& transform);
@ -376,47 +434,103 @@ public:
const Vec3d& get_rotation() const { return m_rotation; } const Vec3d& get_rotation() const { return m_rotation; }
double get_rotation(Axis axis) const { return m_rotation(axis); } double get_rotation(Axis axis) const { return m_rotation(axis); }
#endif // ENABLE_WORLD_COORDINATE
void set_rotation(const Vec3d& rotation); void set_rotation(const Vec3d& rotation);
void set_rotation(Axis axis, double 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; } const Vec3d& get_scaling_factor() const { return m_scaling_factor; }
double get_scaling_factor(Axis axis) const { return m_scaling_factor(axis); } 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(const Vec3d& scaling_factor);
void set_scaling_factor(Axis axis, double 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; } 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; } const Vec3d& get_mirror() const { return m_mirror; }
double get_mirror(Axis axis) const { return m_mirror(axis); } 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.; } 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(const Vec3d& mirror);
void set_mirror(Axis axis, double mirror); void set_mirror(Axis axis, double mirror);
#if ENABLE_WORLD_COORDINATE
bool has_skew() const;
#else
void set_from_transform(const Transform3d& transform); void set_from_transform(const Transform3d& transform);
#endif // ENABLE_WORLD_COORDINATE
void reset(); 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; 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; 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 // 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. // 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. // 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); static Transformation volume_to_bed_transformation(const Transformation& instance_transformation, const BoundingBoxf3& bbox);
#endif // !ENABLE_WORLD_COORDINATE
private: private:
friend class cereal::access; friend class cereal::access;
template<class Archive> void serialize(Archive & ar) { ar(m_offset, m_rotation, m_scaling_factor, m_mirror); } #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) {} explicit Transformation(int) : m_dirty(true) {}
template <class Archive> static void load_and_construct(Archive &ar, cereal::construct<Transformation> &construct) 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. // Calling a private constructor with special "int" parameter to indicate that no construction is necessary.
construct(1); construct(1);
ar(construct.ptr()->m_offset, construct.ptr()->m_rotation, construct.ptr()->m_scaling_factor, construct.ptr()->m_mirror); 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. // 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()) if (this->instances.empty())
throw Slic3r::InvalidArgument("Can't call raw_bounding_box() with no instances"); 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); const Transform3d& inst_matrix = this->instances.front()->get_transformation().get_matrix(true);
#endif // ENABLE_WORLD_COORDINATE
for (const ModelVolume *v : this->volumes) for (const ModelVolume *v : this->volumes)
if (v->is_model_part()) if (v->is_model_part())
m_raw_bounding_box.merge(v->mesh().transformed_bounding_box(inst_matrix * v->get_matrix())); 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 ModelObject::instance_bounding_box(size_t instance_idx, bool dont_translate) const
{ {
BoundingBoxf3 bb; 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); 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()) if (v->is_model_part())
bb.merge(v->mesh().transformed_bounding_box(inst_matrix * v->get_matrix())); 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); new_object->add_instance(*model_instance);
ModelVolume* new_vol = new_object->add_volume(*volume, std::move(mesh)); 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(); 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); 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()); assert(instance_idx < this->instances.size());
const Geometry::Transformation reference_trafo = this->instances[instance_idx]->get_transformation(); 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())) 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. // nothing to do, scaling in the world coordinate space is possible in the representation of Geometry::Transformation.
return; return;
#endif // !ENABLE_WORLD_COORDINATE
bool left_handed = reference_trafo.is_left_handed(); bool left_handed = reference_trafo.is_left_handed();
bool has_mirrorring = ! reference_trafo.get_mirror().isApprox(Vec3d(1., 1., 1.)); 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. // Adjust the meshes.
// Transformation to be applied to 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); 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(); Transform3d volume_offset_correction = this->instances[instance_idx]->get_transformation().get_matrix().inverse() * reference_trafo.get_matrix();
for (ModelVolume *model_volume : this->volumes) { for (ModelVolume *model_volume : this->volumes) {
const Geometry::Transformation volume_trafo = model_volume->get_transformation(); 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; 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.; double volume_new_scaling_factor = volume_uniform_scaling ? volume_trafo.get_scaling_factor().x() : 1.;
// Transform the mesh. // 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); 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> // Following method creates a new shared_ptr<TriangleMesh>
model_volume->transform_this_mesh(mesh_trafo_3x3 * volume_trafo_3x3, left_handed != volume_left_handed); model_volume->transform_this_mesh(mesh_trafo_3x3 * volume_trafo_3x3, left_handed != volume_left_handed);
// Reset the rotation, scaling and mirroring. // 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; double min_z = DBL_MAX;
const ModelInstance* inst = instances[instance_idx]; 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); const Transform3d& mi = inst->get_matrix(true);
#endif // ENABLE_WORLD_COORDINATE
for (const ModelVolume* v : volumes) { for (const ModelVolume* v : volumes) {
if (!v->is_model_part()) 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; double max_z = -DBL_MAX;
const ModelInstance* inst = instances[instance_idx]; 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); const Transform3d& mi = inst->get_matrix(true);
#endif // ENABLE_WORLD_COORDINATE
for (const ModelVolume* v : volumes) { for (const ModelVolume* v : volumes) {
if (!v->is_model_part()) if (!v->is_model_part())
@ -1936,14 +1979,22 @@ void ModelVolume::convert_from_meters()
void ModelInstance::transform_mesh(TriangleMesh* mesh, bool dont_translate) const 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)); mesh->transform(get_matrix(dont_translate));
#endif // ENABLE_WORLD_COORDINATE
} }
BoundingBoxf3 ModelInstance::transform_mesh_bounding_box(const TriangleMesh& mesh, bool dont_translate) const BoundingBoxf3 ModelInstance::transform_mesh_bounding_box(const TriangleMesh& mesh, bool dont_translate) const
{ {
// Rotate around mesh origin. // Rotate around mesh origin.
TriangleMesh copy(mesh); TriangleMesh copy(mesh);
#if ENABLE_WORLD_COORDINATE
copy.transform(get_transformation().get_rotation_matrix());
#else
copy.transform(get_matrix(true, false, true, true)); copy.transform(get_matrix(true, false, true, true));
#endif // ENABLE_WORLD_COORDINATE
BoundingBoxf3 bbox = copy.bounding_box(); BoundingBoxf3 bbox = copy.bounding_box();
if (!empty(bbox)) { 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 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)); return bbox.transformed(get_matrix(dont_translate));
#endif // ENABLE_WORLD_COORDINATE
} }
Vec3d ModelInstance::transform_vector(const Vec3d& v, bool dont_translate) const 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; return get_matrix(dont_translate) * v;
#endif // ENABLE_WORLD_COORDINATE
} }
void ModelInstance::transform_polygon(Polygon* polygon) const void ModelInstance::transform_polygon(Polygon* polygon) const

View File

@ -691,15 +691,26 @@ public:
const Geometry::Transformation& get_transformation() const { return m_transformation; } const Geometry::Transformation& get_transformation() const { return m_transformation; }
void set_transformation(const Geometry::Transformation& transformation) { m_transformation = 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); } void set_transformation(const Transform3d &trafo) { m_transformation.set_from_transform(trafo); }
const Vec3d& get_offset() const { return m_transformation.get_offset(); } 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); } 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(const Vec3d& offset) { m_transformation.set_offset(offset); }
void set_offset(Axis axis, double offset) { m_transformation.set_offset(axis, 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(); } 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); } 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(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(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); } 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(); } 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); } double get_mirror(Axis axis) const { return m_transformation.get_mirror(axis); }
bool is_left_handed() const { return m_transformation.is_left_handed(); } bool is_left_handed() const { return m_transformation.is_left_handed(); }
@ -720,7 +735,12 @@ public:
void convert_from_imperial_units(); void convert_from_imperial_units();
void convert_from_meters(); 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); } 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() { void set_new_unique_id() {
ObjectBase::set_new_unique_id(); ObjectBase::set_new_unique_id();
@ -923,25 +943,41 @@ public:
const Geometry::Transformation& get_transformation() const { return m_transformation; } const Geometry::Transformation& get_transformation() const { return m_transformation; }
void set_transformation(const Geometry::Transformation& transformation) { m_transformation = 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(); } 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); } 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(const Vec3d& offset) { m_transformation.set_offset(offset); }
void set_offset(Axis axis, double offset) { m_transformation.set_offset(axis, 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(); } 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); } 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(const Vec3d& rotation) { m_transformation.set_rotation(rotation); }
void set_rotation(Axis axis, double rotation) { m_transformation.set_rotation(axis, 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(); } 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); } 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(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); } 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(); } 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); } double get_mirror(Axis axis) const { return m_transformation.get_mirror(axis); }
bool is_left_handed() const { return m_transformation.is_left_handed(); } 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. // To be called on an external polygon. It does not translate the polygon, only rotates and scales.
void transform_polygon(Polygon* polygon) const; 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); } 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); } 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 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); } 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: // 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()) if (it != volumes_old.end() && it->volume_id == model_volume->id())
layer_range.volumes.emplace_back(*it); layer_range.volumes.emplace_back(*it);
} else } 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(), 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) }); transformed_its_bbox2d(model_volume->mesh().its, trafo_for_bbox(object_trafo, model_volume->get_matrix(false)), offset) });
#endif // ENABLE_WORLD_COORDINATE
} }
} else { } else {
std::vector<std::vector<PrintObjectRegions::VolumeExtents>> volumes_old; std::vector<std::vector<PrintObjectRegions::VolumeExtents>> volumes_old;
@ -823,7 +828,11 @@ void update_volume_bboxes(
layer_range.volumes.emplace_back(*it); layer_range.volumes.emplace_back(*it);
} }
} else { } 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); 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) for (PrintObjectRegions::LayerRangeRegions &layer_range : layer_ranges)
if (auto &bbox = bboxes[&layer_range - layer_ranges.data()]; bbox.second) if (auto &bbox = bboxes[&layer_range - layer_ranges.data()]; bbox.second)
layer_range.volumes.push_back({ model_volume->id(), bbox.first }); 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) #define ENABLE_SHOW_TOOLPATHS_COG (1 && ENABLE_2_5_0_ALPHA1)
// Enable recalculating toolpaths when switching to/from volumetric rate visualization // Enable recalculating toolpaths when switching to/from volumetric rate visualization
#define ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC (1 && ENABLE_2_5_0_ALPHA1) #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 // Enable modified camera control using mouse
#define ENABLE_NEW_CAMERA_MOVEMENTS (1 && ENABLE_2_5_0_ALPHA1) #define ENABLE_NEW_CAMERA_MOVEMENTS (1 && ENABLE_2_5_0_ALPHA1)
// Enable modified rectangle selection // Enable modified rectangle selection

View File

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

View File

@ -102,6 +102,7 @@ const float* GeometryBuffer::get_vertices_data() const
} }
#endif // !ENABLE_LEGACY_OPENGL_REMOVAL #endif // !ENABLE_LEGACY_OPENGL_REMOVAL
#if !ENABLE_WORLD_COORDINATE
const float Bed3D::Axes::DefaultStemRadius = 0.5f; const float Bed3D::Axes::DefaultStemRadius = 0.5f;
const float Bed3D::Axes::DefaultStemLength = 25.0f; const float Bed3D::Axes::DefaultStemLength = 25.0f;
const float Bed3D::Axes::DefaultTipRadius = 2.5f * Bed3D::Axes::DefaultStemRadius; const float Bed3D::Axes::DefaultTipRadius = 2.5f * Bed3D::Axes::DefaultStemRadius;
@ -179,6 +180,7 @@ void Bed3D::Axes::render()
glsafe(::glDisable(GL_DEPTH_TEST)); 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) 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; out.max.z() = 0.0;
// extend to contain axes // extend to contain axes
out.merge(m_axes.get_origin() + m_axes.get_total_length() * Vec3d::Ones()); 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())); out.merge(out.min + Vec3d(-Axes::DefaultTipRadius, -Axes::DefaultTipRadius, out.max.z()));
#endif // ENABLE_WORLD_COORDINATE
// extend to contain model, if any // extend to contain model, if any
BoundingBoxf3 model_bb = m_model.get_bounding_box(); BoundingBoxf3 model_bb = m_model.get_bounding_box();
if (model_bb.defined) { 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() void Bed3D::render_axes()
{ {
if (m_build_volume.valid()) 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(); m_axes.render();
#endif // ENABLE_WORLD_COORDINATE
} }
#if ENABLE_GL_SHADERS_ATTRIBUTES #if ENABLE_GL_SHADERS_ATTRIBUTES

View File

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

View File

@ -432,14 +432,23 @@ public:
const Geometry::Transformation& get_instance_transformation() const { return m_instance_transformation; } 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(); } 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(); } 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); } 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(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(); } 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(); } 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); } 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(); } 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(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(); } 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(); } 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); } 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(); } 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; } 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(); } 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(); } 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); } 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(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(); } 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(); } 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); } 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(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(); } 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(); } 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); } 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(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(); } 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(); } 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); } 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(); } 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_INCREASE_INSTANCES, Event<int>);
wxDEFINE_EVENT(EVT_GLCANVAS_INSTANCE_MOVED, SimpleEvent); wxDEFINE_EVENT(EVT_GLCANVAS_INSTANCE_MOVED, SimpleEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_INSTANCE_ROTATED, 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_INSTANCE_SCALED, SimpleEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_FORCE_UPDATE, SimpleEvent); wxDEFINE_EVENT(EVT_GLCANVAS_FORCE_UPDATE, SimpleEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_WIPETOWER_MOVED, Vec3dEvent); wxDEFINE_EVENT(EVT_GLCANVAS_WIPETOWER_MOVED, Vec3dEvent);
@ -2914,7 +2917,13 @@ void GLCanvas3D::on_key(wxKeyEvent& evt)
else else
displacement = multiplier * direction; 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); m_selection.translate(displacement);
#endif // ENABLE_WORLD_COORDINATE
m_dirty = true; 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); 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) if (current_printer_technology() == ptFFF && fff_print()->config().complete_objects)
update_sequential_clearance(); update_sequential_clearance();
wxGetApp().obj_manipul()->set_dirty(); 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]; ModelObject* model_object = m_model->objects[object_idx];
if (model_object != nullptr) { if (model_object != nullptr) {
if (selection_mode == Selection::Instance) 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()); model_object->instances[instance_idx]->set_offset(v->get_instance_offset());
#endif // ENABLE_WORLD_COORDINATE
else if (selection_mode == Selection::Volume) 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()); model_object->volumes[volume_idx]->set_offset(v->get_volume_offset());
#endif // ENABLE_WORLD_COORDINATE
object_moved = true; object_moved = true;
model_object->invalidate_bounding_box(); model_object->invalidate_bounding_box();
@ -3907,8 +3930,8 @@ void GLCanvas3D::do_rotate(const std::string& snapshot_type)
int object_idx = v->object_idx(); int object_idx = v->object_idx();
if (object_idx == 1000) { // the wipe tower if (object_idx == 1000) { // the wipe tower
#endif // ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL #endif // ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
Vec3d offset = v->get_volume_offset(); const Vec3d offset = v->get_volume_offset();
post_event(Vec3dEvent(EVT_GLCANVAS_WIPETOWER_ROTATED, Vec3d(offset(0), offset(1), v->get_volume_rotation()(2)))); post_event(Vec3dEvent(EVT_GLCANVAS_WIPETOWER_ROTATED, Vec3d(offset.x(), offset.y(), v->get_volume_rotation().z())));
} }
#if ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL #if ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
int object_idx = v->object_idx(); 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) if (object_idx < 0 || (int)m_model->objects.size() <= object_idx)
continue; continue;
int instance_idx = v->instance_idx(); const int instance_idx = v->instance_idx();
int volume_idx = v->volume_idx(); const int volume_idx = v->volume_idx();
done.insert(std::pair<int, int>(object_idx, instance_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]; ModelObject* model_object = m_model->objects[object_idx];
if (model_object != nullptr) { if (model_object != nullptr) {
if (selection_mode == Selection::Instance) { 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_rotation(v->get_instance_rotation());
model_object->instances[instance_idx]->set_offset(v->get_instance_offset()); model_object->instances[instance_idx]->set_offset(v->get_instance_offset());
#endif // ENABLE_WORLD_COORDINATE
} }
else if (selection_mode == Selection::Volume) { 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_rotation(v->get_volume_rotation());
model_object->volumes[volume_idx]->set_offset(v->get_volume_offset()); model_object->volumes[volume_idx]->set_offset(v->get_volume_offset());
#endif // ENABLE_WORLD_COORDINATE
} }
model_object->invalidate_bounding_box(); 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(); Selection::EMode selection_mode = m_selection.get_mode();
for (const GLVolume* v : m_volumes.volumes) { 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) if (object_idx < 0 || (int)m_model->objects.size() <= object_idx)
continue; continue;
int instance_idx = v->instance_idx(); const int instance_idx = v->instance_idx();
int volume_idx = v->volume_idx(); const int volume_idx = v->volume_idx();
done.insert(std::pair<int, int>(object_idx, instance_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]; ModelObject* model_object = m_model->objects[object_idx];
if (model_object != nullptr) { if (model_object != nullptr) {
if (selection_mode == Selection::Instance) { 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_scaling_factor(v->get_instance_scaling_factor());
model_object->instances[instance_idx]->set_offset(v->get_instance_offset()); model_object->instances[instance_idx]->set_offset(v->get_instance_offset());
#endif // ENABLE_WORLD_COORDINATE
} }
else if (selection_mode == Selection::Volume) { 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->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_scaling_factor(v->get_volume_scaling_factor());
model_object->volumes[volume_idx]->set_offset(v->get_volume_offset()); model_object->volumes[volume_idx]->set_offset(v->get_volume_offset());
#endif // ENABLE_WORLD_COORDINATE
} }
model_object->invalidate_bounding_box(); model_object->invalidate_bounding_box();
} }
@ -4008,10 +4048,10 @@ void GLCanvas3D::do_scale(const std::string& snapshot_type)
// Fixes sinking/flying instances // Fixes sinking/flying instances
for (const std::pair<int, int>& i : done) { for (const std::pair<int, int>& i : done) {
ModelObject* m = m_model->objects[i.first]; 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 // 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) { 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_selection.translate(i.first, i.second, shift);
m->translate_instance(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]; ModelObject* model_object = m_model->objects[object_idx];
if (model_object != nullptr) { if (model_object != nullptr) {
if (selection_mode == Selection::Instance) 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()); model_object->instances[instance_idx]->set_mirror(v->get_instance_mirror());
#endif // ENABLE_WORLD_COORDINATE
else if (selection_mode == Selection::Volume) 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()); model_object->volumes[volume_idx]->set_mirror(v->get_volume_mirror());
#endif // ENABLE_WORLD_COORDINATE
model_object->invalidate_bounding_box(); model_object->invalidate_bounding_box();
} }
@ -4087,6 +4135,44 @@ void GLCanvas3D::do_mirror(const std::string& snapshot_type)
m_dirty = true; 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() void GLCanvas3D::update_gizmos_on_off_state()
{ {
set_as_dirty(); 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_FORCE_UPDATE, SimpleEvent);
wxDECLARE_EVENT(EVT_GLCANVAS_WIPETOWER_MOVED, Vec3dEvent); wxDECLARE_EVENT(EVT_GLCANVAS_WIPETOWER_MOVED, Vec3dEvent);
wxDECLARE_EVENT(EVT_GLCANVAS_INSTANCE_ROTATED, SimpleEvent); 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_INSTANCE_SCALED, SimpleEvent);
wxDECLARE_EVENT(EVT_GLCANVAS_WIPETOWER_ROTATED, Vec3dEvent); wxDECLARE_EVENT(EVT_GLCANVAS_WIPETOWER_ROTATED, Vec3dEvent);
wxDECLARE_EVENT(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, Event<bool>); wxDECLARE_EVENT(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, Event<bool>);
@ -739,7 +742,11 @@ public:
void update_volumes_colors_by_extruder(); 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; } bool is_dragging() const { return m_gizmos.is_dragging() || m_moving; }
#endif // ENABLE_WORLD_COORDINATE
void render(); void render();
// printable_only == false -> render also non printable volumes as grayed // 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_rotate(const std::string& snapshot_type);
void do_scale(const std::string& snapshot_type); void do_scale(const std::string& snapshot_type);
void do_mirror(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 update_gizmos_on_off_state();
void reset_all_gizmos() { m_gizmos.reset_all_states(); } 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); 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. // 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(); 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(); const Transform3d inv_inst_transform = inst_transform.get_matrix(true).inverse();
#endif // ENABLE_WORLD_COORDINATE
const Vec3d instance_offset = v->get_instance_offset(); const Vec3d instance_offset = v->get_instance_offset();
for (size_t i = 0; i < input_files.size(); ++i) { 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; new_volume->source.mesh_offset = model.objects.front()->volumes.front()->source.mesh_offset;
if (from_galery) { 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. // Transform the new modifier to be aligned with the print bed.
const BoundingBoxf3 mesh_bb = new_volume->mesh().bounding_box(); const BoundingBoxf3 mesh_bb = new_volume->mesh().bounding_box();
new_volume->set_transformation(Geometry::Transformation::volume_to_bed_transformation(inst_transform, mesh_bb)); new_volume->set_transformation(Geometry::Transformation::volume_to_bed_transformation(inst_transform, mesh_bb));
#endif // ENABLE_WORLD_COORDINATE
// Set the modifier position. // 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. // 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; 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); 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. // 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. // Transform the new modifier to be aligned with the print bed.
const BoundingBoxf3 mesh_bb = new_volume->mesh().bounding_box(); 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)); new_volume->set_transformation(Geometry::Transformation::volume_to_bed_transformation(v->get_instance_transformation(), mesh_bb));
#endif // ENABLE_WORLD_COORDINATE
// Set the modifier position. // Set the modifier position.
auto offset = (type_name == "Slab") ? auto offset = (type_name == "Slab") ?
// Slab: Lift to print bed // Slab: Lift to print bed
Vec3d(0., 0., 0.5 * mesh_bb.size().z() + instance_bb.min.z() - v->get_instance_offset().z()) : 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. // 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(); 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); new_volume->set_offset(v->get_instance_transformation().get_matrix(true).inverse() * offset);
#endif // ENABLE_WORLD_COORDINATE
const wxString name = _L("Generic") + "-" + _(type_name); const wxString name = _L("Generic") + "-" + _(type_name);
new_volume->name = into_u8(name); new_volume->name = into_u8(name);
@ -2545,7 +2565,13 @@ void ObjectList::part_selection_changed()
Sidebar& panel = wxGetApp().sidebar(); Sidebar& panel = wxGetApp().sidebar();
panel.Freeze(); 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); wxGetApp().plater()->canvas3D()->handle_sidebar_focus_event("", false);
#endif // ENABLE_WORLD_COORDINATE
wxGetApp().obj_manipul() ->UpdateAndShow(update_and_show_manipulations); wxGetApp().obj_manipul() ->UpdateAndShow(update_and_show_manipulations);
wxGetApp().obj_settings()->UpdateAndShow(update_and_show_settings); wxGetApp().obj_settings()->UpdateAndShow(update_and_show_settings);
wxGetApp().obj_layers() ->UpdateAndShow(update_and_show_layers); wxGetApp().obj_layers() ->UpdateAndShow(update_and_show_layers);
@ -3263,8 +3289,12 @@ void ObjectList::update_selections()
return; return;
sels.Add(m_objects_model->GetItemById(selection.get_object_idx())); 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()) { 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()) if (m_objects_model->GetVolumeIdByItem(m_objects_model->GetParent(item)) == gl_vol->volume_idx())
return; return;
} }

View File

@ -52,10 +52,17 @@ static choice_ctrl* create_word_local_combo(wxWindow *parent)
temp->SetFont(Slic3r::GUI::wxGetApp().normal_font()); temp->SetFont(Slic3r::GUI::wxGetApp().normal_font());
if (!wxOSX) temp->SetBackgroundStyle(wxBG_STYLE_PAINT); 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("World coordinates"));
temp->Append(_L("Local coordinates")); temp->Append(_L("Local coordinates"));
temp->SetSelection(0); temp->SetSelection(0);
temp->SetValue(temp->GetString(0)); temp->SetValue(temp->GetString(0));
#endif // ENABLE_WORLD_COORDINATE
temp->SetToolTip(_L("Select coordinate space, in which the transformation will be performed.")); temp->SetToolTip(_L("Select coordinate space, in which the transformation will be performed."));
return temp; return temp;
@ -81,8 +88,14 @@ void msw_rescale_word_local_combo(choice_ctrl* combo)
// Set rescaled size // Set rescaled size
combo->SetSize(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("World coordinates"));
combo->Append(_L("Local coordinates")); combo->Append(_L("Local coordinates"));
#endif // ENABLE_WORLD_COORDINATE
combo->SetValue(selection); combo->SetValue(selection);
#else #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_text[] = { "#990000", "#009900", "#000099" };
static const wxString axes_color_back[] = { "#f5dcdc", "#dcf5dc", "#dcdcf5" }; static const wxString axes_color_back[] = { "#f5dcdc", "#dcf5dc", "#dcdcf5" };
ObjectManipulation::ObjectManipulation(wxWindow* parent) : ObjectManipulation::ObjectManipulation(wxWindow* parent) :
OG_Settings(parent, true) OG_Settings(parent, true)
{ {
@ -157,7 +171,11 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
// Add world local combobox // Add world local combobox
m_word_local_combo = create_word_local_combo(parent); m_word_local_combo = create_word_local_combo(parent);
m_word_local_combo->Bind(wxEVT_COMBOBOX, ([this](wxCommandEvent& evt) { 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); this->set_world_coordinates(evt.GetSelection() != 1);
#endif // ENABLE_WORLD_COORDINATE
}), m_word_local_combo->GetId()); }), m_word_local_combo->GetId());
// Small trick to correct layouting in different view_mode : // Small trick to correct layouting in different view_mode :
@ -264,8 +282,12 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D(); GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
Selection& selection = canvas->get_selection(); 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()) { 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)); volume->set_volume_mirror(axis, -volume->get_volume_mirror(axis));
} }
else if (selection.is_single_full_instance()) { else if (selection.is_single_full_instance()) {
@ -278,7 +300,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
return; return;
// Update mirroring at the GLVolumes. // Update mirroring at the GLVolumes.
selection.synchronize_unselected_instances(Selection::SYNC_ROTATION_GENERAL); selection.synchronize_unselected_instances(Selection::SyncRotationType::GENERAL);
selection.synchronize_unselected_volumes(); selection.synchronize_unselected_volumes();
// Copy mirroring values from GLVolumes into Model (ModelInstance / ModelVolume), trigger background processing. // Copy mirroring values from GLVolumes into Model (ModelInstance / ModelVolume), trigger background processing.
canvas->do_mirror(L("Set Mirror")); canvas->do_mirror(L("Set Mirror"));
@ -327,28 +349,60 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D(); GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
Selection& selection = canvas->get_selection(); Selection& selection = canvas->get_selection();
if (selection.is_single_volume() || selection.is_single_modifier()) { #if ENABLE_WORLD_COORDINATE
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); if (selection.is_single_volume_or_modifier()) {
const GLVolume* volume = selection.get_first_volume();
const Geometry::Transformation& instance_trafo = volume->get_instance_transformation(); const double min_z = get_volume_min_z(*volume);
const Vec3d diff = m_cache.position - instance_trafo.get_matrix(true).inverse() * Vec3d(0., 0., 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")); Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Drop to bed"));
change_position_value(0, diff.x()); change_position_value(0, diff.x());
change_position_value(1, diff.y()); change_position_value(1, diff.y());
change_position_value(2, diff.z()); 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()) { 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 ModelObjectPtrs& objects = wxGetApp().model().objects;
const int idx = selection.get_object_idx(); const int idx = selection.get_object_idx();
if (0 <= idx && idx < static_cast<int>(objects.size())) { if (0 <= idx && idx < static_cast<int>(objects.size())) {
const ModelObject* mo = wxGetApp().model().objects[idx]; const ModelObject* mo = wxGetApp().model().objects[idx];
const double min_z = mo->bounding_box().min.z(); const double min_z = mo->bounding_box().min.z();
if (std::abs(min_z) > SINKING_Z_THRESHOLD) { if (std::abs(min_z) > SINKING_Z_THRESHOLD) {
#endif // ENABLE_WORLD_COORDINATE
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Drop to bed")); Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Drop to bed"));
change_position_value(2, m_cache.position.z() - min_z); 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); editors_grid_sizer->Add(m_drop_to_bed_button);
@ -365,21 +419,22 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D(); GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
Selection& selection = canvas->get_selection(); Selection& selection = canvas->get_selection();
if (selection.is_single_volume() || selection.is_single_modifier()) { #if ENABLE_WORLD_COORDINATE
GLVolume* volume = const_cast<GLVolume*>(selection.get_volume(*selection.get_volume_idxs().begin())); if (selection.is_single_volume_or_modifier())
volume->set_volume_rotation(Vec3d::Zero()); #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()) { else if (selection.is_single_full_instance()) {
for (unsigned int idx : selection.get_volume_idxs()) { for (unsigned int idx : selection.get_volume_idxs()) {
GLVolume* volume = const_cast<GLVolume*>(selection.get_volume(idx)); const_cast<GLVolume*>(selection.get_volume(idx))->set_instance_rotation(Vec3d::Zero());
volume->set_instance_rotation(Vec3d::Zero());
} }
} }
else else
return; return;
// Update rotation at the GLVolumes. // Update rotation at the GLVolumes.
selection.synchronize_unselected_instances(Selection::SYNC_ROTATION_GENERAL); selection.synchronize_unselected_instances(Selection::SyncRotationType::GENERAL);
selection.synchronize_unselected_volumes(); selection.synchronize_unselected_volumes();
// Copy rotation values from GLVolumes into Model (ModelInstance / ModelVolume), trigger background processing. // Copy rotation values from GLVolumes into Model (ModelInstance / ModelVolume), trigger background processing.
canvas->do_rotate(L("Reset Rotation")); canvas->do_rotate(L("Reset Rotation"));
@ -397,10 +452,28 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
m_reset_scale_button = new ScalableButton(parent, wxID_ANY, ScalableBitmap(parent, "undo")); m_reset_scale_button = new ScalableButton(parent, wxID_ANY, ScalableBitmap(parent, "undo"));
m_reset_scale_button->SetToolTip(_L("Reset scale")); m_reset_scale_button->SetToolTip(_L("Reset scale"));
m_reset_scale_button->Bind(wxEVT_BUTTON, [this](wxCommandEvent& e) { 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")); Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Reset scale"));
change_scale_value(0, 100.); change_scale_value(0, 100.);
change_scale_value(1, 100.); change_scale_value(1, 100.);
change_scale_value(2, 100.); change_scale_value(2, 100.);
#endif // ENABLE_WORLD_COORDINATE
}); });
editors_grid_sizer->Add(m_reset_scale_button); 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); 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 = new wxCheckBox(parent, wxID_ANY, _L("Inches"));
m_check_inch->SetFont(wxGetApp().normal_font()); m_check_inch->SetFont(wxGetApp().normal_font());
@ -444,7 +536,26 @@ void ObjectManipulation::Show(const bool show)
if (show) { if (show) {
// Show the "World Coordinates" / "Local Coordintes" Combo in Advanced / Expert mode only. // 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; 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_word_local_combo->Show(show_world_local_combo);
m_empty_str->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); 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"; m_use_colors = wxGetApp().app_config->get("color_mapinulation_panel") == "1";
// update colors for edit-boxes // update colors for edit-boxes
int axis_id = 0; 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_rotate_label_string = L("Rotation");
m_new_scale_label_string = L("Scale factors"); m_new_scale_label_string = L("Scale factors");
#if !ENABLE_WORLD_COORDINATE
if (wxGetApp().get_mode() == comSimple) if (wxGetApp().get_mode() == comSimple)
m_world_coordinates = true; m_world_coordinates = true;
#endif // !ENABLE_WORLD_COORDINATE
ObjectList* obj_list = wxGetApp().obj_list(); ObjectList* obj_list = wxGetApp().obj_list();
if (selection.is_single_full_instance()) { 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 // 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(); 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. // 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_uniform_scale = true;
m_lock_bnt->SetLock(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) { if (m_world_coordinates) {
#endif // ENABLE_WORLD_COORDINATE
m_new_rotate_label_string = L("Rotate"); m_new_rotate_label_string = L("Rotate");
m_new_rotation = Vec3d::Zero(); m_new_rotation = Vec3d::Zero();
m_new_size = selection.get_scaled_instance_bounding_box().size(); 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 { 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_size = volume->get_instance_scaling_factor().cwiseProduct(wxGetApp().model().objects[volume->object_idx()]->raw_mesh_bounding_box().size());
m_new_scale = volume->get_instance_scaling_factor() * 100.; m_new_scale = volume->get_instance_scaling_factor() * 100.0;
} }
m_new_enabled = true; m_new_enabled = true;
@ -557,19 +683,52 @@ void ObjectManipulation::update_settings_value(const Selection& selection)
const BoundingBoxf3& box = selection.get_bounding_box(); const BoundingBoxf3& box = selection.get_bounding_box();
m_new_position = box.center(); m_new_position = box.center();
m_new_rotation = Vec3d::Zero(); m_new_rotation = Vec3d::Zero();
m_new_scale = Vec3d(100., 100., 100.); m_new_scale = Vec3d(100.0, 100.0, 100.0);
m_new_size = box.size(); m_new_size = box.size();
m_new_rotate_label_string = L("Rotate"); m_new_rotate_label_string = L("Rotate");
m_new_scale_label_string = L("Scale"); m_new_scale_label_string = L("Scale");
m_new_enabled = true; 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()) { else if (selection.is_single_modifier() || selection.is_single_volume()) {
#endif // ENABLE_WORLD_COORDINATE
// the selection contains a single volume // 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_position = volume->get_volume_offset();
m_new_rotation = volume->get_volume_rotation() * (180. / M_PI); m_new_rotate_label_string = L("Rotate");
m_new_scale = volume->get_volume_scaling_factor() * 100.; 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())); 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; m_new_enabled = true;
} }
else if (obj_list->multiple_selection() || obj_list->is_selected(itInstanceRoot)) { 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); update(m_cache.rotation, m_cache.rotation_rounded, meRotation, m_new_rotation);
} }
#if !ENABLE_WORLD_COORDINATE
if (selection.requires_uniform_scale()) { if (selection.requires_uniform_scale()) {
m_lock_bnt->SetLock(true); 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->SetToolTip(_L("You cannot use non-uniform scaling mode for multiple objects/parts selection"));
m_lock_bnt->disable(); m_lock_bnt->disable();
} }
else { else {
#endif // !ENABLE_WORLD_COORDINATE
m_lock_bnt->SetLock(m_uniform_scale); m_lock_bnt->SetLock(m_uniform_scale);
m_lock_bnt->SetToolTip(wxEmptyString); m_lock_bnt->SetToolTip(wxEmptyString);
m_lock_bnt->enable(); 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) if (m_word_local_combo->GetSelection() != new_selection)
m_word_local_combo->SetSelection(new_selection); m_word_local_combo->SetSelection(new_selection);
} }
#endif // !ENABLE_WORLD_COORDINATE
if (m_new_enabled) if (m_new_enabled)
m_og->enable(); m_og->enable();
@ -677,29 +840,75 @@ void ObjectManipulation::update_reset_buttons_visibility()
bool show_rotation = false; bool show_rotation = false;
bool show_scale = false; bool show_scale = false;
bool show_drop_to_bed = 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()) { 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 rotation;
Vec3d scale; Vec3d scale;
double min_z = 0.; double min_z = 0.0;
#endif // ENABLE_WORLD_COORDINATE
if (selection.is_single_full_instance()) { 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(); rotation = volume->get_instance_rotation();
scale = volume->get_instance_scaling_factor(); scale = volume->get_instance_scaling_factor();
min_z = wxGetApp().model().objects[volume->composite_id.object_id]->bounding_box().min.z(); min_z = selection.get_scaled_instance_bounding_box().min.z();
#endif // ENABLE_WORLD_COORDINATE
} }
else { 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(); rotation = volume->get_volume_rotation();
scale = volume->get_volume_scaling_factor(); scale = volume->get_volume_scaling_factor();
min_z = get_volume_min_z(*volume); 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_rotation = !rotation.isApprox(Vec3d::Zero());
show_scale = !scale.isApprox(Vec3d::Ones()); show_scale = !scale.isApprox(Vec3d::Ones());
show_drop_to_bed = std::abs(min_z) > SINKING_Z_THRESHOLD; show_drop_to_bed = std::abs(min_z) > SINKING_Z_THRESHOLD;
#endif // ENABLE_WORLD_COORDINATE
} }
#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] { 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 // 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 // So, let check if Manipulation panel is still shown for this moment
if (!this->IsShown()) if (!this->IsShown())
@ -707,6 +916,10 @@ void ObjectManipulation::update_reset_buttons_visibility()
m_reset_rotation_button->Show(show_rotation); m_reset_rotation_button->Show(show_rotation);
m_reset_scale_button->Show(show_scale); m_reset_scale_button->Show(show_scale);
m_drop_to_bed_button->Show(show_drop_to_bed); 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 // Because of CallAfter we need to layout sidebar after Show/hide of reset buttons one more time
Sidebar& panel = wxGetApp().sidebar(); Sidebar& panel = wxGetApp().sidebar();
@ -726,9 +939,17 @@ void ObjectManipulation::update_mirror_buttons_visibility()
Selection& selection = canvas->get_selection(); Selection& selection = canvas->get_selection();
std::array<MirrorButtonState, 3> new_states = {mbHidden, mbHidden, mbHidden}; std::array<MirrorButtonState, 3> new_states = {mbHidden, mbHidden, mbHidden};
#if ENABLE_WORLD_COORDINATE
if (is_local_coordinates()) {
#else
if (!m_world_coordinates) { 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()) { 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; Vec3d mirror;
if (selection.is_single_full_instance()) 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); 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() void ObjectManipulation::reset_settings_value()
{ {
m_new_position = Vec3d::Zero(); m_new_position = Vec3d::Zero();
@ -815,7 +1049,19 @@ void ObjectManipulation::change_position_value(int axis, double value)
auto canvas = wxGetApp().plater()->canvas3D(); auto canvas = wxGetApp().plater()->canvas3D();
Selection& selection = canvas->get_selection(); Selection& selection = canvas->get_selection();
selection.setup_cache(); 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()); selection.translate(position - m_cache.position, selection.requires_local_axes());
#endif // ENABLE_WORLD_COORDINATE
canvas->do_move(L("Set Position")); canvas->do_move(L("Set Position"));
m_cache.position = position; m_cache.position = position;
@ -834,6 +1080,18 @@ void ObjectManipulation::change_rotation_value(int axis, double value)
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D(); GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
Selection& selection = canvas->get_selection(); 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); TransformationType transformation_type(TransformationType::World_Relative_Joint);
if (selection.is_single_full_instance() || selection.requires_local_axes()) if (selection.is_single_full_instance() || selection.requires_local_axes())
transformation_type.set_independent(); transformation_type.set_independent();
@ -842,6 +1100,7 @@ void ObjectManipulation::change_rotation_value(int axis, double value)
// transformation_type.set_absolute(); // transformation_type.set_absolute();
transformation_type.set_local(); transformation_type.set_local();
} }
#endif // ENABLE_WORLD_COORDINATE
selection.setup_cache(); selection.setup_cache();
selection.rotate( selection.rotate(
@ -887,8 +1146,12 @@ void ObjectManipulation::change_size_value(int axis, double value)
const Selection& selection = wxGetApp().plater()->canvas3D()->get_selection(); const Selection& selection = wxGetApp().plater()->canvas3D()->get_selection();
Vec3d ref_size = m_cache.size; 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()) { 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_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_ref_size = v->bounding_box().size().cwiseProduct(v->get_volume_scaling_factor());
const Vec3d local_change = local_size.cwiseQuotient(local_ref_size); 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(); ref_size = Vec3d::Ones();
} }
else if (selection.is_single_full_instance()) else if (selection.is_single_full_instance())
#if ENABLE_WORLD_COORDINATE
ref_size = is_world_coordinates() ?
#else
ref_size = m_world_coordinates ? ref_size = m_world_coordinates ?
#endif // ENABLE_WORLD_COORDINATE
selection.get_unscaled_instance_bounding_box().size() : 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)); this->do_scale(axis, size.cwiseQuotient(ref_size));
#endif // ENABLE_WORLD_COORDINATE
m_cache.size = size; m_cache.size = size;
m_cache.size_rounded(axis) = DBL_MAX; 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 void ObjectManipulation::do_scale(int axis, const Vec3d &scale) const
{ {
Selection& selection = wxGetApp().plater()->canvas3D()->get_selection(); Selection& selection = wxGetApp().plater()->canvas3D()->get_selection();
#if !ENABLE_WORLD_COORDINATE
Vec3d scaling_factor = scale; 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); TransformationType transformation_type(TransformationType::World_Relative_Joint);
if (selection.is_single_full_instance()) { if (selection.is_single_full_instance()) {
transformation_type.set_absolute(); 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()) if (m_uniform_scale || selection.requires_uniform_scale())
scaling_factor = scale(axis) * Vec3d::Ones(); scaling_factor = scale(axis) * Vec3d::Ones();
#endif // ENABLE_WORLD_COORDINATE
selection.setup_cache(); selection.setup_cache();
selection.scale(scaling_factor, transformation_type); selection.scale(scaling_factor, transformation_type);
wxGetApp().plater()->canvas3D()->do_scale(L("Set Scale")); 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) void ObjectManipulation::on_change(const std::string& opt_key, int axis, double new_value)
{ {
if (!m_cache.is_valid()) if (!m_cache.is_valid())
@ -962,15 +1266,24 @@ 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)
{ {
const Selection &selection = wxGetApp().plater()->canvas3D()->get_selection(); #if ENABLE_WORLD_COORDINATE
if (selection.is_single_full_instance() && m_world_coordinates && !new_value) { 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 && !use_uniform_scale) {
// Verify whether the instance rotation is multiples of 90 degrees, so that the scaling in world coordinates is possible. // 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 // 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? // Is the angle close to a multiple of 90 degrees?
if (! Geometry::is_rotation_ninety_degrees(volume->get_instance_rotation())) { if (!Geometry::is_rotation_ninety_degrees(volume->get_instance_rotation())) {
// Cannot apply scaling in the world coordinate system. // Cannot apply scaling in the world coordinate system.
//wxMessageDialog dlg(GUI::wxGetApp().mainframe, //wxMessageDialog dlg(GUI::wxGetApp().mainframe,
MessageDialog dlg(GUI::wxGetApp().mainframe, MessageDialog dlg(GUI::wxGetApp().mainframe,
@ -994,9 +1307,29 @@ void ObjectManipulation::set_uniform_scaling(const bool new_value)
this->UpdateAndShow(true); 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() void ObjectManipulation::msw_rescale()
{ {
const int em = wxGetApp().em_unit(); const int em = wxGetApp().em_unit();
@ -1014,6 +1347,9 @@ void ObjectManipulation::msw_rescale()
m_mirror_bitmap_hidden.msw_rescale(); m_mirror_bitmap_hidden.msw_rescale();
m_reset_scale_button->msw_rescale(); m_reset_scale_button->msw_rescale();
m_reset_rotation_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_drop_to_bed_button->msw_rescale();
m_lock_bnt->msw_rescale(); m_lock_bnt->msw_rescale();
@ -1053,6 +1389,9 @@ void ObjectManipulation::sys_color_changed()
m_mirror_bitmap_hidden.msw_rescale(); m_mirror_bitmap_hidden.msw_rescale();
m_reset_scale_button->msw_rescale(); m_reset_scale_button->msw_rescale();
m_reset_rotation_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_drop_to_bed_button->msw_rescale();
m_lock_bnt->msw_rescale(); m_lock_bnt->msw_rescale();
@ -1060,6 +1399,19 @@ void ObjectManipulation::sys_color_changed()
m_mirror_buttons[id].first->msw_rescale(); 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' }; static const char axes[] = { 'x', 'y', 'z' };
ManipulationEditor::ManipulationEditor(ObjectManipulation* parent, ManipulationEditor::ManipulationEditor(ObjectManipulation* parent,
const std::string& opt_key, const std::string& opt_key,
@ -1101,8 +1453,8 @@ ManipulationEditor::ManipulationEditor(ObjectManipulation* parent,
parent->set_focused_editor(nullptr); parent->set_focused_editor(nullptr);
#if ENABLE_OBJECT_MANIPULATOR_FOCUS #if ENABLE_OBJECT_MANIPULATOR_FOCUS
// if the widgets exchanging focus are both manipulator fields, call kill_focus // if the widgets loosing focus is a manipulator field, call kill_focus
if (dynamic_cast<ManipulationEditor*>(e.GetEventObject()) != nullptr && dynamic_cast<ManipulationEditor*>(e.GetWindow()) != nullptr) if (dynamic_cast<ManipulationEditor*>(e.GetEventObject()) != nullptr)
#else #else
if (!m_enter_pressed) if (!m_enter_pressed)
#endif // ENABLE_OBJECT_MANIPULATOR_FOCUS #endif // ENABLE_OBJECT_MANIPULATOR_FOCUS

View File

@ -5,6 +5,9 @@
#include "GUI_ObjectSettings.hpp" #include "GUI_ObjectSettings.hpp"
#include "GUI_ObjectList.hpp" #include "GUI_ObjectList.hpp"
#if ENABLE_WORLD_COORDINATE
#include "GUI_Geometry.hpp"
#endif // ENABLE_WORLD_COORDINATE
#include "libslic3r/Point.hpp" #include "libslic3r/Point.hpp"
#include <float.h> #include <float.h>
@ -57,6 +60,10 @@ public:
void set_value(const wxString& new_value); void set_value(const wxString& new_value);
void kill_focus(ObjectManipulation *parent); 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: private:
double get_value(); double get_value();
}; };
@ -113,9 +120,12 @@ private:
wxStaticText* m_empty_str = nullptr; wxStaticText* m_empty_str = nullptr;
// Non-owning pointers to the reset buttons, so we can hide and show them. // Non-owning pointers to the reset buttons, so we can hide and show them.
ScalableButton* m_reset_scale_button = nullptr; ScalableButton* m_reset_scale_button{ nullptr };
ScalableButton* m_reset_rotation_button = nullptr; ScalableButton* m_reset_rotation_button{ nullptr };
ScalableButton* m_drop_to_bed_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}; wxCheckBox* m_check_inch {nullptr};
@ -144,22 +154,35 @@ private:
Vec3d m_new_size; Vec3d m_new_size;
bool m_new_enabled {true}; bool m_new_enabled {true};
bool m_uniform_scale {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? // Does the object manipulation panel work in World or Local coordinates?
bool m_world_coordinates = true; bool m_world_coordinates = true;
#endif // ENABLE_WORLD_COORDINATE
LockButton* m_lock_bnt{ nullptr }; LockButton* m_lock_bnt{ nullptr };
choice_ctrl* m_word_local_combo { nullptr }; choice_ctrl* m_word_local_combo { nullptr };
ScalableBitmap m_manifold_warning_bmp; ScalableBitmap m_manifold_warning_bmp;
wxStaticBitmap* m_fix_throught_netfab_bitmap; wxStaticBitmap* m_fix_throught_netfab_bitmap;
#if ENABLE_WORLD_COORDINATE
// Currently focused editor (nullptr if none)
ManipulationEditor* m_focused_editor{ nullptr };
#else
#ifndef __APPLE__ #ifndef __APPLE__
// Currently focused editor (nullptr if none) // Currently focused editor (nullptr if none)
ManipulationEditor* m_focused_editor {nullptr}; ManipulationEditor* m_focused_editor {nullptr};
#endif // __APPLE__ #endif // __APPLE__
#endif // ENABLE_WORLD_COORDINATE
wxFlexGridSizer* m_main_grid_sizer; wxFlexGridSizer* m_main_grid_sizer;
wxFlexGridSizer* m_labels_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 // sizers, used for msw_rescale
wxBoxSizer* m_word_local_combo_sizer; wxBoxSizer* m_word_local_combo_sizer;
std::vector<wxBoxSizer*> m_rescalable_sizers; std::vector<wxBoxSizer*> m_rescalable_sizers;
@ -180,11 +203,19 @@ public:
// Called from the App to update the UI if dirty. // Called from the App to update the UI if dirty.
void update_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; } 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? // 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); } 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; } bool get_world_coordinates() const { return m_world_coordinates; }
#endif // ENABLE_WORLD_COORDINATE
void reset_cache() { m_cache.reset(); } void reset_cache() { m_cache.reset(); }
#ifndef __APPLE__ #ifndef __APPLE__
@ -200,11 +231,23 @@ public:
void sys_color_changed(); void sys_color_changed();
void on_change(const std::string& opt_key, int axis, double new_value); void on_change(const std::string& opt_key, int axis, double new_value);
void set_focused_editor(ManipulationEditor* focused_editor) { void set_focused_editor(ManipulationEditor* focused_editor) {
#if ENABLE_WORLD_COORDINATE
m_focused_editor = focused_editor;
#else
#ifndef __APPLE__ #ifndef __APPLE__
m_focused_editor = focused_editor; m_focused_editor = focused_editor;
#endif // __APPLE__ #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: private:
void reset_settings_value(); void reset_settings_value();
void update_settings_value(const Selection& selection); void update_settings_value(const Selection& selection);
@ -220,6 +263,11 @@ private:
void change_scale_value(int axis, double value); void change_scale_value(int axis, double value);
void change_size_value(int axis, double value); void change_size_value(int axis, double value);
void do_scale(int axis, const Vec3d &scale) const; 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(); wxGetApp().obj_manipul()->set_dirty();
m_parent.set_as_dirty(); m_parent.set_as_dirty();
return true; 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; for (auto &grabber : m_grabbers) grabber.dragging = false;
m_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)); m_parent.post_event(SimpleEvent(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED));
// updates camera target constraints // updates camera target constraints
m_parent.refresh_camera_scene_box(); m_parent.refresh_camera_scene_box();
#endif // ENABLE_WORLD_COORDINATE
return true; return true;
} }
} }
return false; 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 std::string GLGizmoBase::format(float value, unsigned int decimals) const
{ {
return Slic3r::string_printf("%.*f", decimals, value); return Slic3r::string_printf("%.*f", decimals, value);

View File

@ -227,6 +227,11 @@ protected:
/// <param name="mouse_event">Keep information about mouse click</param> /// <param name="mouse_event">Keep information about mouse click</param>
/// <returns>same as on_mouse</returns> /// <returns>same as on_mouse</returns>
bool use_grabbers(const wxMouseEvent &mouse_event); bool use_grabbers(const wxMouseEvent &mouse_event);
#if ENABLE_WORLD_COORDINATE
void do_stop_dragging(bool perform_mouse_cleanup);
#endif // ENABLE_WORLD_COORDINATE
private: private:
// Flag for dirty visible state of Gizmo // Flag for dirty visible state of Gizmo
// When True then need new rendering // 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"); 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. // 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(); 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) 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() void GLGizmoCut::update_contours()
{ {
const Selection& selection = m_parent.get_selection(); 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 BoundingBoxf3& box = first_glvolume->transformed_convex_hull_bounding_box();
const ModelObject* model_object = wxGetApp().model().objects[selection.get_object_idx()]; 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; ++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); 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 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(); 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)); glsafe(::glEnable(GL_BLEND));
if (selection.is_single_full_instance()) { 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 #if ENABLE_GL_SHADERS_ATTRIBUTES
const Camera& camera = wxGetApp().plater()->get_camera(); const Camera& camera = wxGetApp().plater()->get_camera();
const Transform3d view_model_matrix = camera.get_view_matrix() * 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("view_model_matrix", view_model_matrix);
shader->set_uniform("projection_matrix", camera.get_projection_matrix()); shader->set_uniform("projection_matrix", camera.get_projection_matrix());
#else #else
glsafe(::glPushMatrix()); 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())); glsafe(::glMultMatrixd(m.data()));
#endif // ENABLE_GL_SHADERS_ATTRIBUTES #endif // ENABLE_GL_SHADERS_ATTRIBUTES
if (this->is_plane_update_necessary()) if (this->is_plane_update_necessary())
@ -172,17 +172,17 @@ void GLGizmoFlatten::on_render_for_picking()
glsafe(::glDisable(GL_BLEND)); glsafe(::glDisable(GL_BLEND));
if (selection.is_single_full_instance() && !wxGetKeyState(WXK_CONTROL)) { 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 #if ENABLE_GL_SHADERS_ATTRIBUTES
const Camera& camera = wxGetApp().plater()->get_camera(); const Camera& camera = wxGetApp().plater()->get_camera();
const Transform3d view_model_matrix = camera.get_view_matrix() * 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("view_model_matrix", view_model_matrix);
shader->set_uniform("projection_matrix", camera.get_projection_matrix()); shader->set_uniform("projection_matrix", camera.get_projection_matrix());
#else #else
glsafe(::glPushMatrix()); 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())); glsafe(::glMultMatrixd(m.data()));
#endif // ENABLE_GL_SHADERS_ATTRIBUTES #endif // ENABLE_GL_SHADERS_ATTRIBUTES
if (this->is_plane_update_necessary()) if (this->is_plane_update_necessary())
@ -228,7 +228,11 @@ void GLGizmoFlatten::update_planes()
} }
ch = ch.convex_hull_3d(); ch = ch.convex_hull_3d();
m_planes.clear(); 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); const Transform3d& inst_matrix = mo->instances.front()->get_matrix(true);
#endif // ENABLE_WORLD_COORDINATE
// Following constants are used for discarding too small polygons. // Following constants are used for discarding too small polygons.
const float minimal_area = 5.f; // in square mm (world coordinates) 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(); const Selection& selection = m_parent.get_selection();
//#if ENABLE_RENDER_PICKING_PASS //#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 //#endif
glsafe(::glEnable(GL_DEPTH_TEST)); 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(); }); ScopeGuard guard([shader]() { if (shader) shader->stop_using(); });
#endif // ENABLE_LEGACY_OPENGL_REMOVAL #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(); Geometry::Transformation trafo = vol->get_instance_transformation() * vol->get_volume_transformation();
#if ENABLE_GL_SHADERS_ATTRIBUTES #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_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 Camera& camera = wxGetApp().plater()->get_camera();
const Transform3d& view_matrix = camera.get_view_matrix(); 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 Camera& camera = wxGetApp().plater()->get_camera();
const Selection& selection = m_parent.get_selection(); 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(); 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())); 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 "GLGizmoMove.hpp"
#include "slic3r/GUI/GLCanvas3D.hpp" #include "slic3r/GUI/GLCanvas3D.hpp"
#include "slic3r/GUI/GUI_App.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 #if ENABLE_GL_SHADERS_ATTRIBUTES
#include "slic3r/GUI/Plater.hpp" #include "slic3r/GUI/Plater.hpp"
#endif // ENABLE_GL_SHADERS_ATTRIBUTES #endif // ENABLE_GL_SHADERS_ATTRIBUTES
@ -21,18 +24,29 @@ GLGizmoMove3D::GLGizmoMove3D(GLCanvas3D& parent, const std::string& icon_filenam
std::string GLGizmoMove3D::get_tooltip() const 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(); 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(); const Vec3d& position = selection.get_bounding_box().center();
if (m_hover_id == 0 || m_grabbers[0].dragging) if (m_hover_id == 0 || m_grabbers[0].dragging)
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) 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) 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 else
return ""; return "";
#endif // ENABLE_WORLD_COORDINATE
} }
bool GLGizmoMove3D::on_mouse(const wxMouseEvent &mouse_event) { bool GLGizmoMove3D::on_mouse(const wxMouseEvent &mouse_event) {
@ -40,9 +54,7 @@ bool GLGizmoMove3D::on_mouse(const wxMouseEvent &mouse_event) {
} }
void GLGizmoMove3D::data_changed() { void GLGizmoMove3D::data_changed() {
const Selection &selection = m_parent.get_selection(); m_grabbers[2].enabled = !m_parent.get_selection().is_wipe_tower();
bool is_wipe_tower = selection.is_wipe_tower();
m_grabbers[2].enabled = !is_wipe_tower;
} }
bool GLGizmoMove3D::on_init() bool GLGizmoMove3D::on_init()
@ -79,11 +91,29 @@ void GLGizmoMove3D::on_start_dragging()
assert(m_hover_id != -1); assert(m_hover_id != -1);
m_displacement = Vec3d::Zero(); 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(); const BoundingBoxf3& box = m_parent.get_selection().get_bounding_box();
m_starting_drag_position = m_grabbers[m_hover_id].center; m_starting_drag_position = m_grabbers[m_hover_id].center;
m_starting_box_center = box.center(); m_starting_box_center = box.center();
m_starting_box_bottom_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() void GLGizmoMove3D::on_stop_dragging()
@ -102,7 +132,19 @@ void GLGizmoMove3D::on_dragging(const UpdateData& data)
m_displacement.z() = calc_projection(data); m_displacement.z() = calc_projection(data);
Selection &selection = m_parent.get_selection(); 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); selection.translate(m_displacement);
#endif // ENABLE_WORLD_COORDINATE
} }
void GLGizmoMove3D::on_render() 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)); m_cone.init_from(its_make_cone(1.0, 1.0, double(PI) / 18.0));
#endif // !ENABLE_GIZMO_GRABBER_REFACTOR #endif // !ENABLE_GIZMO_GRABBER_REFACTOR
const Selection& selection = m_parent.get_selection();
glsafe(::glClear(GL_DEPTH_BUFFER_BIT)); glsafe(::glClear(GL_DEPTH_BUFFER_BIT));
glsafe(::glEnable(GL_DEPTH_TEST)); 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 BoundingBoxf3& box = selection.get_bounding_box();
const Vec3d& center = box.center(); const Vec3d& center = box.center();
@ -131,14 +201,24 @@ void GLGizmoMove3D::on_render()
// z axis // z axis
m_grabbers[2].center = { center.x(), center.y(), box.max.z() + Offset }; m_grabbers[2].center = { center.x(), center.y(), box.max.z() + Offset };
m_grabbers[2].color = AXES_COLOR[2]; m_grabbers[2].color = AXES_COLOR[2];
#endif // ENABLE_WORLD_COORDINATE
glsafe(::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f)); glsafe(::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f));
#if ENABLE_LEGACY_OPENGL_REMOVAL #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) { auto render_grabber_connection = [this, &center](unsigned int id) {
#endif // ENABLE_WORLD_COORDINATE
if (m_grabbers[id].enabled) { 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)) { if (!m_grabber_connections[id].model.is_initialized() || !m_grabber_connections[id].old_center.isApprox(center)) {
m_grabber_connections[id].old_center = center; m_grabber_connections[id].old_center = center;
#endif // ENABLE_WORLD_COORDINATE
m_grabber_connections[id].model.reset(); m_grabber_connections[id].model.reset();
GLModel::Geometry init_data; GLModel::Geometry init_data;
@ -148,7 +228,11 @@ void GLGizmoMove3D::on_render()
init_data.reserve_indices(2); init_data.reserve_indices(2);
// vertices // vertices
#if ENABLE_WORLD_COORDINATE
init_data.add_vertex((Vec3f)zero.cast<float>());
#else
init_data.add_vertex((Vec3f)center.cast<float>()); init_data.add_vertex((Vec3f)center.cast<float>());
#endif // ENABLE_WORLD_COORDINATE
init_data.add_vertex((Vec3f)m_grabbers[id].center.cast<float>()); init_data.add_vertex((Vec3f)m_grabbers[id].center.cast<float>());
// indices // indices
@ -171,7 +255,11 @@ void GLGizmoMove3D::on_render()
#if ENABLE_GL_SHADERS_ATTRIBUTES #if ENABLE_GL_SHADERS_ATTRIBUTES
const Camera& camera = wxGetApp().plater()->get_camera(); 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()); shader->set_uniform("view_model_matrix", camera.get_view_matrix());
#endif // ENABLE_WORLD_COORDINATE
shader->set_uniform("projection_matrix", camera.get_projection_matrix()); shader->set_uniform("projection_matrix", camera.get_projection_matrix());
#endif // ENABLE_GL_SHADERS_ATTRIBUTES #endif // ENABLE_GL_SHADERS_ATTRIBUTES
@ -183,7 +271,11 @@ void GLGizmoMove3D::on_render()
if (m_grabbers[i].enabled) { if (m_grabbers[i].enabled) {
glsafe(::glColor4fv(AXES_COLOR[i].data())); glsafe(::glColor4fv(AXES_COLOR[i].data()));
::glBegin(GL_LINES); ::glBegin(GL_LINES);
#if ENABLE_WORLD_COORDINATE
::glVertex3dv(zero.data());
#else
::glVertex3dv(center.data()); ::glVertex3dv(center.data());
#endif // ENABLE_WORLD_COORDINATE
::glVertex3dv(m_grabbers[i].center.data()); ::glVertex3dv(m_grabbers[i].center.data());
glsafe(::glEnd()); glsafe(::glEnd());
} }
@ -196,6 +288,19 @@ void GLGizmoMove3D::on_render()
#endif // ENABLE_LEGACY_OPENGL_REMOVAL #endif // ENABLE_LEGACY_OPENGL_REMOVAL
// draw grabbers // 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); render_grabbers(box);
#if !ENABLE_GIZMO_GRABBER_REFACTOR #if !ENABLE_GIZMO_GRABBER_REFACTOR
for (unsigned int i = 0; i < 3; ++i) { for (unsigned int i = 0; i < 3; ++i) {
@ -203,6 +308,7 @@ void GLGizmoMove3D::on_render()
render_grabber_extension((Axis)i, box, false); render_grabber_extension((Axis)i, box, false);
} }
#endif // !ENABLE_GIZMO_GRABBER_REFACTOR #endif // !ENABLE_GIZMO_GRABBER_REFACTOR
#endif // ENABLE_WORLD_COORDINATE
} }
else { else {
// draw axis // draw axis
@ -213,7 +319,11 @@ void GLGizmoMove3D::on_render()
#if ENABLE_GL_SHADERS_ATTRIBUTES #if ENABLE_GL_SHADERS_ATTRIBUTES
const Camera& camera = wxGetApp().plater()->get_camera(); 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()); shader->set_uniform("view_model_matrix", camera.get_view_matrix());
#endif // ENABLE_WORLD_COORDINATE
shader->set_uniform("projection_matrix", camera.get_projection_matrix()); shader->set_uniform("projection_matrix", camera.get_projection_matrix());
#endif // ENABLE_GL_SHADERS_ATTRIBUTES #endif // ENABLE_GL_SHADERS_ATTRIBUTES
@ -225,7 +335,11 @@ void GLGizmoMove3D::on_render()
#else #else
glsafe(::glColor4fv(AXES_COLOR[m_hover_id].data())); glsafe(::glColor4fv(AXES_COLOR[m_hover_id].data()));
::glBegin(GL_LINES); ::glBegin(GL_LINES);
#if ENABLE_WORLD_COORDINATE
::glVertex3dv(zero.data());
#else
::glVertex3dv(center.data()); ::glVertex3dv(center.data());
#endif // ENABLE_WORLD_COORDINATE
::glVertex3dv(m_grabbers[m_hover_id].center.data()); ::glVertex3dv(m_grabbers[m_hover_id].center.data());
glsafe(::glEnd()); glsafe(::glEnd());
@ -235,20 +349,65 @@ void GLGizmoMove3D::on_render()
shader->start_using(); shader->start_using();
shader->set_uniform("emission_factor", 0.1f); shader->set_uniform("emission_factor", 0.1f);
// draw grabber // 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); m_grabbers[m_hover_id].render(true, mean_size);
shader->stop_using(); shader->stop_using();
} }
#if !ENABLE_GIZMO_GRABBER_REFACTOR #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); render_grabber_extension((Axis)m_hover_id, box, false);
#endif // ENABLE_WORLD_COORDINATE
#endif // !ENABLE_GIZMO_GRABBER_REFACTOR #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() void GLGizmoMove3D::on_render_for_picking()
{ {
glsafe(::glDisable(GL_DEPTH_TEST)); 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(); const BoundingBoxf3& box = m_parent.get_selection().get_bounding_box();
render_grabbers_for_picking(box); render_grabbers_for_picking(box);
#if !ENABLE_GIZMO_GRABBER_REFACTOR #if !ENABLE_GIZMO_GRABBER_REFACTOR
@ -256,23 +415,24 @@ void GLGizmoMove3D::on_render_for_picking()
render_grabber_extension(Y, box, true); render_grabber_extension(Y, box, true);
render_grabber_extension(Z, box, true); render_grabber_extension(Z, box, true);
#endif // !ENABLE_GIZMO_GRABBER_REFACTOR #endif // !ENABLE_GIZMO_GRABBER_REFACTOR
#endif // ENABLE_WORLD_COORDINATE
} }
double GLGizmoMove3D::calc_projection(const UpdateData& data) const double GLGizmoMove3D::calc_projection(const UpdateData& data) const
{ {
double projection = 0.0; double projection = 0.0;
Vec3d starting_vec = m_starting_drag_position - m_starting_box_center; const Vec3d starting_vec = m_starting_drag_position - m_starting_box_center;
double len_starting_vec = starting_vec.norm(); const double len_starting_vec = starting_vec.norm();
if (len_starting_vec != 0.0) { 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 // 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 // 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) // 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 // 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 // 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 // finds projection of the vector along the staring direction
projection = inters_vec.dot(starting_vec.normalized()); 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_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) 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)); 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 #if ENABLE_LEGACY_OPENGL_REMOVAL
@ -312,7 +477,7 @@ void GLGizmoMove3D::render_grabber_extension(Axis axis, const BoundingBoxf3& box
#if ENABLE_GL_SHADERS_ATTRIBUTES #if ENABLE_GL_SHADERS_ATTRIBUTES
const Camera& camera = wxGetApp().plater()->get_camera(); 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) if (axis == X)
view_model_matrix = view_model_matrix * Geometry::assemble_transform(Vec3d::Zero(), 0.5 * PI * Vec3d::UnitY()); view_model_matrix = view_model_matrix * Geometry::assemble_transform(Vec3d::Zero(), 0.5 * PI * Vec3d::UnitY());
else if (axis == Y) else if (axis == Y)
@ -345,5 +510,62 @@ void GLGizmoMove3D::render_grabber_extension(Axis axis, const BoundingBoxf3& box
} }
#endif // !ENABLE_GIZMO_GRABBER_REFACTOR #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 GUI
} // namespace Slic3r } // namespace Slic3r

View File

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

View File

@ -291,7 +291,11 @@ void GLGizmoPainterBase::render_cursor_sphere(const Transform3d& trafo) const
return; return;
#endif // ENABLE_LEGACY_OPENGL_REMOVAL #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(); 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(); const bool is_left_handed = Geometry::Transformation(trafo).is_left_handed();
#if !ENABLE_GL_SHADERS_ATTRIBUTES #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 Selection &selection = m_parent.get_selection();
const ModelObject *mo = m_c->selection_info()->model_object(); const ModelObject *mo = m_c->selection_info()->model_object();
const ModelInstance *mi = mo->instances[selection.get_instance_idx()]; 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); 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(); 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_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); 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 ModelObject *mo = m_c->selection_info()->model_object();
const ModelInstance *mi = mo->instances[selection.get_instance_idx()]; const ModelInstance *mi = mo->instances[selection.get_instance_idx()];
const Transform3d instance_trafo = mi->get_transformation().get_matrix(); 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); const Transform3d instance_trafo_not_translate = mi->get_transformation().get_matrix(true);
#endif // ENABLE_WORLD_COORDINATE
// Precalculate transformations of individual meshes. // Precalculate transformations of individual meshes.
std::vector<Transform3d> trafo_matrices; std::vector<Transform3d> trafo_matrices;
@ -555,7 +567,11 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
for (const ModelVolume *mv : mo->volumes) for (const ModelVolume *mv : mo->volumes)
if (mv->is_model_part()) { if (mv->is_model_part()) {
trafo_matrices.emplace_back(instance_trafo * mv->get_matrix()); 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)); 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); 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 ModelObject *mo = m_c->selection_info()->model_object();
const ModelInstance *mi = mo->instances[selection.get_instance_idx()]; const ModelInstance *mi = mo->instances[selection.get_instance_idx()];
const Transform3d instance_trafo = mi->get_transformation().get_matrix(); 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); const Transform3d instance_trafo_not_translate = mi->get_transformation().get_matrix(true);
#endif // ENABLE_WORLD_COORDINATE
// Precalculate transformations of individual meshes. // Precalculate transformations of individual meshes.
std::vector<Transform3d> trafo_matrices; std::vector<Transform3d> trafo_matrices;
@ -645,7 +665,11 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
for (const ModelVolume *mv : mo->volumes) for (const ModelVolume *mv : mo->volumes)
if (mv->is_model_part()) { if (mv->is_model_part()) {
trafo_matrices.emplace_back(instance_trafo * mv->get_matrix()); 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)); 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. // Now "click" into all the prepared points and spill paint around them.

View File

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

View File

@ -34,6 +34,10 @@ private:
float m_snap_coarse_out_radius{ 0.0f }; float m_snap_coarse_out_radius{ 0.0f };
float m_snap_fine_in_radius{ 0.0f }; float m_snap_fine_in_radius{ 0.0f };
float m_snap_fine_out_radius{ 0.0f }; float m_snap_fine_out_radius{ 0.0f };
#if ENABLE_WORLD_COORDINATE
BoundingBoxf3 m_bounding_box;
Transform3d m_orient_matrix{ Transform3d::Identity() };
#endif // ENABLE_WORLD_COORDINATE
#if !ENABLE_GIZMO_GRABBER_REFACTOR #if !ENABLE_GIZMO_GRABBER_REFACTOR
GLModel m_cone; GLModel m_cone;
@ -119,6 +123,10 @@ private:
// returns the intersection of the mouse ray with the plane perpendicular to the gizmo axis, in local coordinate // returns the intersection of the mouse ray with the plane perpendicular to the gizmo axis, in local coordinate
Vec3d mouse_position_in_local_plane(const Linef3& mouse_ray, const Selection& selection) const; Vec3d mouse_position_in_local_plane(const Linef3& mouse_ray, const Selection& selection) const;
#if ENABLE_WORLD_COORDINATE
void init_data_from_selection(const Selection& selection);
#endif // ENABLE_WORLD_COORDINATE
}; };
class GLGizmoRotate3D : public GLGizmoBase class GLGizmoRotate3D : public GLGizmoBase
@ -129,7 +137,7 @@ public:
GLGizmoRotate3D(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); 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()); } 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 get_tooltip() const override {
std::string tooltip = m_gizmos[X].get_tooltip(); std::string tooltip = m_gizmos[X].get_tooltip();

View File

@ -2,6 +2,9 @@
#include "GLGizmoScale.hpp" #include "GLGizmoScale.hpp"
#include "slic3r/GUI/GLCanvas3D.hpp" #include "slic3r/GUI/GLCanvas3D.hpp"
#include "slic3r/GUI/GUI_App.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 #if ENABLE_GL_SHADERS_ATTRIBUTES
#include "slic3r/GUI/Plater.hpp" #include "slic3r/GUI/Plater.hpp"
#endif // ENABLE_GL_SHADERS_ATTRIBUTES #endif // ENABLE_GL_SHADERS_ATTRIBUTES
@ -14,7 +17,7 @@ namespace Slic3r {
namespace GUI { 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) GLGizmoScale3D::GLGizmoScale3D(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id)
: GLGizmoBase(parent, icon_filename, 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 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(); const Selection& selection = m_parent.get_selection();
bool single_instance = selection.is_single_full_instance(); Vec3d scale = 100.0 * Vec3d::Ones();
bool single_volume = selection.is_single_modifier() || selection.is_single_volume(); if (selection.is_single_full_instance())
scale = 100.0 * selection.get_first_volume()->get_instance_scaling_factor();
Vec3f scale = 100.0f * Vec3f::Ones(); else if (selection.is_single_modifier() || selection.is_single_volume())
if (single_instance) scale = 100.0 * selection.get_first_volume()->get_volume_scaling_factor();
scale = 100.0f * selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_scaling_factor().cast<float>(); #endif // ENABLE_WORLD_COORDINATE
else if (single_volume)
scale = 100.0f * selection.get_volume(*selection.get_volume_idxs().begin())->get_volume_scaling_factor().cast<float>();
if (m_hover_id == 0 || m_hover_id == 1 || m_grabbers[0].dragging || m_grabbers[1].dragging) if (m_hover_id == 0 || m_hover_id == 1 || m_grabbers[0].dragging || m_grabbers[1].dragging)
return "X: " + format(scale.x(), 4) + "%"; return "X: " + format(scale.x(), 4) + "%";
@ -72,12 +76,28 @@ bool GLGizmoScale3D::on_mouse(const wxMouseEvent &mouse_event)
if (mouse_event.Dragging()) { if (mouse_event.Dragging()) {
if (m_dragging) { if (m_dragging) {
// Apply new temporary scale factors // Apply new temporary scale factors
TransformationType transformation_type(TransformationType::Local_Absolute_Joint); #if ENABLE_WORLD_COORDINATE
if (mouse_event.AltDown()) transformation_type.set_independent(); 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();
Selection &selection = m_parent.get_selection(); transformation_type.set_relative();
selection.scale(get_scale(), transformation_type); #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(m_scale, transformation_type);
if (mouse_event.CmdDown()) selection.translate(m_offset, true); if (mouse_event.CmdDown()) selection.translate(m_offset, true);
#endif // ENABLE_WORLD_COORDINATE
} }
} }
return use_grabbers(mouse_event); return use_grabbers(mouse_event);
@ -85,26 +105,29 @@ bool GLGizmoScale3D::on_mouse(const wxMouseEvent &mouse_event)
void GLGizmoScale3D::data_changed() void GLGizmoScale3D::data_changed()
{ {
const Selection &selection = m_parent.get_selection(); #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() || bool enable_scale_xyz = selection.is_single_full_instance() ||
selection.is_single_volume() || selection.is_single_volume() ||
selection.is_single_modifier(); selection.is_single_modifier();
for (unsigned int i = 0; i < 6; ++i) for (unsigned int i = 0; i < 6; ++i)
m_grabbers[i].enabled = enable_scale_xyz; m_grabbers[i].enabled = enable_scale_xyz;
if (enable_scale_xyz) { if (enable_scale_xyz) {
// all volumes in the selection belongs to the same instance, any of // all volumes in the selection belongs to the same instance, any of
// them contains the needed data, so we take the first // them contains the needed data, so we take the first
const GLVolume *volume = selection.get_volume(*selection.get_volume_idxs().begin()); const GLVolume* volume = selection.get_first_volume();
if (selection.is_single_full_instance()) { if (selection.is_single_full_instance())
set_scale(volume->get_instance_scaling_factor()); set_scale(volume->get_instance_scaling_factor());
} else if (selection.is_single_volume() || else if (selection.is_single_volume() || selection.is_single_modifier())
selection.is_single_modifier()) {
set_scale(volume->get_volume_scaling_factor()); set_scale(volume->get_volume_scaling_factor());
} }
} else { else
set_scale(Vec3d::Ones()); set_scale(Vec3d::Ones());
} #endif // ENABLE_WORLD_COORDINATE
} }
bool GLGizmoScale3D::on_init() bool GLGizmoScale3D::on_init()
@ -113,15 +136,17 @@ bool GLGizmoScale3D::on_init()
m_grabbers.push_back(Grabber()); m_grabbers.push_back(Grabber());
} }
#if !ENABLE_WORLD_COORDINATE
double half_pi = 0.5 * (double)PI; double half_pi = 0.5 * (double)PI;
// x axis // x axis
m_grabbers[0].angles(1) = half_pi; m_grabbers[0].angles.y() = half_pi;
m_grabbers[1].angles(1) = half_pi; m_grabbers[1].angles.y() = half_pi;
// y axis // y axis
m_grabbers[2].angles(0) = half_pi; m_grabbers[2].angles.x() = half_pi;
m_grabbers[3].angles(0) = half_pi; m_grabbers[3].angles.x() = half_pi;
#endif // !ENABLE_WORLD_COORDINATE
m_shortcut_key = WXK_CONTROL_S; m_shortcut_key = WXK_CONTROL_S;
@ -142,9 +167,15 @@ bool GLGizmoScale3D::on_is_activable() const
void GLGizmoScale3D::on_start_dragging() void GLGizmoScale3D::on_start_dragging()
{ {
assert(m_hover_id != -1); assert(m_hover_id != -1);
m_starting.drag_position = m_grabbers[m_hover_id].center;
m_starting.ctrl_down = wxGetKeyState(WXK_CONTROL); 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(); const Vec3d& center = m_starting.box.center();
m_starting.pivots[0] = m_transform * Vec3d(m_starting.box.max.x(), center.y(), center.z()); 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[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[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()); 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() { void GLGizmoScale3D::on_stop_dragging() {
@ -175,78 +207,156 @@ void GLGizmoScale3D::on_render()
{ {
const Selection& selection = m_parent.get_selection(); 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(::glClear(GL_DEPTH_BUFFER_BIT));
glsafe(::glEnable(GL_DEPTH_TEST)); 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(); m_transform = Transform3d::Identity();
// Transforms grabbers' offsets to world refefence system // Transforms grabbers' offsets to world refefence system
Transform3d offsets_transform = Transform3d::Identity(); Transform3d offsets_transform = Transform3d::Identity();
m_offsets_transform = Transform3d::Identity(); m_offsets_transform = Transform3d::Identity();
Vec3d angles = Vec3d::Zero(); 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 // calculate bounding box in instance local reference system
const Selection::IndicesList& idxs = selection.get_volume_idxs(); const Selection::IndicesList& idxs = selection.get_volume_idxs();
for (unsigned int idx : idxs) { for (unsigned int idx : idxs) {
const GLVolume* vol = selection.get_volume(idx); const GLVolume& v = *selection.get_volume(idx);
m_box.merge(vol->bounding_box().transformed(vol->get_volume_transformation().get_matrix())); 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 // gets transform from first selected volume
const GLVolume* v = selection.get_volume(*idxs.begin()); const GLVolume& v = *selection.get_first_volume();
m_transform = v->get_instance_transformation().get_matrix(); #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 // 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 // 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; m_offsets_transform = offsets_transform;
} }
else if (single_volume) { else if (selection.is_single_modifier() || selection.is_single_volume()) {
const GLVolume* v = selection.get_volume(*selection.get_volume_idxs().begin()); #endif // ENABLE_WORLD_COORDINATE
m_box = v->bounding_box(); const GLVolume& v = *selection.get_first_volume();
m_transform = v->world_matrix(); #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); angles = Geometry::extract_euler_angles(m_transform);
// consider rotation+mirror only components of the transform for offsets // 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 = Geometry::assemble_transform(Vec3d::Zero(), v->get_volume_rotation(), Vec3d::Ones(), v->get_volume_mirror()); m_offsets_transform = Geometry::assemble_transform(Vec3d::Zero(), v.get_volume_rotation(), Vec3d::Ones(), v.get_volume_mirror());
} }
else 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_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_y = offsets_transform * Vec3d(0.0, (double)Offset, 0.0);
const Vec3d offset_z = offsets_transform * Vec3d(0.0, 0.0, (double)Offset); 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)); 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 // 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[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]; m_grabbers[1].color = (ctrl_down && m_hover_id == 0) ? CONSTRAINED_COLOR : AXES_COLOR[0];
// y axis // 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[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]; m_grabbers[3].color = (ctrl_down && m_hover_id == 2) ? CONSTRAINED_COLOR : AXES_COLOR[1];
// z axis // 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[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]; m_grabbers[5].color = (ctrl_down && m_hover_id == 4) ? CONSTRAINED_COLOR : AXES_COLOR[2];
// uniform // uniform
m_grabbers[6].center = m_transform * Vec3d(m_box.min.x(), m_box.min.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_box.max.x(), m_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_box.max.x(), m_box.max.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_box.min.x(), m_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) { for (int i = 6; i < 10; ++i) {
m_grabbers[i].color = m_highlight_color; m_grabbers[i].color = m_highlight_color;
} }
@ -255,12 +365,25 @@ void GLGizmoScale3D::on_render()
for (int i = 0; i < 10; ++i) { for (int i = 0; i < 10; ++i) {
m_grabbers[i].angles = angles; m_grabbers[i].angles = angles;
} }
#endif // ENABLE_WORLD_COORDINATE
glsafe(::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f)); 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 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); 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 (m_hover_id == -1) {
#if ENABLE_LEGACY_OPENGL_REMOVAL #if ENABLE_LEGACY_OPENGL_REMOVAL
@ -270,7 +393,11 @@ void GLGizmoScale3D::on_render()
shader->start_using(); shader->start_using();
#if ENABLE_GL_SHADERS_ATTRIBUTES #if ENABLE_GL_SHADERS_ATTRIBUTES
const Camera& camera = wxGetApp().plater()->get_camera(); 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()); shader->set_uniform("view_model_matrix", camera.get_view_matrix());
#endif // ENABLE_WORLD_COORDINATE
shader->set_uniform("projection_matrix", camera.get_projection_matrix()); shader->set_uniform("projection_matrix", camera.get_projection_matrix());
#endif // ENABLE_GL_SHADERS_ATTRIBUTES #endif // ENABLE_GL_SHADERS_ATTRIBUTES
if (m_grabbers[0].enabled && m_grabbers[1].enabled) if (m_grabbers[0].enabled && m_grabbers[1].enabled)
@ -317,7 +444,11 @@ void GLGizmoScale3D::on_render()
shader->start_using(); shader->start_using();
#if ENABLE_GL_SHADERS_ATTRIBUTES #if ENABLE_GL_SHADERS_ATTRIBUTES
const Camera& camera = wxGetApp().plater()->get_camera(); 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()); shader->set_uniform("view_model_matrix", camera.get_view_matrix());
#endif // ENABLE_WORLD_COORDINATE
shader->set_uniform("projection_matrix", camera.get_projection_matrix()); shader->set_uniform("projection_matrix", camera.get_projection_matrix());
#endif // ENABLE_GL_SHADERS_ATTRIBUTES #endif // ENABLE_GL_SHADERS_ATTRIBUTES
render_grabbers_connection(0, 1, m_grabbers[0].color); render_grabbers_connection(0, 1, m_grabbers[0].color);
@ -328,7 +459,7 @@ void GLGizmoScale3D::on_render()
shader = wxGetApp().get_shader("gouraud_light"); shader = wxGetApp().get_shader("gouraud_light");
#else #else
// draw connection // draw connection
glsafe(::glColor4fv(m_grabbers[0].color.data())); glsafe(::glColor4fv(AXES_COLOR[0].data()));
render_grabbers_connection(0, 1); render_grabbers_connection(0, 1);
// draw grabbers // draw grabbers
@ -350,7 +481,11 @@ void GLGizmoScale3D::on_render()
shader->start_using(); shader->start_using();
#if ENABLE_GL_SHADERS_ATTRIBUTES #if ENABLE_GL_SHADERS_ATTRIBUTES
const Camera& camera = wxGetApp().plater()->get_camera(); 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()); shader->set_uniform("view_model_matrix", camera.get_view_matrix());
#endif // ENABLE_WORLD_COORDINATE
shader->set_uniform("projection_matrix", camera.get_projection_matrix()); shader->set_uniform("projection_matrix", camera.get_projection_matrix());
#endif // ENABLE_GL_SHADERS_ATTRIBUTES #endif // ENABLE_GL_SHADERS_ATTRIBUTES
render_grabbers_connection(2, 3, m_grabbers[2].color); render_grabbers_connection(2, 3, m_grabbers[2].color);
@ -361,7 +496,7 @@ void GLGizmoScale3D::on_render()
shader = wxGetApp().get_shader("gouraud_light"); shader = wxGetApp().get_shader("gouraud_light");
#else #else
// draw connection // draw connection
glsafe(::glColor4fv(m_grabbers[2].color.data())); glsafe(::glColor4fv(AXES_COLOR[1].data()));
render_grabbers_connection(2, 3); render_grabbers_connection(2, 3);
// draw grabbers // draw grabbers
@ -383,7 +518,11 @@ void GLGizmoScale3D::on_render()
shader->start_using(); shader->start_using();
#if ENABLE_GL_SHADERS_ATTRIBUTES #if ENABLE_GL_SHADERS_ATTRIBUTES
const Camera& camera = wxGetApp().plater()->get_camera(); 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()); shader->set_uniform("view_model_matrix", camera.get_view_matrix());
#endif // ENABLE_WORLD_COORDINATE
shader->set_uniform("projection_matrix", camera.get_projection_matrix()); shader->set_uniform("projection_matrix", camera.get_projection_matrix());
#endif // ENABLE_GL_SHADERS_ATTRIBUTES #endif // ENABLE_GL_SHADERS_ATTRIBUTES
render_grabbers_connection(4, 5, m_grabbers[4].color); render_grabbers_connection(4, 5, m_grabbers[4].color);
@ -394,7 +533,7 @@ void GLGizmoScale3D::on_render()
shader = wxGetApp().get_shader("gouraud_light"); shader = wxGetApp().get_shader("gouraud_light");
#else #else
// draw connection // draw connection
glsafe(::glColor4fv(m_grabbers[4].color.data())); glsafe(::glColor4fv(AXES_COLOR[2].data()));
render_grabbers_connection(4, 5); render_grabbers_connection(4, 5);
// draw grabbers // draw grabbers
@ -416,7 +555,11 @@ void GLGizmoScale3D::on_render()
shader->start_using(); shader->start_using();
#if ENABLE_GL_SHADERS_ATTRIBUTES #if ENABLE_GL_SHADERS_ATTRIBUTES
const Camera& camera = wxGetApp().plater()->get_camera(); 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()); shader->set_uniform("view_model_matrix", camera.get_view_matrix());
#endif // ENABLE_WORLD_COORDINATE
shader->set_uniform("projection_matrix", camera.get_projection_matrix()); shader->set_uniform("projection_matrix", camera.get_projection_matrix());
#endif // ENABLE_GL_SHADERS_ATTRIBUTES #endif // ENABLE_GL_SHADERS_ATTRIBUTES
render_grabbers_connection(6, 7, m_drag_color); render_grabbers_connection(6, 7, m_drag_color);
@ -448,12 +591,34 @@ void GLGizmoScale3D::on_render()
shader->stop_using(); 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() void GLGizmoScale3D::on_render_for_picking()
{ {
glsafe(::glDisable(GL_DEPTH_TEST)); 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()); render_grabbers_for_picking(m_parent.get_selection().get_bounding_box());
#endif // ENABLE_WORLD_COORDINATE
} }
#if ENABLE_LEGACY_OPENGL_REMOVAL #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 #endif // ENABLE_LEGACY_OPENGL_REMOVAL
#if ENABLE_WORLD_COORDINATE
void GLGizmoScale3D::do_scale_along_axis(Axis axis, const UpdateData& data) void GLGizmoScale3D::do_scale_along_axis(Axis axis, const UpdateData& data)
{ {
double ratio = calc_ratio(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) { if (ratio > 0.0) {
m_scale(axis) = m_starting.scale(axis) * ratio; m_scale(axis) = m_starting.scale(axis) * ratio;
if (m_starting.ctrl_down) { if (m_starting.ctrl_down) {
double local_offset = 0.5 * (m_scale(axis) - m_starting.scale(axis)) * m_starting.box.size()(axis); double local_offset = 0.5 * (m_scale(axis) - m_starting.scale(axis)) * m_starting.box.size()(axis);
if (m_hover_id == 2 * axis) if (m_hover_id == 2 * axis)
local_offset *= -1.0; local_offset *= -1.0;
@ -534,36 +753,86 @@ void GLGizmoScale3D::do_scale_along_axis(Axis axis, const UpdateData& data)
m_offset = Vec3d::Zero(); m_offset = Vec3d::Zero();
} }
} }
#endif // ENABLE_WORLD_COORDINATE
#if ENABLE_WORLD_COORDINATE
void GLGizmoScale3D::do_scale_uniform(const UpdateData & 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) void GLGizmoScale3D::do_scale_uniform(const UpdateData& data)
{ {
double ratio = calc_ratio(data); const double ratio = calc_ratio(data);
if (ratio > 0.0) { if (ratio > 0.0) {
m_scale = m_starting.scale * ratio; m_scale = m_starting.scale * ratio;
m_offset = Vec3d::Zero(); m_offset = Vec3d::Zero();
} }
} }
#endif // ENABLE_WORLD_COORDINATE
double GLGizmoScale3D::calc_ratio(const UpdateData& data) const double GLGizmoScale3D::calc_ratio(const UpdateData& data) const
{ {
double ratio = 0.0; 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) { 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 // 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 // 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) // 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 // 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 // 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 // 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; ratio = (len_starting_vec + proj) / len_starting_vec;
} }
@ -574,5 +843,34 @@ double GLGizmoScale3D::calc_ratio(const UpdateData& data) const
return ratio; 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 GUI
} // namespace Slic3r } // namespace Slic3r

View File

@ -3,31 +3,46 @@
#include "GLGizmoBase.hpp" #include "GLGizmoBase.hpp"
#if !ENABLE_WORLD_COORDINATE
#include "libslic3r/BoundingBox.hpp" #include "libslic3r/BoundingBox.hpp"
#endif // !ENABLE_WORLD_COORDINATE
namespace Slic3r { namespace Slic3r {
namespace GUI { namespace GUI {
#if ENABLE_WORLD_COORDINATE
class Selection;
#endif // ENABLE_WORLD_COORDINATE
class GLGizmoScale3D : public GLGizmoBase class GLGizmoScale3D : public GLGizmoBase
{ {
static const float Offset; static const double Offset;
struct StartingData struct StartingData
{ {
Vec3d scale; bool ctrl_down{ false };
Vec3d drag_position; 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; BoundingBoxf3 box;
Vec3d pivots[6]; #if !ENABLE_WORLD_COORDINATE
bool ctrl_down; std::array<Vec3d, 6> pivots{ Vec3d::Zero(), Vec3d::Zero(), Vec3d::Zero(), Vec3d::Zero(), Vec3d::Zero(), Vec3d::Zero() };
#endif // !ENABLE_WORLD_COORDINATE
StartingData() : scale(Vec3d::Ones()), drag_position(Vec3d::Zero()), ctrl_down(false) { for (int i = 0; i < 5; ++i) { pivots[i] = Vec3d::Zero(); } }
}; };
mutable BoundingBoxf3 m_box; BoundingBoxf3 m_bounding_box;
mutable Transform3d m_transform; #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) // 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_scale{ Vec3d::Ones() };
Vec3d m_offset{ Vec3d::Zero() }; Vec3d m_offset{ Vec3d::Zero() };
double m_snap_step{ 0.05 }; double m_snap_step{ 0.05 };
@ -54,7 +69,11 @@ public:
void set_snap_step(double step) { m_snap_step = step; } void set_snap_step(double step) { m_snap_step = step; }
const Vec3d& get_scale() const { return m_scale; } 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; } void set_scale(const Vec3d& scale) { m_starting.scale = scale; m_scale = scale; }
#endif // ENABLE_WORLD_COORDINATE
std::string get_tooltip() const override; std::string get_tooltip() const override;
@ -87,6 +106,13 @@ private:
void do_scale_uniform(const UpdateData& data); void do_scale_uniform(const UpdateData& data);
double calc_ratio(const UpdateData& data) const; 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 #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()); 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(); const Transform3d& instance_scaling_matrix_inverse = transformation.get_matrix(true, true, false, true).inverse();
#endif // ENABLE_WORLD_COORDINATE
#if ENABLE_GL_SHADERS_ATTRIBUTES #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 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(); 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 Camera& camera = wxGetApp().plater()->get_camera();
const Selection& selection = m_parent.get_selection(); 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(); 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())); 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(); const Selection& selection = get_pool()->get_canvas()->get_selection();
if (selection.is_single_full_instance()) { if (selection.is_single_full_instance()) {
m_model_object = selection.get_model()->objects[selection.get_object_idx()]; 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 else
m_model_object = nullptr; 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 // at this moment is enebled to process mouse move under gizmo
// tools bar e.g. Do not interupt dragging. // tools bar e.g. Do not interupt dragging.
return false; return false;
} else if (mc.exist_tooltip) { }
else if (mc.exist_tooltip) {
// first move out of gizmo tool bar - unselect tooltip // first move out of gizmo tool bar - unselect tooltip
mc.exist_tooltip = false; mc.exist_tooltip = false;
update_hover_state(Undefined); update_hover_state(Undefined);
@ -423,10 +424,12 @@ bool GLGizmosManager::gizmos_toolbar_on_mouse(const wxMouseEvent &mouse_event) {
mc.left = true; mc.left = true;
open_gizmo(gizmo); open_gizmo(gizmo);
return true; return true;
} else if (mouse_event.RightDown()) { }
else if (mouse_event.RightDown()) {
mc.right = true; mc.right = true;
return true; return true;
} else if (mouse_event.MiddleDown()) { }
else if (mouse_event.MiddleDown()) {
mc.middle = true; mc.middle = true;
return 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 // draging start on toolbar so no propagation into scene
return true; return true;
} else if (mc.left && mouse_event.LeftUp()) { }
else if (mc.left && mouse_event.LeftUp()) {
mc.left = false; mc.left = false;
return true; return true;
} else if (mc.right && mouse_event.RightUp()) { }
else if (mc.right && mouse_event.RightUp()) {
mc.right = false; mc.right = false;
return true; return true;
} else if (mc.middle && mouse_event.MiddleUp()) { }
else if (mc.middle && mouse_event.MiddleUp()) {
mc.middle = false; mc.middle = false;
return true; return true;
} }

View File

@ -112,7 +112,11 @@ void MeshClipper::render_cut()
void MeshClipper::recalculate_triangles() 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>(); 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. // 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 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()); 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; 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); 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 = -camera.get_dir_forward();
Vec3d direction_to_camera_mesh = (instance_matrix_no_translation_no_scaling.inverse() * direction_to_camera).normalized().eval(); 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()); 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_ObjectManipulation.hpp"
#include "GUI_ObjectLayers.hpp" #include "GUI_ObjectLayers.hpp"
#include "GUI_Utils.hpp" #include "GUI_Utils.hpp"
#if ENABLE_WORLD_COORDINATE
#include "GUI_Geometry.hpp"
#endif // ENABLE_WORLD_COORDINATE
#include "GUI_Factories.hpp" #include "GUI_Factories.hpp"
#include "wxExtensions.hpp" #include "wxExtensions.hpp"
#include "MainFrame.hpp" #include "MainFrame.hpp"
@ -1514,6 +1517,11 @@ void Sidebar::update_mode()
wxWindowUpdateLocker noUpdates(this); 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->get_sizer()->Show(m_mode > comSimple);
p->object_list->unselect_objects(); 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_MOVED, &priv::on_wipetower_moved, this);
view3D_canvas->Bind(EVT_GLCANVAS_WIPETOWER_ROTATED, &priv::on_wipetower_rotated, this); view3D_canvas->Bind(EVT_GLCANVAS_WIPETOWER_ROTATED, &priv::on_wipetower_rotated, this);
view3D_canvas->Bind(EVT_GLCANVAS_INSTANCE_ROTATED, [this](SimpleEvent&) { update(); }); 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_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_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); 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)) if ((0 > idx) || (idx > 1000))
#endif // ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL #endif // ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
return-1; 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) if (model.objects[idx]->volumes.size() > 1)
return v->volume_idx(); return v->volume_idx();
return -1; 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_type(old_volume->type());
new_volume->set_material_id(old_volume->material_id()); new_volume->set_material_id(old_volume->material_id());
new_volume->set_transformation(old_volume->get_transformation()); 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)); 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); assert(!old_volume->source.is_converted_from_inches || !old_volume->source.is_converted_from_meters);
if (old_volume->source.is_converted_from_inches) if (old_volume->source.is_converted_from_inches)
new_volume->convert_from_imperial_units(); 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) if (selection.is_wipe_tower() || get_selection().get_volume_idxs().size() != 1)
return; 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 object_idx = v->object_idx();
int volume_idx = v->volume_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->config.apply(old_volume->config);
new_volume->set_type(old_volume->type()); new_volume->set_type(old_volume->type());
new_volume->set_material_id(old_volume->material_id()); 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()) * new_volume->set_transformation(Geometry::assemble_transform(old_volume->source.transform.get_offset()) *
old_volume->get_transformation().get_matrix(true) * old_volume->get_transformation().get_matrix(true) *
old_volume->source.transform.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)); 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.object_idx = old_volume->source.object_idx;
new_volume->source.volume_idx = old_volume->source.volume_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); 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() || const bool is_some_full_instances = selection.is_single_full_instance() ||
selection.is_single_full_object() || selection.is_single_full_object() ||
selection.is_multiple_full_instance(); 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(); const bool is_part = selection.is_single_volume() || selection.is_single_modifier();
#endif // ENABLE_WORLD_COORDINATE
menu = is_some_full_instances ? menus.object_menu() : menu = is_some_full_instances ? menus.object_menu() :
is_part ? menus.part_menu() : menus.multi_selection_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) 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()); mesh = mesh_to_export(*model_object, (selection.is_single_full_object() && model_object->instances.size() > 1) ? -1 : selection.get_instance_idx());
else { 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 = model_object->volumes[volume->volume_idx()]->mesh();
mesh.transform(volume->get_volume_transformation().get_matrix(), true); 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_ #define slic3r_GUI_Selection_hpp_
#include "libslic3r/Geometry.hpp" #include "libslic3r/Geometry.hpp"
#if ENABLE_WORLD_COORDINATE
#include "GUI_Geometry.hpp"
#include "CoordAxes.hpp"
#else
#include "GLModel.hpp" #include "GLModel.hpp"
#endif // ENABLE_WORLD_COORDINATE
#include <set> #include <set>
#include <optional> #include <optional>
@ -24,6 +29,7 @@ using ModelObjectPtrs = std::vector<ModelObject*>;
namespace GUI { namespace GUI {
#if !ENABLE_WORLD_COORDINATE
class TransformationType class TransformationType
{ {
public: public:
@ -76,6 +82,7 @@ private:
Enum m_value; Enum m_value;
}; };
#endif // !ENABLE_WORLD_COORDINATE
class Selection class Selection
{ {
@ -110,16 +117,19 @@ private:
private: private:
struct TransformCache struct TransformCache
{ {
Vec3d position; Vec3d position{ Vec3d::Zero() };
Vec3d rotation; Vec3d rotation{ Vec3d::Zero() };
Vec3d scaling_factor; Vec3d scaling_factor{ Vec3d::Ones() };
Vec3d mirror; Vec3d mirror{ Vec3d::Ones() };
Transform3d rotation_matrix; Transform3d rotation_matrix{ Transform3d::Identity() };
Transform3d scale_matrix; Transform3d scale_matrix{ Transform3d::Identity() };
Transform3d mirror_matrix; Transform3d mirror_matrix{ Transform3d::Identity() };
Transform3d full_matrix; 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); explicit TransformCache(const Geometry::Transformation& transform);
}; };
@ -131,13 +141,18 @@ private:
VolumeCache(const Geometry::Transformation& volume_transform, const Geometry::Transformation& instance_transform); VolumeCache(const Geometry::Transformation& volume_transform, const Geometry::Transformation& instance_transform);
const Vec3d& get_volume_position() const { return m_volume.position; } 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_rotation() const { return m_volume.rotation; }
const Vec3d& get_volume_scaling_factor() const { return m_volume.scaling_factor; } const Vec3d& get_volume_scaling_factor() const { return m_volume.scaling_factor; }
const Vec3d& get_volume_mirror() const { return m_volume.mirror; } 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_rotation_matrix() const { return m_volume.rotation_matrix; }
const Transform3d& get_volume_scale_matrix() const { return m_volume.scale_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_mirror_matrix() const { return m_volume.mirror_matrix; }
const Transform3d& get_volume_full_matrix() const { return m_volume.full_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_position() const { return m_instance.position; }
const Vec3d& get_instance_rotation() const { return m_instance.rotation; } 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_scale_matrix() const { return m_instance.scale_matrix; }
const Transform3d& get_instance_mirror_matrix() const { return m_instance.mirror_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; } 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: public:
@ -207,15 +225,32 @@ private:
Cache m_cache; Cache m_cache;
Clipboard m_clipboard; Clipboard m_clipboard;
std::optional<BoundingBoxf3> m_bounding_box; std::optional<BoundingBoxf3> m_bounding_box;
// Bounding box of a selection, with no instance scaling applied. This bounding box // Bounding box of a single full instance selection, in world coordinates, with no instance scaling applied.
// is useful for absolute scaling of tilted objects in world coordinate space. // 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; 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; 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 #if ENABLE_RENDER_SELECTION_CENTER
GLModel m_vbo_sphere; GLModel m_vbo_sphere;
#endif // ENABLE_RENDER_SELECTION_CENTER #endif // ENABLE_RENDER_SELECTION_CENTER
#if ENABLE_WORLD_COORDINATE
CoordAxes m_axes;
#endif // ENABLE_WORLD_COORDINATE
GLModel m_arrow; GLModel m_arrow;
GLModel m_curved_arrow; GLModel m_curved_arrow;
#if ENABLE_LEGACY_OPENGL_REMOVAL #if ENABLE_LEGACY_OPENGL_REMOVAL
@ -290,6 +325,9 @@ public:
bool is_from_single_object() const; bool is_from_single_object() const;
bool is_sla_compliant() const; bool is_sla_compliant() const;
bool is_instance_mode() const { return m_mode == Instance; } 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(); } 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 // 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 // returns true if the selection contains all and only the given indices
bool matches(const std::vector<unsigned int>& volume_idxs) const; 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; 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 // Returns the the object id if the selection is from a single object, otherwise is -1
int get_object_idx() const; int get_object_idx() const;
@ -311,28 +360,60 @@ public:
const IndicesList& get_volume_idxs() const { return m_list; } const IndicesList& get_volume_idxs() const { return m_list; }
const GLVolume* get_volume(unsigned int volume_idx) const; 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; } const ObjectIdxsToInstanceIdxsMap& get_content() const { return m_cache.content; }
unsigned int volumes_count() const { return (unsigned int)m_list.size(); } unsigned int volumes_count() const { return (unsigned int)m_list.size(); }
const BoundingBoxf3& get_bounding_box() const; const BoundingBoxf3& get_bounding_box() const;
// Bounding box of a selection, with no instance scaling applied. This bounding box // Bounding box of a single full instance selection, in world coordinates, with no instance scaling applied.
// is useful for absolute scaling of tilted objects in world coordinate space. // 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; 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; 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(); void setup_cache();
#if ENABLE_WORLD_COORDINATE
void translate(const Vec3d& displacement, TransformationType transformation_type);
#else
void translate(const Vec3d& displacement, bool local = false); void translate(const Vec3d& displacement, bool local = false);
#endif // ENABLE_WORLD_COORDINATE
void rotate(const Vec3d& rotation, TransformationType transformation_type); void rotate(const Vec3d& rotation, TransformationType transformation_type);
void flattening_rotate(const Vec3d& normal); void flattening_rotate(const Vec3d& normal);
void scale(const Vec3d& scale, TransformationType transformation_type); void scale(const Vec3d& scale, TransformationType transformation_type);
void scale_to_fit_print_volume(const BuildVolume& volume); void scale_to_fit_print_volume(const BuildVolume& volume);
void mirror(Axis axis); 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); 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); 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 erase();
void render(float scale_factor = 1.0); void render(float scale_factor = 1.0);
@ -368,10 +449,23 @@ private:
void do_remove_volume(unsigned int volume_idx); void do_remove_volume(unsigned int volume_idx);
void do_remove_instance(unsigned int object_idx, unsigned int instance_idx); void do_remove_instance(unsigned int object_idx, unsigned int instance_idx);
void do_remove_object(unsigned int object_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(); } 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(); void render_synchronized_volumes();
#if ENABLE_LEGACY_OPENGL_REMOVAL #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); void render_bounding_box(const BoundingBoxf3& box, const ColorRGB& color);
#endif // ENABLE_WORLD_COORDINATE
#else #else
void render_selected_volumes() const; void render_selected_volumes() const;
void render_bounding_box(const BoundingBoxf3& box, float* color) const; void render_bounding_box(const BoundingBoxf3& box, float* color) const;
@ -389,11 +483,15 @@ private:
#endif // ENABLE_GL_SHADERS_ATTRIBUTES #endif // ENABLE_GL_SHADERS_ATTRIBUTES
public: public:
enum SyncRotationType { enum class SyncRotationType {
// Do not synchronize rotation. Either not rotating at all, or rotating by world Z axis. // Do not synchronize rotation. Either not rotating at all, or rotating by world Z axis.
SYNC_ROTATION_NONE = 0, NONE = 0,
// Synchronize after rotation by an axis not parallel with Z. // Synchronize after rotation by an axis not parallel with Z.
SYNC_ROTATION_GENERAL = 1, GENERAL = 1,
#if ENABLE_WORLD_COORDINATE
// Fully synchronize rotation.
FULL = 2,
#endif // ENABLE_WORLD_COORDINATE
}; };
void synchronize_unselected_instances(SyncRotationType sync_rotation_type); void synchronize_unselected_instances(SyncRotationType sync_rotation_type);
void synchronize_unselected_volumes(); void synchronize_unselected_volumes();
@ -405,6 +503,11 @@ private:
void paste_volumes_from_clipboard(); void paste_volumes_from_clipboard();
void paste_objects_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 } // namespace GUI

View File

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