NEW:add "world coordinates" scale for scale gizmo
upgrade Transformation class jira:none about 75% code is from PrusaSlicer,thanks for PrusaSlicer and enricoturri1966 commit b32e9366606dce7d4f8de8db84fd902113bdbe28 Author: enricoturri1966 <enricoturri@seznam.cz> Date: Tue Mar 7 14:32:18 2023 +0100 Rework of constrained scaling Change-Id: I1248ea586e6b8f2fb6cdf3aa901ed7f525c3f111 (cherry picked from commit e10381aad1412b0c47afa340b634faa3af9d1a1f)
This commit is contained in:
parent
0756fd979a
commit
c0536c09b4
|
@ -330,6 +330,10 @@ Vec3d extract_euler_angles(const Eigen::Matrix<double, 3, 3, Eigen::DontAlign>&
|
|||
return angles;
|
||||
}
|
||||
|
||||
Vec3d extract_rotation(const Transform3d &transform) {
|
||||
return extract_euler_angles(transform);
|
||||
}
|
||||
|
||||
Vec3d extract_euler_angles(const Transform3d& transform)
|
||||
{
|
||||
// use only the non-translational part of the transform
|
||||
|
@ -341,6 +345,56 @@ Vec3d extract_euler_angles(const Transform3d& transform)
|
|||
return extract_euler_angles(m);
|
||||
}
|
||||
|
||||
static Transform3d extract_rotation_matrix(const Transform3d &trafo)
|
||||
{
|
||||
Matrix3d rotation;
|
||||
Matrix3d scale;
|
||||
trafo.computeRotationScaling(&rotation, &scale);
|
||||
return Transform3d(rotation);
|
||||
}
|
||||
|
||||
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 Transform3d extract_scale(const Transform3d &trafo)
|
||||
{
|
||||
Matrix3d rotation;
|
||||
Matrix3d scale;
|
||||
trafo.computeRotationScaling(&rotation, &scale);
|
||||
return Transform3d(scale);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static bool contains_skew(const Transform3d &trafo)
|
||||
{
|
||||
Matrix3d rotation;
|
||||
Matrix3d scale;
|
||||
trafo.computeRotationScaling(&rotation, &scale);
|
||||
|
||||
if (scale.isDiagonal()) return false;
|
||||
|
||||
if (scale.determinant() >= 0.0) return true;
|
||||
|
||||
// the matrix contains mirror
|
||||
const Matrix3d ratio = scale.cwiseQuotient(trafo.matrix().block<3, 3>(0, 0));
|
||||
|
||||
auto check_skew = [&ratio](int i, int j, bool &skew) {
|
||||
if (!std::isnan(ratio(i, j)) && !std::isnan(ratio(j, i))) skew |= std::abs(ratio(i, j) * ratio(j, i) - 1.0) > EPSILON;
|
||||
};
|
||||
|
||||
bool has_skew = false;
|
||||
check_skew(0, 1, has_skew);
|
||||
check_skew(0, 2, has_skew);
|
||||
check_skew(1, 2, has_skew);
|
||||
return has_skew;
|
||||
}
|
||||
|
||||
void rotation_from_two_vectors(Vec3d from, Vec3d to, Vec3d& rotation_axis, double& phi, Matrix3d* rotation_matrix)
|
||||
{
|
||||
const Matrix3d m = Eigen::Quaterniond().setFromTwoVectors(from, to).toRotationMatrix();
|
||||
|
@ -385,95 +439,42 @@ Transform3d scale_transform(const Vec3d &scale)
|
|||
return transform;
|
||||
}
|
||||
|
||||
Transformation::Flags::Flags()
|
||||
: dont_translate(true)
|
||||
, dont_rotate(true)
|
||||
, dont_scale(true)
|
||||
, dont_mirror(true)
|
||||
Transform3d Transformation::get_offset_matrix() const { return translation_transform(get_offset()); }
|
||||
|
||||
const Vec3d &Transformation::get_rotation() const
|
||||
{
|
||||
m_temp_rotation = extract_rotation(extract_rotation_matrix(m_matrix));
|
||||
return m_temp_rotation;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void Transformation::Flags::set(bool dont_translate, bool dont_rotate, bool dont_scale, bool dont_mirror)
|
||||
{
|
||||
this->dont_translate = dont_translate;
|
||||
this->dont_rotate = dont_rotate;
|
||||
this->dont_scale = dont_scale;
|
||||
this->dont_mirror = dont_mirror;
|
||||
}
|
||||
|
||||
Transformation::Transformation()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
Transformation::Transformation(const Transform3d& transform)
|
||||
{
|
||||
set_from_transform(transform);
|
||||
}
|
||||
|
||||
Transform3d Transformation::get_offset_matrix() const {
|
||||
return translation_transform(get_offset());
|
||||
}
|
||||
|
||||
void Transformation::set_offset(const Vec3d &offset)
|
||||
{
|
||||
set_offset(X, offset(0));
|
||||
set_offset(Y, offset(1));
|
||||
set_offset(Z, offset(2));
|
||||
}
|
||||
|
||||
void Transformation::set_offset(Axis axis, double offset)
|
||||
{
|
||||
if (m_offset(axis) != offset)
|
||||
{
|
||||
m_offset(axis) = offset;
|
||||
m_dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
static Transform3d extract_rotation_matrix(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);
|
||||
}
|
||||
|
||||
Transform3d Transformation::get_rotation_matrix() const {
|
||||
return extract_rotation_matrix(m_matrix);
|
||||
}
|
||||
Transform3d Transformation::get_rotation_matrix() const { return extract_rotation_matrix(m_matrix); }
|
||||
|
||||
void Transformation::set_rotation(const Vec3d &rotation)
|
||||
{
|
||||
set_rotation(X, rotation(0));
|
||||
set_rotation(Y, rotation(1));
|
||||
set_rotation(Z, rotation(2));
|
||||
const Vec3d offset = get_offset();
|
||||
m_matrix = rotation_transform(rotation) * extract_scale(m_matrix);
|
||||
m_matrix.translation() = offset;
|
||||
}
|
||||
|
||||
void Transformation::set_rotation(Axis axis, double rotation)
|
||||
{
|
||||
rotation = angle_to_0_2PI(rotation);
|
||||
if (is_approx(std::abs(rotation), 2.0 * (double)PI))
|
||||
rotation = 0.0;
|
||||
if (is_approx(std::abs(rotation), 2.0 * double(PI))) rotation = 0.0;
|
||||
|
||||
if (m_rotation(axis) != rotation)
|
||||
{
|
||||
m_rotation(axis) = rotation;
|
||||
m_dirty = true;
|
||||
}
|
||||
auto [curr_rotation, scale] = extract_rotation_scale(m_matrix);
|
||||
Vec3d angles = extract_rotation(curr_rotation);
|
||||
angles[axis] = rotation;
|
||||
|
||||
const Vec3d offset = get_offset();
|
||||
m_matrix = rotation_transform(angles) * scale;
|
||||
m_matrix.translation() = offset;
|
||||
}
|
||||
|
||||
const Vec3d &Transformation::get_scaling_factor() const
|
||||
{
|
||||
const Transform3d scale = extract_scale(m_matrix);
|
||||
m_temp_scaling_factor= {std::abs(scale(0, 0)), std::abs(scale(1, 1)), std::abs(scale(2, 2))};
|
||||
return m_temp_scaling_factor;
|
||||
}
|
||||
|
||||
Transform3d Transformation::get_scaling_factor_matrix() const
|
||||
|
@ -485,27 +486,65 @@ Transform3d Transformation::get_scaling_factor_matrix() const
|
|||
return scale;
|
||||
}
|
||||
|
||||
void Transformation::set_scaling_factor(const Vec3d& scaling_factor)
|
||||
void Transformation::set_scaling_factor(const Vec3d &scaling_factor)
|
||||
{
|
||||
set_scaling_factor(X, scaling_factor(0));
|
||||
set_scaling_factor(Y, scaling_factor(1));
|
||||
set_scaling_factor(Z, scaling_factor(2));
|
||||
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_matrix(m_matrix) * scale_transform(scaling_factor);
|
||||
m_matrix.translation() = offset;
|
||||
}
|
||||
|
||||
void Transformation::set_scaling_factor(Axis axis, double scaling_factor)
|
||||
{
|
||||
if (m_scaling_factor(axis) != std::abs(scaling_factor))
|
||||
{
|
||||
m_scaling_factor(axis) = std::abs(scaling_factor);
|
||||
m_dirty = true;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
void Transformation::set_mirror(const Vec3d& mirror)
|
||||
const Vec3d &Transformation::get_mirror() const
|
||||
{
|
||||
set_mirror(X, mirror(0));
|
||||
set_mirror(Y, mirror(1));
|
||||
set_mirror(Z, mirror(2));
|
||||
const Transform3d scale = extract_scale(m_matrix);
|
||||
m_temp_mirror = {scale(0, 0) / std::abs(scale(0, 0)), scale(1, 1) / std::abs(scale(1, 1)), scale(2, 2) / std::abs(scale(2, 2))};
|
||||
return m_temp_mirror;
|
||||
}
|
||||
|
||||
Transform3d Transformation::get_mirror_matrix() const
|
||||
{
|
||||
Transform3d scale = extract_scale(m_matrix);
|
||||
scale(0, 0) = scale(0, 0) / std::abs(scale(0, 0));
|
||||
scale(1, 1) = scale(1, 1) / std::abs(scale(1, 1));
|
||||
scale(2, 2) = scale(2, 2) / std::abs(scale(2, 2));
|
||||
return scale;
|
||||
}
|
||||
|
||||
void Transformation::set_mirror(const Vec3d &mirror)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
auto [rotation, scale] = extract_rotation_scale(m_matrix);
|
||||
const Vec3d curr_scales = {scale(0, 0), scale(1, 1), scale(2, 2)};
|
||||
const Vec3d signs = curr_scales.cwiseProduct(copy);
|
||||
|
||||
if (signs[0] < 0.0) scale(0, 0) = -scale(0, 0);
|
||||
if (signs[1] < 0.0) scale(1, 1) = -scale(1, 1);
|
||||
if (signs[2] < 0.0) scale(2, 2) = -scale(2, 2);
|
||||
|
||||
const Vec3d offset = get_offset();
|
||||
m_matrix = rotation * scale;
|
||||
m_matrix.translation() = offset;
|
||||
}
|
||||
|
||||
void Transformation::set_mirror(Axis axis, double mirror)
|
||||
|
@ -516,101 +555,59 @@ void Transformation::set_mirror(Axis axis, double mirror)
|
|||
else if (abs_mirror != 1.0)
|
||||
mirror /= abs_mirror;
|
||||
|
||||
if (m_mirror(axis) != mirror)
|
||||
{
|
||||
m_mirror(axis) = mirror;
|
||||
m_dirty = true;
|
||||
}
|
||||
auto [rotation, scale] = extract_rotation_scale(m_matrix);
|
||||
const double curr_scale = scale(axis, axis);
|
||||
const double sign = curr_scale * mirror;
|
||||
|
||||
if (sign < 0.0) scale(axis, axis) = -scale(axis, axis);
|
||||
|
||||
const Vec3d offset = get_offset();
|
||||
m_matrix = rotation * scale;
|
||||
m_matrix.translation() = offset;
|
||||
}
|
||||
|
||||
void Transformation::set_from_transform(const Transform3d& transform)
|
||||
bool Transformation::has_skew() const { return contains_skew(m_matrix); }
|
||||
|
||||
void Transformation::reset() { m_matrix = Transform3d::Identity(); }
|
||||
|
||||
void Transformation::reset_rotation()
|
||||
{
|
||||
// offset
|
||||
set_offset(transform.matrix().block(0, 3, 3, 1));
|
||||
|
||||
Eigen::Matrix<double, 3, 3, Eigen::DontAlign> m3x3 = transform.matrix().block(0, 0, 3, 3);
|
||||
|
||||
// mirror
|
||||
// it is impossible to reconstruct the original mirroring factors from a matrix,
|
||||
// we can only detect if the matrix contains a left handed reference system
|
||||
// in which case we reorient it back to right handed by mirroring the x axis
|
||||
Vec3d mirror = Vec3d::Ones();
|
||||
if (m3x3.col(0).dot(m3x3.col(1).cross(m3x3.col(2))) < 0.0)
|
||||
{
|
||||
mirror(0) = -1.0;
|
||||
// remove mirror
|
||||
m3x3.col(0) *= -1.0;
|
||||
}
|
||||
set_mirror(mirror);
|
||||
|
||||
// scale
|
||||
set_scaling_factor(Vec3d(m3x3.col(0).norm(), m3x3.col(1).norm(), m3x3.col(2).norm()));
|
||||
|
||||
// remove scale
|
||||
m3x3.col(0).normalize();
|
||||
m3x3.col(1).normalize();
|
||||
m3x3.col(2).normalize();
|
||||
|
||||
// rotation
|
||||
set_rotation(Geometry::extract_euler_angles(m3x3));
|
||||
|
||||
// forces matrix recalculation matrix
|
||||
m_matrix = get_matrix();
|
||||
|
||||
// // debug check
|
||||
// if (!m_matrix.isApprox(transform))
|
||||
// std::cout << "something went wrong in extracting data from matrix" << std::endl;
|
||||
}
|
||||
|
||||
void Transformation::reset()
|
||||
{
|
||||
m_offset = Vec3d::Zero();
|
||||
m_rotation = Vec3d::Zero();
|
||||
m_scaling_factor = Vec3d::Ones();
|
||||
m_mirror = Vec3d::Ones();
|
||||
m_matrix = Transform3d::Identity();
|
||||
m_dirty = false;
|
||||
}
|
||||
|
||||
void Transformation::reset_rotation() {
|
||||
const Geometry::TransformationSVD svd(*this);
|
||||
m_matrix = get_offset_matrix() * Transform3d(svd.v * svd.s * svd.v.transpose()) * svd.mirror_matrix();
|
||||
m_rotation = Vec3d::Zero();
|
||||
}
|
||||
|
||||
void Transformation::reset_scaling_factor() {
|
||||
void Transformation::reset_scaling_factor()
|
||||
{
|
||||
const Geometry::TransformationSVD svd(*this);
|
||||
m_matrix = get_offset_matrix() * Transform3d(svd.u) * Transform3d(svd.v.transpose()) * svd.mirror_matrix();
|
||||
m_scaling_factor = Vec3d::Ones();
|
||||
}
|
||||
|
||||
void Transformation::reset_skew() {
|
||||
void Transformation::reset_skew()
|
||||
{
|
||||
auto new_scale_factor = [](const Matrix3d &s) {
|
||||
return pow(s(0, 0) * s(1, 1) * s(2, 2), 1. / 3.); // scale average
|
||||
};
|
||||
|
||||
const Geometry::TransformationSVD svd(*this);
|
||||
m_matrix = get_offset_matrix() * Transform3d(svd.u) * scale_transform(new_scale_factor(svd.s)) * Transform3d(svd.v.transpose()) * svd.mirror_matrix();
|
||||
const Transform3d scale_tran = extract_scale(m_matrix);
|
||||
m_scaling_factor = {std::abs(scale_tran(0, 0)), std::abs(scale_tran(1, 1)), std::abs(scale_tran(2, 2))};
|
||||
}
|
||||
|
||||
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))
|
||||
{
|
||||
m_matrix = Geometry::assemble_transform(
|
||||
dont_translate ? Vec3d::Zero() : m_offset,
|
||||
dont_rotate ? Vec3d::Zero() : m_rotation,
|
||||
dont_scale ? Vec3d::Ones() : m_scaling_factor,
|
||||
dont_mirror ? Vec3d::Ones() : m_mirror
|
||||
);
|
||||
|
||||
m_flags.set(dont_translate, dont_rotate, dont_scale, dont_mirror);
|
||||
m_dirty = false;
|
||||
}
|
||||
|
||||
if (dont_translate == false && dont_rotate == false && dont_scale == false && dont_mirror == false) {
|
||||
return m_matrix;
|
||||
}
|
||||
Transformation refence_tran(m_matrix);
|
||||
if (dont_translate)
|
||||
refence_tran.reset_offset();
|
||||
if (dont_rotate)
|
||||
refence_tran.reset_rotation();
|
||||
if (dont_scale)
|
||||
refence_tran.reset_scaling_factor();
|
||||
if (dont_mirror)
|
||||
refence_tran.reset_mirror();
|
||||
m_temp_matrix = refence_tran.get_matrix();
|
||||
return m_temp_matrix;
|
||||
}
|
||||
|
||||
Transform3d Transformation::get_matrix_no_offset() const
|
||||
|
@ -627,10 +624,9 @@ Transform3d Transformation::get_matrix_no_scaling_factor() const
|
|||
return copy.get_matrix();
|
||||
}
|
||||
|
||||
Transformation Transformation::operator * (const Transformation& other) const
|
||||
{
|
||||
return Transformation(get_matrix() * other.get_matrix());
|
||||
}
|
||||
Transformation Transformation::operator*(const Transformation &other) const { return Transformation(get_matrix() * other.get_matrix()); }
|
||||
//end Transformation
|
||||
|
||||
|
||||
Transformation Transformation::volume_to_bed_transformation(const Transformation& instance_transformation, const BoundingBoxf3& bbox)
|
||||
{
|
||||
|
|
|
@ -365,64 +365,58 @@ Transform3d scale_transform(const Vec3d &scale);
|
|||
|
||||
class Transformation
|
||||
{
|
||||
struct Flags
|
||||
{
|
||||
bool dont_translate;
|
||||
bool dont_rotate;
|
||||
bool dont_scale;
|
||||
bool dont_mirror;
|
||||
|
||||
Flags();
|
||||
|
||||
bool needs_update(bool dont_translate, bool dont_rotate, bool dont_scale, bool dont_mirror) const;
|
||||
void set(bool dont_translate, bool dont_rotate, bool dont_scale, bool dont_mirror);
|
||||
};
|
||||
|
||||
Vec3d m_offset; // In unscaled coordinates
|
||||
Vec3d m_rotation; // Rotation around the three axes, in radians around mesh center point
|
||||
Vec3d m_scaling_factor; // Scaling factors along the three axes
|
||||
Vec3d m_mirror; // Mirroring along the three axes
|
||||
|
||||
mutable Transform3d m_matrix;
|
||||
mutable Flags m_flags;
|
||||
mutable bool m_dirty;
|
||||
|
||||
Transform3d m_matrix{Transform3d::Identity()};
|
||||
mutable Transform3d m_temp_matrix{Transform3d::Identity()};//just for return
|
||||
mutable Vec3d m_temp_offset{Vec3d::Zero()}; // just for return
|
||||
mutable Vec3d m_temp_rotation{Vec3d::Zero()}; // just for return
|
||||
mutable Vec3d m_temp_scaling_factor{Vec3d::Ones()}; // just for return
|
||||
mutable Vec3d m_temp_mirror{Vec3d::Ones()}; // just for return
|
||||
public:
|
||||
Transformation();
|
||||
explicit Transformation(const Transform3d& transform);
|
||||
Transformation() = default;
|
||||
Transformation(const Transformation &trans) : m_matrix(trans.get_matrix()) {}
|
||||
explicit Transformation(const Transform3d &transform) : m_matrix(transform) {}
|
||||
|
||||
//BBS: add get dirty function
|
||||
bool is_dirty() { return m_dirty; }
|
||||
const Vec3d& get_offset() const{ m_temp_offset = m_matrix.translation();return m_temp_offset;}
|
||||
double get_offset(Axis axis) const { return get_offset()[axis]; }
|
||||
|
||||
const Vec3d& get_offset() const { return m_offset; }
|
||||
double get_offset(Axis axis) const { return m_offset(axis); }
|
||||
Transform3d get_offset_matrix() const;
|
||||
void set_offset(const Vec3d& offset);
|
||||
void set_offset(Axis axis, double offset);
|
||||
|
||||
const Vec3d& get_rotation() const { return m_rotation; }
|
||||
double get_rotation(Axis axis) const { return m_rotation(axis); }
|
||||
void set_offset(const Vec3d &offset) { m_matrix.translation() = offset; }
|
||||
void set_offset(Axis axis, double offset) { m_matrix.translation()[axis] = offset; }
|
||||
|
||||
const Vec3d &get_rotation() const;
|
||||
double get_rotation(Axis axis) const { return get_rotation()[axis]; }
|
||||
|
||||
Transform3d get_rotation_matrix() const;
|
||||
void set_rotation(const Vec3d& rotation);
|
||||
|
||||
void set_rotation(const Vec3d &rotation);
|
||||
void set_rotation(Axis axis, double rotation);
|
||||
|
||||
const Vec3d &get_scaling_factor() const;
|
||||
double get_scaling_factor(Axis axis) const { return get_scaling_factor()[axis]; }
|
||||
|
||||
Transform3d get_scaling_factor_matrix() const;
|
||||
const Vec3d& get_scaling_factor() const { return m_scaling_factor; }
|
||||
double get_scaling_factor(Axis axis) const { return m_scaling_factor(axis); }
|
||||
|
||||
void set_scaling_factor(const Vec3d& scaling_factor);
|
||||
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;
|
||||
}
|
||||
|
||||
void set_scaling_factor(const Vec3d &scaling_factor);
|
||||
void set_scaling_factor(Axis axis, double scaling_factor);
|
||||
bool is_scaling_uniform() const { return std::abs(m_scaling_factor.x() - m_scaling_factor.y()) < 1e-8 && std::abs(m_scaling_factor.x() - m_scaling_factor.z()) < 1e-8; }
|
||||
|
||||
const Vec3d& get_mirror() const { return m_mirror; }
|
||||
double get_mirror(Axis axis) const { return m_mirror(axis); }
|
||||
bool is_left_handed() const { return m_mirror.x() * m_mirror.y() * m_mirror.z() < 0.; }
|
||||
const Vec3d &get_mirror() const;
|
||||
double get_mirror(Axis axis) const { return get_mirror()[axis]; }
|
||||
|
||||
void set_mirror(const Vec3d& mirror);
|
||||
Transform3d get_mirror_matrix() const;
|
||||
|
||||
bool is_left_handed() const { return m_matrix.linear().determinant() < 0; }
|
||||
|
||||
void set_mirror(const Vec3d &mirror);
|
||||
void set_mirror(Axis axis, double mirror);
|
||||
|
||||
void set_from_transform(const Transform3d& transform);
|
||||
void set_matrix(const Transform3d &transform) { set_from_transform(transform); }
|
||||
bool has_skew() const;
|
||||
|
||||
void reset();
|
||||
void reset_offset() { set_offset(Vec3d::Zero()); }
|
||||
|
@ -431,31 +425,27 @@ public:
|
|||
void reset_mirror() { set_mirror(Vec3d::Ones()); }
|
||||
void reset_skew();
|
||||
|
||||
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;
|
||||
|
||||
Transform3d get_matrix_no_offset() const;
|
||||
Transform3d get_matrix_no_scaling_factor() const;
|
||||
|
||||
Transformation operator * (const Transformation& other) const;
|
||||
|
||||
// Find volume transformation, so that the chained (instance_trafo * volume_trafo) will be as close to identity
|
||||
// as possible in least squares norm in regard to the 8 corners of bbox.
|
||||
// Bounding box is expected to be centered around zero in all axes.
|
||||
static Transformation volume_to_bed_transformation(const Transformation& instance_transformation, const BoundingBoxf3& bbox);
|
||||
|
||||
void set_matrix(const Transform3d &transform) { m_matrix = transform; }
|
||||
void set_from_transform(const Transform3d &transform) { m_matrix = transform; }//add
|
||||
Transformation operator*(const Transformation &other) const;
|
||||
static Transformation volume_to_bed_transformation(const Transformation &instance_transformation, const BoundingBoxf3 &bbox);
|
||||
// BBS: backup use this compare
|
||||
friend bool operator==(Transformation const& l, Transformation const& r) {
|
||||
return l.m_offset == r.m_offset && l.m_rotation == r.m_rotation && l.m_scaling_factor == r.m_scaling_factor && l.m_mirror == r.m_mirror;
|
||||
}
|
||||
|
||||
friend bool operator==(Transformation const &l, Transformation const &r) { return l.m_matrix.isApprox(r.m_matrix); }
|
||||
friend bool operator!=(Transformation const &l, Transformation const &r) { return !(l == r); }
|
||||
private:
|
||||
friend class cereal::access;
|
||||
template<class Archive> void serialize(Archive & ar) { ar(m_offset, m_rotation, m_scaling_factor, m_mirror); }
|
||||
explicit Transformation(int) : m_dirty(true) {}
|
||||
template <class Archive> static void load_and_construct(Archive &ar, cereal::construct<Transformation> &construct)
|
||||
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_offset, construct.ptr()->m_rotation, construct.ptr()->m_scaling_factor, construct.ptr()->m_mirror);
|
||||
ar(construct.ptr()->m_matrix);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -3348,6 +3348,11 @@ void ModelVolume::convert_from_meters()
|
|||
this->source.is_converted_from_meters = true;
|
||||
}
|
||||
|
||||
const Transform3d &ModelVolume::get_matrix(bool dont_translate, bool dont_rotate, bool dont_scale, bool dont_mirror) const
|
||||
{
|
||||
return m_transformation.get_matrix(dont_translate, dont_rotate, dont_scale, dont_mirror);
|
||||
}
|
||||
|
||||
void ModelInstance::transform_mesh(TriangleMesh* mesh, bool dont_translate) const
|
||||
{
|
||||
mesh->transform(get_matrix(dont_translate));
|
||||
|
@ -3402,6 +3407,11 @@ void ModelInstance::transform_polygon(Polygon* polygon) const
|
|||
polygon->scale(get_scaling_factor(X), get_scaling_factor(Y)); // scale around polygon origin
|
||||
}
|
||||
|
||||
const Transform3d &ModelInstance::get_matrix(bool dont_translate, bool dont_rotate, bool dont_scale, bool dont_mirror) const
|
||||
{
|
||||
return m_transformation.get_matrix(dont_translate, dont_rotate, dont_scale, dont_mirror);
|
||||
}
|
||||
|
||||
//BBS
|
||||
// BBS set print speed table and find maximum speed
|
||||
void Model::setPrintSpeedTable(const DynamicPrintConfig& config, const PrintConfig& print_config) {
|
||||
|
|
|
@ -1000,7 +1000,7 @@ public:
|
|||
void set_rotation(const Vec3d& rotation) { m_transformation.set_rotation(rotation); }
|
||||
void set_rotation(Axis axis, double rotation) { m_transformation.set_rotation(axis, rotation); }
|
||||
|
||||
Vec3d get_scaling_factor() const { return m_transformation.get_scaling_factor(); }
|
||||
const Vec3d &get_scaling_factor() const { return m_transformation.get_scaling_factor(); }
|
||||
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); }
|
||||
|
@ -1018,8 +1018,7 @@ public:
|
|||
void set_text_info(const TextInfo& text_info) { m_text_info = text_info; }
|
||||
const TextInfo& get_text_info() const { return m_text_info; }
|
||||
|
||||
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;
|
||||
void set_new_unique_id() {
|
||||
ObjectBase::set_new_unique_id();
|
||||
this->config.set_new_unique_id();
|
||||
|
@ -1275,7 +1274,7 @@ public:
|
|||
m_assemble_initialized = true;
|
||||
m_assemble_transformation = transformation;
|
||||
}
|
||||
void set_assemble_from_transform(Transform3d& transform) {
|
||||
void set_assemble_from_transform(const Transform3d& transform) {
|
||||
m_assemble_initialized = true;
|
||||
m_assemble_transformation.set_from_transform(transform);
|
||||
}
|
||||
|
@ -1336,8 +1335,7 @@ public:
|
|||
// To be called on an external polygon. It does not translate the polygon, only rotates and scales.
|
||||
void transform_polygon(Polygon* polygon) const;
|
||||
|
||||
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;
|
||||
bool is_printable() const { return object->printable && printable && (print_volume_state == ModelInstancePVS_Inside); }
|
||||
bool is_assemble_initialized() { return m_assemble_initialized; }
|
||||
|
||||
|
|
|
@ -2278,7 +2278,11 @@ std::vector<int> GLCanvas3D::load_object(const Model& model, int obj_idx)
|
|||
|
||||
void GLCanvas3D::mirror_selection(Axis axis)
|
||||
{
|
||||
m_selection.mirror(axis);
|
||||
TransformationType transformation_type;
|
||||
//transformation_type.set_world();
|
||||
transformation_type.set_relative();
|
||||
m_selection.setup_cache();
|
||||
m_selection.mirror(axis, transformation_type);
|
||||
do_mirror(L("Mirror Object"));
|
||||
// BBS
|
||||
//wxGetApp().obj_manipul()->set_dirty();
|
||||
|
@ -4794,11 +4798,9 @@ void GLCanvas3D::do_rotate(const std::string& snapshot_type)
|
|||
if (model_object != nullptr) {
|
||||
if (selection_mode == Selection::Instance) {
|
||||
if (m_canvas_type == GLCanvas3D::ECanvasType::CanvasAssembleView) {
|
||||
model_object->instances[instance_idx]->set_assemble_rotation(v->get_instance_rotation());
|
||||
model_object->instances[instance_idx]->set_assemble_offset(v->get_instance_offset());
|
||||
model_object->instances[instance_idx]->set_assemble_from_transform(v->get_instance_transformation().get_matrix());
|
||||
} else {
|
||||
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_transformation(v->get_instance_transformation());
|
||||
}
|
||||
}
|
||||
else if (selection_mode == Selection::Volume) {
|
||||
|
@ -4812,8 +4814,7 @@ void GLCanvas3D::do_rotate(const std::string& snapshot_type)
|
|||
old_text_world_tran = mi->get_transformation().get_matrix() * cur_mv->get_matrix();
|
||||
}
|
||||
|
||||
cur_mv->set_rotation(v->get_volume_rotation());
|
||||
cur_mv->set_offset(v->get_volume_offset());
|
||||
cur_mv->set_transformation(v->get_volume_transformation());
|
||||
if (is_text_mv) { // deal text_info
|
||||
auto cur_text_world_tran = mi->get_transformation().get_matrix() * cur_mv->get_matrix();
|
||||
generate_new_hit_in_text_info(cur_mv, model_object, mi, old_text_world_tran, cur_text_world_tran, text_info, 1);
|
||||
|
@ -4893,8 +4894,7 @@ void GLCanvas3D::do_scale(const std::string& snapshot_type)
|
|||
ModelObject* model_object = m_model->objects[object_idx];
|
||||
if (model_object != nullptr) {
|
||||
if (selection_mode == Selection::Instance) {
|
||||
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_transformation(v->get_instance_transformation());
|
||||
}
|
||||
else if (selection_mode == Selection::Volume) {
|
||||
auto cur_mv = model_object->volumes[volume_idx];
|
||||
|
@ -4907,9 +4907,8 @@ void GLCanvas3D::do_scale(const std::string& snapshot_type)
|
|||
old_text_world_tran = mi->get_transformation().get_matrix() * cur_mv->get_matrix();
|
||||
}
|
||||
|
||||
model_object->instances[instance_idx]->set_offset(v->get_instance_offset());
|
||||
cur_mv->set_scaling_factor(v->get_volume_scaling_factor());
|
||||
cur_mv->set_offset(v->get_volume_offset());
|
||||
model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
|
||||
cur_mv->set_transformation(v->get_volume_transformation());
|
||||
|
||||
if (is_text_mv) { // deal text_info
|
||||
auto cur_text_world_tran = mi->get_transformation().get_matrix() * cur_mv->get_matrix();
|
||||
|
@ -5014,10 +5013,10 @@ void GLCanvas3D::do_mirror(const std::string& snapshot_type)
|
|||
ModelObject* model_object = m_model->objects[object_idx];
|
||||
if (model_object != nullptr) {
|
||||
if (selection_mode == Selection::Instance)
|
||||
model_object->instances[instance_idx]->set_mirror(v->get_instance_mirror());
|
||||
model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
|
||||
else if (selection_mode == Selection::Volume) {
|
||||
if (model_object->volumes[volume_idx]->get_mirror() != v->get_volume_mirror()) {
|
||||
model_object->volumes[volume_idx]->set_mirror(v->get_volume_mirror());
|
||||
if (model_object->volumes[volume_idx]->get_transformation() != v->get_volume_transformation()) {
|
||||
model_object->volumes[volume_idx]->set_transformation(v->get_volume_transformation());
|
||||
// BBS: backup
|
||||
Slic3r::save_object_mesh(*model_object);
|
||||
}
|
||||
|
|
|
@ -63,6 +63,11 @@ std::string GLGizmoScale3D::get_tooltip() const
|
|||
return "";
|
||||
}
|
||||
|
||||
void GLGizmoScale3D::data_changed(bool is_serializing)
|
||||
{
|
||||
change_cs_by_selection();
|
||||
}
|
||||
|
||||
void GLGizmoScale3D::enable_ununiversal_scale(bool enable)
|
||||
{
|
||||
for (unsigned int i = 0; i < 6; ++i)
|
||||
|
@ -78,13 +83,6 @@ bool GLGizmoScale3D::on_init()
|
|||
|
||||
double half_pi = 0.5 * (double)PI;
|
||||
|
||||
// x axis
|
||||
m_grabbers[0].angles(1) = half_pi;
|
||||
m_grabbers[1].angles(1) = half_pi;
|
||||
|
||||
// y axis
|
||||
m_grabbers[2].angles(0) = half_pi;
|
||||
m_grabbers[3].angles(0) = half_pi;
|
||||
|
||||
// BBS
|
||||
m_grabbers[4].enabled = false;
|
||||
|
@ -110,28 +108,50 @@ bool GLGizmoScale3D::on_is_activable() const
|
|||
|
||||
void GLGizmoScale3D::on_set_state() {
|
||||
if (get_state() == On) {
|
||||
m_object_manipulation->set_coordinates_type(ECoordinatesType::Local);
|
||||
m_last_selected_obejct_idx = -1;
|
||||
m_last_selected_volume_idx = -1;
|
||||
change_cs_by_selection();
|
||||
}
|
||||
}
|
||||
|
||||
static int constraint_id(int grabber_id)
|
||||
{
|
||||
static const std::vector<int> id_map = {1, 0, 3, 2, 5, 4, 8, 9, 6, 7};
|
||||
return (0 <= grabber_id && grabber_id < (int) id_map.size()) ? id_map[grabber_id] : -1;
|
||||
}
|
||||
|
||||
void GLGizmoScale3D::on_start_dragging()
|
||||
{
|
||||
if (m_hover_id != -1)
|
||||
{
|
||||
m_starting.drag_position = m_grabbers[m_hover_id].center;
|
||||
m_starting.plane_center = m_grabbers[4].center;
|
||||
m_starting.plane_nromal = m_grabbers[5].center - m_grabbers[4].center;
|
||||
if (m_hover_id != -1) {
|
||||
auto grabbers_transform = m_grabbers_tran.get_matrix();
|
||||
m_starting.drag_position = grabbers_transform * m_grabbers[m_hover_id].center;
|
||||
m_starting.plane_center = grabbers_transform * m_grabbers[4].center; // plane_center = bottom center
|
||||
m_starting.plane_nromal = (grabbers_transform * m_grabbers[5].center - grabbers_transform * m_grabbers[4].center).normalized();
|
||||
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();
|
||||
m_starting.box = m_bounding_box;
|
||||
|
||||
const Vec3d& center = m_starting.box.center();
|
||||
m_starting.pivots[0] = m_transform * Vec3d(m_starting.box.max(0), center(1), center(2));
|
||||
m_starting.pivots[1] = m_transform * Vec3d(m_starting.box.min(0), center(1), center(2));
|
||||
m_starting.pivots[2] = m_transform * Vec3d(center(0), m_starting.box.max(1), center(2));
|
||||
m_starting.pivots[3] = m_transform * Vec3d(center(0), m_starting.box.min(1), center(2));
|
||||
m_starting.pivots[4] = m_transform * Vec3d(center(0), center(1), m_starting.box.max(2));
|
||||
m_starting.pivots[5] = m_transform * Vec3d(center(0), center(1), m_starting.box.min(2));
|
||||
m_starting.center = m_center;
|
||||
m_starting.instance_center = m_instance_center;
|
||||
|
||||
const Vec3d box_half_size = 0.5 * m_bounding_box.size();
|
||||
|
||||
m_starting.local_pivots[0] = Vec3d(box_half_size.x(), 0.0, -box_half_size.z());
|
||||
m_starting.local_pivots[1] = Vec3d(-box_half_size.x(), 0.0, -box_half_size.z());
|
||||
m_starting.local_pivots[2] = Vec3d(0.0, box_half_size.y(), -box_half_size.z());
|
||||
m_starting.local_pivots[3] = Vec3d(0.0, -box_half_size.y(), -box_half_size.z());
|
||||
m_starting.local_pivots[4] = Vec3d(0.0, 0.0, box_half_size.z());
|
||||
m_starting.local_pivots[5] = Vec3d(0.0, 0.0, -box_half_size.z());
|
||||
for (size_t i = 0; i < 6; i++) {
|
||||
m_starting.pivots[i] = grabbers_transform * m_starting.local_pivots[i]; // todo delete
|
||||
}
|
||||
m_starting.constraint_position = grabbers_transform * m_grabbers[constraint_id(m_hover_id)].center;
|
||||
m_scale = m_starting.scale = Vec3d::Ones() ;
|
||||
m_offset = Vec3d::Zero();
|
||||
}
|
||||
}
|
||||
|
||||
void GLGizmoScale3D::on_stop_dragging()
|
||||
{
|
||||
}
|
||||
|
||||
void GLGizmoScale3D::on_update(const UpdateData& data)
|
||||
|
@ -146,100 +166,83 @@ void GLGizmoScale3D::on_update(const UpdateData& data)
|
|||
do_scale_uniform(data);
|
||||
}
|
||||
|
||||
void GLGizmoScale3D::on_render()
|
||||
void GLGizmoScale3D::update_grabbers_data()
|
||||
{
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
const Selection &selection = m_parent.get_selection();
|
||||
const auto &[box, box_trafo] = selection.get_bounding_box_in_current_reference_system();
|
||||
m_bounding_box = box;
|
||||
m_center = box_trafo.translation();
|
||||
m_grabbers_tran.set_matrix(box_trafo);
|
||||
m_instance_center = (selection.is_single_full_instance() || selection.is_single_volume_or_modifier()) ? selection.get_first_volume()->get_instance_offset() : m_center;
|
||||
|
||||
const Vec3d box_half_size = 0.5 * m_bounding_box.size();
|
||||
bool ctrl_down = wxGetKeyState(WXK_CONTROL);
|
||||
|
||||
|
||||
bool single_instance = selection.is_single_full_instance();
|
||||
bool single_volume = selection.is_single_modifier() || selection.is_single_volume();
|
||||
|
||||
// x axis
|
||||
m_grabbers[0].center = Vec3d(-(box_half_size.x()), 0.0, -box_half_size.z());
|
||||
m_grabbers[0].color = (ctrl_down && m_hover_id == 1) ? CONSTRAINED_COLOR : AXES_COLOR[0];
|
||||
m_grabbers[1].center = Vec3d(box_half_size.x(), 0.0, -box_half_size.z());
|
||||
m_grabbers[1].color = (ctrl_down && m_hover_id == 0) ? CONSTRAINED_COLOR : AXES_COLOR[0];
|
||||
// y axis
|
||||
m_grabbers[2].center = Vec3d(0.0, -(box_half_size.y()), -box_half_size.z());
|
||||
m_grabbers[2].color = (ctrl_down && m_hover_id == 3) ? CONSTRAINED_COLOR : AXES_COLOR[1];
|
||||
m_grabbers[3].center = Vec3d(0.0, box_half_size.y(), -box_half_size.z());
|
||||
m_grabbers[3].color = (ctrl_down && m_hover_id == 2) ? CONSTRAINED_COLOR : AXES_COLOR[1];
|
||||
// z axis do not show 4
|
||||
m_grabbers[4].center = Vec3d(0.0, 0.0, -(box_half_size.z()));
|
||||
m_grabbers[4].enabled = false;
|
||||
|
||||
m_grabbers[5].center = Vec3d(0.0, 0.0, box_half_size.z());
|
||||
m_grabbers[5].color = (ctrl_down && m_hover_id == 4) ? CONSTRAINED_COLOR : AXES_COLOR[2];
|
||||
// uniform
|
||||
m_grabbers[6].center = Vec3d(-box_half_size.x(), -box_half_size.y(), -box_half_size.z());
|
||||
m_grabbers[6].color = (ctrl_down && m_hover_id == 8) ? CONSTRAINED_COLOR : GRABBER_UNIFORM_COL;
|
||||
m_grabbers[7].center = Vec3d(box_half_size.x(), -box_half_size.y(), -box_half_size.z());
|
||||
m_grabbers[7].color = (ctrl_down && m_hover_id == 9) ? CONSTRAINED_COLOR : GRABBER_UNIFORM_COL;
|
||||
m_grabbers[8].center = Vec3d(box_half_size.x(), box_half_size.y(), -box_half_size.z());
|
||||
m_grabbers[8].color = (ctrl_down && m_hover_id == 6) ? CONSTRAINED_COLOR : GRABBER_UNIFORM_COL;
|
||||
m_grabbers[9].center = Vec3d(-box_half_size.x(), box_half_size.y(), -box_half_size.z());
|
||||
m_grabbers[9].color = (ctrl_down && m_hover_id == 7) ? CONSTRAINED_COLOR : GRABBER_UNIFORM_COL;
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
//m_grabbers[i].color = AXES_COLOR[i / 2];
|
||||
m_grabbers[i].hover_color = AXES_HOVER_COLOR[i / 2];
|
||||
}
|
||||
for (int i = 6; i < 10; ++i) {
|
||||
//m_grabbers[i].color = GRABBER_UNIFORM_COL;
|
||||
m_grabbers[i].hover_color = GRABBER_UNIFORM_HOVER_COL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GLGizmoScale3D::change_cs_by_selection() {
|
||||
int obejct_idx, volume_idx;
|
||||
ModelVolume *model_volume = m_parent.get_selection().get_selected_single_volume(obejct_idx, volume_idx);
|
||||
if (m_last_selected_obejct_idx == obejct_idx && m_last_selected_volume_idx == volume_idx) { return; }
|
||||
m_last_selected_obejct_idx = obejct_idx;
|
||||
m_last_selected_volume_idx = volume_idx;
|
||||
if (m_parent.get_selection().is_multiple_full_object()) {
|
||||
m_object_manipulation->set_coordinates_type(ECoordinatesType::World);
|
||||
} else if (model_volume) {
|
||||
m_object_manipulation->set_coordinates_type(ECoordinatesType::Local);
|
||||
}
|
||||
}
|
||||
|
||||
void GLGizmoScale3D::on_render()
|
||||
{
|
||||
glsafe(::glClear(GL_DEPTH_BUFFER_BIT));
|
||||
glsafe(::glEnable(GL_DEPTH_TEST));
|
||||
|
||||
m_box.reset();
|
||||
m_transform = Transform3d::Identity();
|
||||
// Transforms grabbers' offsets to world refefence system
|
||||
Transform3d offsets_transform = Transform3d::Identity();
|
||||
m_offsets_transform = Transform3d::Identity();
|
||||
Vec3d angles = Vec3d::Zero();
|
||||
|
||||
if (single_instance) {
|
||||
// calculate bounding box in instance local reference system
|
||||
const Selection::IndicesList& idxs = selection.get_volume_idxs();
|
||||
for (unsigned int idx : idxs) {
|
||||
const GLVolume* vol = selection.get_volume(idx);
|
||||
m_box.merge(vol->bounding_box().transformed(vol->get_volume_transformation().get_matrix()));
|
||||
}
|
||||
|
||||
// gets transform from first selected volume
|
||||
const GLVolume* v = selection.get_volume(*idxs.begin());
|
||||
m_transform = v->get_instance_transformation().get_matrix();
|
||||
// gets angles from first selected volume
|
||||
angles = v->get_instance_rotation();
|
||||
// consider rotation+mirror only components of the transform for offsets
|
||||
offsets_transform = Geometry::assemble_transform(Vec3d::Zero(), angles, Vec3d::Ones(), v->get_instance_mirror());
|
||||
m_offsets_transform = offsets_transform;
|
||||
}
|
||||
else if (single_volume) {
|
||||
const GLVolume* v = selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
m_box = v->bounding_box();
|
||||
m_transform = v->world_matrix();
|
||||
angles = Geometry::extract_euler_angles(m_transform);
|
||||
// consider rotation+mirror only components of the transform for offsets
|
||||
offsets_transform = Geometry::assemble_transform(Vec3d::Zero(), angles, Vec3d::Ones(), v->get_instance_mirror());
|
||||
m_offsets_transform = Geometry::assemble_transform(Vec3d::Zero(), v->get_volume_rotation(), Vec3d::Ones(), v->get_volume_mirror());
|
||||
}
|
||||
else
|
||||
m_box = selection.get_bounding_box();
|
||||
|
||||
const Vec3d& center = m_box.center();
|
||||
Vec3d offset_x = offsets_transform * Vec3d((double)Offset, 0.0, 0.0);
|
||||
Vec3d offset_y = offsets_transform * Vec3d(0.0, (double)Offset, 0.0);
|
||||
Vec3d offset_z = offsets_transform * Vec3d(0.0, 0.0, (double)Offset);
|
||||
|
||||
bool ctrl_down = (m_dragging && m_starting.ctrl_down) || (!m_dragging && wxGetKeyState(WXK_CONTROL));
|
||||
|
||||
// x axis
|
||||
m_grabbers[0].center = m_transform * Vec3d(m_box.min(0), center(1), m_box.min(2));
|
||||
m_grabbers[1].center = m_transform * Vec3d(m_box.max(0), center(1), m_box.min(2));
|
||||
|
||||
// y axis
|
||||
m_grabbers[2].center = m_transform * Vec3d(center(0), m_box.min(1), m_box.min(2));
|
||||
m_grabbers[3].center = m_transform * Vec3d(center(0), m_box.max(1), m_box.min(2));
|
||||
|
||||
// z axis do not show 4
|
||||
m_grabbers[4].center = m_transform * Vec3d(center(0), center(1), m_box.min(2));
|
||||
m_grabbers[4].enabled = false;
|
||||
|
||||
m_grabbers[5].center = m_transform * Vec3d(center(0), center(1), m_box.max(2));
|
||||
|
||||
// uniform
|
||||
m_grabbers[6].center = m_transform * Vec3d(m_box.min(0), m_box.min(1), m_box.min(2));
|
||||
m_grabbers[7].center = m_transform * Vec3d(m_box.max(0), m_box.min(1), m_box.min(2));
|
||||
m_grabbers[8].center = m_transform * Vec3d(m_box.max(0), m_box.max(1), m_box.min(2));
|
||||
m_grabbers[9].center = m_transform * Vec3d(m_box.min(0), m_box.max(1), m_box.min(2));
|
||||
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
m_grabbers[i].color = AXES_COLOR[i/2];
|
||||
m_grabbers[i].hover_color = AXES_HOVER_COLOR[i/2];
|
||||
}
|
||||
|
||||
for (int i = 6; i < 10; ++i) {
|
||||
m_grabbers[i].color = GRABBER_UNIFORM_COL;
|
||||
m_grabbers[i].hover_color = GRABBER_UNIFORM_HOVER_COL;
|
||||
}
|
||||
|
||||
// sets grabbers orientation
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
m_grabbers[i].angles = angles;
|
||||
}
|
||||
update_grabbers_data();
|
||||
|
||||
glsafe(::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f));
|
||||
|
||||
const BoundingBoxf3& selection_box = selection.get_bounding_box();
|
||||
|
||||
float grabber_mean_size = (float)((selection_box.size()(0) + selection_box.size()(1) + selection_box.size()(2)) / 3.0);
|
||||
|
||||
float grabber_mean_size = (float) ((m_bounding_box.size().x() + m_bounding_box.size().y() + m_bounding_box.size().z()) / 3.0);
|
||||
glsafe(::glPushMatrix());
|
||||
glsafe(::glMultMatrixd(m_grabbers_tran.get_matrix().data()));
|
||||
//draw connections
|
||||
|
||||
// BBS: when select multiple objects, uniform scale can be deselected, display the connection(4,5)
|
||||
|
@ -260,12 +263,16 @@ void GLGizmoScale3D::on_render()
|
|||
|
||||
// draw grabbers
|
||||
render_grabbers(grabber_mean_size);
|
||||
glsafe(::glPopMatrix());
|
||||
}
|
||||
|
||||
void GLGizmoScale3D::on_render_for_picking()
|
||||
{
|
||||
glsafe(::glDisable(GL_DEPTH_TEST));
|
||||
glsafe(::glPushMatrix());
|
||||
glsafe(::glMultMatrixd(m_grabbers_tran.get_matrix().data()));
|
||||
render_grabbers_for_picking(m_parent.get_selection().get_bounding_box());
|
||||
glsafe(::glPopMatrix());
|
||||
}
|
||||
|
||||
void GLGizmoScale3D::render_grabbers_connection(unsigned int id_1, unsigned int id_2) const
|
||||
|
@ -296,22 +303,25 @@ void GLGizmoScale3D::do_scale_along_axis(Axis axis, const UpdateData& data)
|
|||
if (ratio > 0.0)
|
||||
{
|
||||
m_scale(axis) = m_starting.scale(axis) * ratio;
|
||||
if (m_starting.ctrl_down)
|
||||
{
|
||||
if (m_starting.ctrl_down && abs(ratio-1.0f)>0.001) {
|
||||
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;
|
||||
|
||||
}
|
||||
Vec3d local_offset_vec;
|
||||
switch (axis)
|
||||
{
|
||||
case X: { local_offset_vec = local_offset * Vec3d::UnitX(); break; }
|
||||
case Y: { local_offset_vec = local_offset * Vec3d::UnitY(); break; }
|
||||
case Z: { local_offset_vec = local_offset * Vec3d::UnitZ(); break; }
|
||||
case Y: { local_offset_vec = local_offset * Vec3d::UnitY(); break;}
|
||||
case Z: { local_offset_vec = local_offset * Vec3d::UnitZ(); break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
|
||||
m_offset = m_offsets_transform * local_offset_vec;
|
||||
if (m_object_manipulation->is_world_coordinates()) {
|
||||
m_offset = local_offset_vec;
|
||||
} else {//if (m_object_manipulation->is_instance_coordinates())
|
||||
m_offset = m_grabbers_tran.get_matrix_no_offset() * local_offset_vec;
|
||||
}
|
||||
}
|
||||
else
|
||||
m_offset = Vec3d::Zero();
|
||||
|
@ -332,7 +342,7 @@ double GLGizmoScale3D::calc_ratio(const UpdateData& data) const
|
|||
{
|
||||
double ratio = 0.0;
|
||||
|
||||
Vec3d pivot = (m_starting.ctrl_down && (m_hover_id < 6)) ? m_starting.pivots[m_hover_id] : m_starting.plane_center;
|
||||
Vec3d pivot = (m_starting.ctrl_down && (m_hover_id < 6)) ? m_starting.constraint_position : m_starting.plane_center; // plane_center = bottom center
|
||||
Vec3d starting_vec = m_starting.drag_position - pivot;
|
||||
double len_starting_vec = starting_vec.norm();
|
||||
if (len_starting_vec != 0.0)
|
||||
|
|
|
@ -19,19 +19,23 @@ class GLGizmoScale3D : public GLGizmoBase
|
|||
{
|
||||
Vec3d scale;
|
||||
Vec3d drag_position;
|
||||
Vec3d constraint_position;
|
||||
Vec3d center{Vec3d::Zero()};//sphere bounding box center
|
||||
Vec3d instance_center{Vec3d::Zero()};
|
||||
Vec3d plane_center; // keep the relative center position for scale in the bottom plane
|
||||
Vec3d plane_nromal; // keep the bottom plane
|
||||
BoundingBoxf3 box;
|
||||
Vec3d pivots[6];
|
||||
Vec3d pivots[6];// Vec3d constraint_position{Vec3d::Zero()};
|
||||
Vec3d local_pivots[6];
|
||||
bool ctrl_down;
|
||||
|
||||
StartingData() : scale(Vec3d::Ones()), drag_position(Vec3d::Zero()), ctrl_down(false) { for (int i = 0; i < 5; ++i) { pivots[i] = Vec3d::Zero(); } }
|
||||
};
|
||||
|
||||
mutable BoundingBoxf3 m_box;
|
||||
mutable Transform3d m_transform;
|
||||
// Transforms grabbers offsets to the proper reference system (world for instances, instance for volumes)
|
||||
mutable Transform3d m_offsets_transform;
|
||||
mutable BoundingBoxf3 m_bounding_box;
|
||||
Geometry::Transformation m_grabbers_tran;//m_grabbers_transform
|
||||
Vec3d m_center{Vec3d::Zero()};
|
||||
Vec3d m_instance_center{Vec3d::Zero()};
|
||||
Vec3d m_scale;
|
||||
Vec3d m_offset;
|
||||
double m_snap_step;
|
||||
|
@ -54,7 +58,7 @@ public:
|
|||
const Vec3d& get_offset() const { return m_offset; }
|
||||
|
||||
std::string get_tooltip() const override;
|
||||
|
||||
void data_changed(bool is_serializing) override;
|
||||
void enable_ununiversal_scale(bool enable);
|
||||
protected:
|
||||
virtual bool on_init() override;
|
||||
|
@ -63,12 +67,12 @@ protected:
|
|||
virtual bool on_is_activable() const override;
|
||||
virtual void on_set_state() override;
|
||||
virtual void on_start_dragging() override;
|
||||
virtual void on_stop_dragging() override;
|
||||
virtual void on_update(const UpdateData& data) override;
|
||||
virtual void on_render() override;
|
||||
virtual void on_render_for_picking() override;
|
||||
//BBS: GUI refactor: add object manipulation
|
||||
virtual void on_render_input_window(float x, float y, float bottom_limit);
|
||||
|
||||
private:
|
||||
void render_grabbers_connection(unsigned int id_1, unsigned int id_2) const;
|
||||
|
||||
|
@ -76,6 +80,10 @@ private:
|
|||
void do_scale_uniform(const UpdateData& data);
|
||||
|
||||
double calc_ratio(const UpdateData& data) const;
|
||||
void update_grabbers_data();
|
||||
void change_cs_by_selection(); // cs mean Coordinate System
|
||||
private:
|
||||
int m_last_selected_obejct_idx, m_last_selected_volume_idx;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -996,15 +996,19 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt)
|
|||
//wxGetApp().obj_manipul()->set_dirty();
|
||||
break;
|
||||
}
|
||||
case Scale:
|
||||
{
|
||||
case Scale: {
|
||||
// Apply new temporary scale factors
|
||||
TransformationType transformation_type(TransformationType::Local_Absolute_Joint);
|
||||
//if (evt.AltDown())
|
||||
// transformation_type.set_independent();
|
||||
selection.scale(get_scale(), transformation_type);
|
||||
if (control_down && m_gizmos[m_current].get()->get_hover_id() < 6)
|
||||
selection.translate(get_scale_offset(), true);
|
||||
TransformationType transformation_type;
|
||||
if (wxGetApp().obj_manipul()->is_local_coordinates()) {
|
||||
transformation_type.set_local();
|
||||
} else if (wxGetApp().obj_manipul()->is_instance_coordinates())
|
||||
transformation_type.set_instance();
|
||||
transformation_type.set_relative();
|
||||
|
||||
if (evt.AltDown())
|
||||
transformation_type.set_independent();
|
||||
selection.scale_and_translate(get_scale(), get_scale_offset(), transformation_type);
|
||||
|
||||
// BBS
|
||||
//wxGetApp().obj_manipul()->set_dirty();
|
||||
break;
|
||||
|
|
|
@ -108,15 +108,17 @@ void GizmoObjectManipulation::update_settings_value(const Selection& selection)
|
|||
if (is_world_coordinates()) {//for move and rotate
|
||||
m_new_rotate_label_string = L("Rotate");
|
||||
m_new_rotation = volume->get_instance_rotation() * (180. / M_PI);
|
||||
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_size = selection.get_bounding_box_in_current_reference_system().first.size();
|
||||
m_unscale_size = selection.get_unscaled_instance_bounding_box().size();
|
||||
m_new_scale = m_new_size.cwiseQuotient(m_unscale_size) * 100.0;
|
||||
}
|
||||
else {//if (is_local_coordinates()) {//for scale
|
||||
auto tran = selection.get_first_volume()->get_instance_transformation();
|
||||
m_new_position = tran.get_matrix().inverse() * cs_center;
|
||||
m_new_rotation = volume->get_instance_rotation() * (180. / M_PI);
|
||||
m_new_size = volume->get_instance_transformation().get_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_size = selection.get_bounding_box_in_current_reference_system().first.size();
|
||||
m_unscale_size = selection.get_full_unscaled_instance_local_bounding_box().size();
|
||||
m_new_scale = m_new_size.cwiseQuotient(m_unscale_size) * 100.0;
|
||||
}
|
||||
|
||||
m_new_enabled = true;
|
||||
|
@ -128,44 +130,45 @@ void GizmoObjectManipulation::update_settings_value(const Selection& selection)
|
|||
m_new_position = box.center();
|
||||
m_new_rotation = Vec3d::Zero();
|
||||
m_new_scale = Vec3d(100., 100., 100.);
|
||||
m_new_size = box.size();
|
||||
m_new_size = selection.get_bounding_box_in_current_reference_system().first.size();
|
||||
m_new_rotate_label_string = L("Rotate");
|
||||
m_new_scale_label_string = L("Scale");
|
||||
m_new_enabled = true;
|
||||
m_new_title_string = L("Object Operations");
|
||||
}
|
||||
else if (selection.is_single_modifier() || selection.is_single_volume()) {
|
||||
} else if (selection.is_single_volume_or_modifier()) {
|
||||
const GLVolume *volume = selection.get_first_volume();
|
||||
if (is_world_coordinates()) {//for move and rotate
|
||||
const Geometry::Transformation trafo(volume->world_matrix());
|
||||
const Vec3d &offset = trafo.get_offset();
|
||||
m_new_position = offset;
|
||||
m_new_rotation = volume->get_volume_rotation() * (180. / M_PI);
|
||||
m_new_scale = volume->get_volume_scaling_factor() * 100.;
|
||||
m_new_rotation = Vec3d::Zero();
|
||||
m_new_scale = Vec3d(100.0, 100.0, 100.0);
|
||||
m_unscale_size = selection.get_bounding_box_in_current_reference_system().first.size();
|
||||
m_new_size = selection.get_bounding_box_in_current_reference_system().first.size();
|
||||
} else if (is_local_coordinates()) {//for scale
|
||||
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_instance_transformation().get_scaling_factor().cwiseProduct(
|
||||
volume->get_volume_transformation().get_scaling_factor().cwiseProduct(volume->bounding_box().size()));
|
||||
m_unscale_size = selection.get_bounding_box_in_current_reference_system().first.size();
|
||||
m_new_size = selection.get_bounding_box_in_current_reference_system().first.size();
|
||||
} else {
|
||||
m_new_position = volume->get_volume_offset();
|
||||
m_new_rotate_label_string = L("Rotate (relative)");
|
||||
m_new_rotation = Vec3d::Zero();
|
||||
m_new_scale_label_string = L("Scale");
|
||||
m_new_scale = Vec3d(100.0, 100.0, 100.0);
|
||||
m_unscale_size = selection.get_bounding_box_in_current_reference_system().first.size();
|
||||
m_new_size = selection.get_bounding_box_in_current_reference_system().first.size();
|
||||
}
|
||||
m_new_enabled = true;
|
||||
m_new_title_string = L("Volume Operations");
|
||||
}
|
||||
else if (obj_list->multiple_selection() || obj_list->is_selected(itInstanceRoot)) {
|
||||
} else if (obj_list->is_connectors_item_selected() || obj_list->multiple_selection() || obj_list->is_selected(itInstanceRoot)) {
|
||||
reset_settings_value();
|
||||
m_new_move_label_string = L("Translate");
|
||||
m_new_rotate_label_string = L("Rotate");
|
||||
m_new_scale_label_string = L("Scale");
|
||||
m_new_size = selection.get_bounding_box().size();
|
||||
m_unscale_size = selection.get_bounding_box_in_current_reference_system().first.size();
|
||||
m_new_size = selection.get_bounding_box_in_current_reference_system().first.size();
|
||||
m_new_enabled = true;
|
||||
m_new_title_string = L("Group Operations");
|
||||
}
|
||||
|
@ -250,8 +253,9 @@ void GizmoObjectManipulation::update_reset_buttons_visibility()
|
|||
{
|
||||
const Selection& selection = m_glcanvas.get_selection();
|
||||
|
||||
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());
|
||||
if (selection.is_single_full_instance() || selection.is_single_volume_or_modifier()) {
|
||||
const GLVolume * volume = selection.get_first_volume();
|
||||
|
||||
Vec3d rotation;
|
||||
Vec3d scale;
|
||||
double min_z = 0.;
|
||||
|
@ -266,7 +270,7 @@ void GizmoObjectManipulation::update_reset_buttons_visibility()
|
|||
min_z = get_volume_min_z(volume);
|
||||
}
|
||||
m_show_clear_rotation = !rotation.isApprox(Vec3d::Zero());
|
||||
m_show_clear_scale = !scale.isApprox(Vec3d::Ones(), EPSILON);
|
||||
m_show_clear_scale = (m_cache.scale / 100.0f - Vec3d::Ones()).norm() > 0.001;
|
||||
m_show_drop_to_bed = (std::abs(min_z) > EPSILON);
|
||||
}
|
||||
}
|
||||
|
@ -338,18 +342,20 @@ void GizmoObjectManipulation::change_scale_value(int axis, double value)
|
|||
{
|
||||
if (value <= 0.0)
|
||||
return;
|
||||
if (std::abs(m_cache.scale_rounded(axis) - value) < EPSILON)
|
||||
if (std::abs(m_cache.scale_rounded(axis) - value) < EPSILON) {
|
||||
m_show_clear_scale = (m_cache.scale / 100.0f - Vec3d::Ones()).norm() > 0.001;
|
||||
return;
|
||||
|
||||
}
|
||||
Vec3d scale = m_cache.scale;
|
||||
if (scale[axis] != 0 && std::abs(m_cache.size[axis] * value / scale[axis]) > MAX_NUM) {
|
||||
scale[axis] *= MAX_NUM / m_cache.size[axis];
|
||||
}
|
||||
else {
|
||||
scale(axis) = value;
|
||||
}
|
||||
|
||||
this->do_scale(axis, scale);
|
||||
Vec3d ref_scale = m_cache.scale;
|
||||
const Selection &selection = m_glcanvas.get_selection();
|
||||
if (selection.is_single_volume_or_modifier()) {
|
||||
scale = scale.cwiseQuotient(ref_scale); // scale / ref_scale
|
||||
ref_scale = Vec3d::Ones();
|
||||
} else if (selection.is_single_full_instance())
|
||||
ref_scale = 100 * Vec3d::Ones();
|
||||
this->do_scale(axis, scale.cwiseQuotient(ref_scale));
|
||||
|
||||
m_cache.scale = scale;
|
||||
m_cache.scale_rounded(axis) = DBL_MAX;
|
||||
|
@ -370,17 +376,17 @@ void GizmoObjectManipulation::change_size_value(int axis, double value)
|
|||
const Selection& selection = m_glcanvas.get_selection();
|
||||
|
||||
Vec3d ref_size = m_cache.size;
|
||||
if (selection.is_single_volume() || selection.is_single_modifier()) {
|
||||
Vec3d instance_scale = wxGetApp().model().objects[selection.get_volume(*selection.get_volume_idxs().begin())->object_idx()]->instances[0]->get_transformation().get_scaling_factor();
|
||||
ref_size = selection.get_volume(*selection.get_volume_idxs().begin())->bounding_box().size();
|
||||
ref_size = Vec3d(instance_scale[0] * ref_size[0], instance_scale[1] * ref_size[1], instance_scale[2] * ref_size[2]);
|
||||
if (selection.is_single_volume_or_modifier()) {
|
||||
size = size.cwiseQuotient(ref_size);
|
||||
ref_size = Vec3d::Ones();
|
||||
} else if (selection.is_single_full_instance()) {
|
||||
if (is_world_coordinates())
|
||||
ref_size = selection.get_full_unscaled_instance_bounding_box().size();
|
||||
else
|
||||
ref_size = selection.get_full_unscaled_instance_local_bounding_box().size();
|
||||
}
|
||||
else if (selection.is_single_full_instance())
|
||||
ref_size = is_world_coordinates() ?
|
||||
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();
|
||||
|
||||
this->do_scale(axis, 100. * Vec3d(size(0) / ref_size(0), size(1) / ref_size(1), size(2) / ref_size(2)));
|
||||
this->do_scale(axis, size.cwiseQuotient(ref_size));
|
||||
|
||||
m_cache.size = size;
|
||||
m_cache.size_rounded(axis) = DBL_MAX;
|
||||
|
@ -390,24 +396,27 @@ void GizmoObjectManipulation::change_size_value(int axis, double value)
|
|||
void GizmoObjectManipulation::do_scale(int axis, const Vec3d &scale) const
|
||||
{
|
||||
Selection& selection = m_glcanvas.get_selection();
|
||||
Vec3d scaling_factor = scale;
|
||||
|
||||
TransformationType transformation_type(TransformationType::World_Relative_Joint);
|
||||
if (selection.is_single_full_instance()) {
|
||||
transformation_type.set_absolute();
|
||||
if (!is_world_coordinates())
|
||||
TransformationType transformation_type;
|
||||
if (is_local_coordinates())
|
||||
transformation_type.set_local();
|
||||
else if (is_instance_coordinates())
|
||||
transformation_type.set_instance();
|
||||
if (selection.is_single_volume_or_modifier() && !is_local_coordinates())
|
||||
transformation_type.set_relative();
|
||||
|
||||
Vec3d scaling_factor = m_uniform_scale ? scale(axis) * Vec3d::Ones() : scale;
|
||||
for (size_t i = 0; i < scaling_factor.size(); i++) {//range protect //scaling_factor too big has problem
|
||||
if (scaling_factor[i] * m_unscale_size[i] > MAX_NUM) {
|
||||
scaling_factor[i] = MAX_NUM/ m_unscale_size[i];
|
||||
}
|
||||
}
|
||||
|
||||
// BBS: when select multiple objects, uniform scale can be deselected
|
||||
if (m_uniform_scale/* || selection.requires_uniform_scale()*/)
|
||||
scaling_factor = scale(axis) * Vec3d::Ones();
|
||||
|
||||
selection.start_dragging();
|
||||
selection.scale(scaling_factor * 0.01, transformation_type);
|
||||
selection.scale(scaling_factor, transformation_type);
|
||||
m_glcanvas.do_scale(L("Set Scale"));
|
||||
}
|
||||
|
||||
|
||||
void GizmoObjectManipulation::on_change(const std::string& opt_key, int axis, double new_value)
|
||||
{
|
||||
if (!m_cache.is_valid())
|
||||
|
@ -731,8 +740,7 @@ void GizmoObjectManipulation::show_scale_tooltip_information(ImGuiWrapper *imgui
|
|||
|
||||
float space_size = imgui_wrapper->get_style_scaling() * 8;
|
||||
float position_size = imgui_wrapper->calc_text_size(_L("Position")).x + space_size;
|
||||
float object_cs_size = imgui_wrapper->calc_text_size(_L("Object coordinates")).x + imgui_wrapper->calc_text_size(" ").x + space_size;
|
||||
float caption_max = std::max(position_size, object_cs_size) + 2 * space_size;
|
||||
float caption_max = imgui_wrapper->calc_text_size(_L("Object coordinates")).x + 2 * space_size;
|
||||
float end_text_size = imgui_wrapper->calc_text_size(this->m_new_unit_string).x;
|
||||
|
||||
// position
|
||||
|
@ -751,7 +759,7 @@ void GizmoObjectManipulation::show_scale_tooltip_information(ImGuiWrapper *imgui
|
|||
|
||||
ImGui::AlignTextToFramePadding();
|
||||
unsigned int current_active_id = ImGui::GetActiveID();
|
||||
ImGui::PushItemWidth(caption_max);
|
||||
|
||||
Selection & selection = m_glcanvas.get_selection();
|
||||
std::vector<std::string> modes = {_u8L("World coordinates"), _u8L("Object coordinates")};//_u8L("Part coordinates")
|
||||
if (selection.is_multiple_full_object()) {
|
||||
|
@ -762,15 +770,17 @@ void GizmoObjectManipulation::show_scale_tooltip_information(ImGuiWrapper *imgui
|
|||
set_coordinates_type(ECoordinatesType::World);
|
||||
selection_idx = 0;
|
||||
}
|
||||
|
||||
float caption_cs_size = imgui_wrapper->calc_text_size("").x;
|
||||
float combox_content_size = imgui_wrapper->calc_text_size(_L("Object coordinates")).x * 1.1 + ImGui::GetStyle().FramePadding.x * 18.0f;
|
||||
float caption_size = caption_cs_size + 2 * space_size;
|
||||
float combox_content_size = imgui_wrapper->calc_text_size(_L("Object coordinates")).x * 1.2 + imgui_wrapper->calc_text_size("xxx").x + imgui_wrapper->scaled(3);
|
||||
ImGuiWrapper::push_combo_style(m_glcanvas.get_scale());
|
||||
bool combox_changed = false;
|
||||
if (render_combo(imgui_wrapper, "", modes, selection_idx, caption_size, combox_content_size)) {
|
||||
combox_changed = true;
|
||||
}
|
||||
ImGuiWrapper::pop_combo_style();
|
||||
caption_max = combox_content_size - 4 * space_size;
|
||||
ImGui::SameLine(caption_max + index * space_size);
|
||||
ImGui::PushItemWidth(unit_size);
|
||||
ImGui::TextAlignCenter("X");
|
||||
|
@ -1007,8 +1017,7 @@ void GizmoObjectManipulation::do_render_scale_input_window(ImGuiWrapper* imgui_w
|
|||
|
||||
float space_size = imgui_wrapper->get_style_scaling() * 8;
|
||||
float scale_size = imgui_wrapper->calc_text_size(_L("Scale")).x + space_size;
|
||||
float size_len = imgui_wrapper->calc_text_size(_L("Size")).x + space_size;
|
||||
float caption_max = std::max(scale_size, size_len) + 2 * space_size;
|
||||
float caption_max = imgui_wrapper->calc_text_size(_L("Object coordinates")).x + 2 * space_size;
|
||||
float end_text_size = imgui_wrapper->calc_text_size(this->m_new_unit_string).x;
|
||||
ImGui::AlignTextToFramePadding();
|
||||
unsigned int current_active_id = ImGui::GetActiveID();
|
||||
|
@ -1024,10 +1033,30 @@ void GizmoObjectManipulation::do_render_scale_input_window(ImGuiWrapper* imgui_w
|
|||
int index = 2;
|
||||
int index_unit = 1;
|
||||
|
||||
ImGui::PushItemWidth(caption_max);
|
||||
ImGui::Dummy(ImVec2(caption_max, -1));
|
||||
//imgui_wrapper->text(_L(" "));
|
||||
//ImGui::PushItemWidth(unit_size * 1.5);
|
||||
Selection & selection = m_glcanvas.get_selection();
|
||||
std::vector<std::string> modes = {_u8L("World coordinates"), _u8L("Object coordinates"), _u8L("Part coordinates")};
|
||||
if (selection.is_single_full_object()) { modes.pop_back(); }
|
||||
if (selection.is_multiple_full_object()) {
|
||||
modes.pop_back();
|
||||
modes.pop_back();
|
||||
}
|
||||
size_t selection_idx = (int) m_coordinates_type;
|
||||
if (selection_idx >= modes.size()) {
|
||||
set_coordinates_type(ECoordinatesType::World);
|
||||
selection_idx = 0;
|
||||
}
|
||||
|
||||
float caption_cs_size = imgui_wrapper->calc_text_size("").x;
|
||||
float caption_size = caption_cs_size + 2 * space_size;
|
||||
float combox_content_size = imgui_wrapper->calc_text_size(_L("Object coordinates")).x * 1.2 + imgui_wrapper->calc_text_size("xxx").x + imgui_wrapper->scaled(3);
|
||||
ImGuiWrapper::push_combo_style(m_glcanvas.get_scale());
|
||||
bool combox_changed = false;
|
||||
if (render_combo(imgui_wrapper, "", modes, selection_idx, caption_size, combox_content_size)) {
|
||||
combox_changed = true;
|
||||
}
|
||||
ImGuiWrapper::pop_combo_style();
|
||||
caption_max = combox_content_size - 4 * space_size;
|
||||
//ImGui::Dummy(ImVec2(caption_max, -1));
|
||||
ImGui::SameLine(caption_max + space_size);
|
||||
ImGui::PushItemWidth(unit_size);
|
||||
ImGui::TextAlignCenter("X");
|
||||
|
@ -1091,20 +1120,31 @@ void GizmoObjectManipulation::do_render_scale_input_window(ImGuiWrapper* imgui_w
|
|||
ImGui::BBLInputDouble(label_scale_values[1][2], &display_size[2], 0.0f, 0.0f, "%.2f");
|
||||
ImGui::SameLine(caption_max + (++index_unit) *unit_size + (++index) * space_size);
|
||||
imgui_wrapper->text(this->m_new_unit_string);
|
||||
|
||||
for (int i = 0;i<display_size.size();i++)
|
||||
{
|
||||
if (std::abs(display_size[i]) > MAX_NUM) display_size[i] = MAX_NUM;
|
||||
for (int i = 0; i < display_size.size(); i++) {
|
||||
if (std::abs(display_size[i]) > MAX_NUM) {
|
||||
display_size[i] = MAX_NUM;
|
||||
}
|
||||
}
|
||||
if (display_size.x() > 0 && display_size.y() > 0 && display_size.z() > 0) {
|
||||
m_buffered_size = display_size;
|
||||
}
|
||||
|
||||
int size_sel = update(current_active_id, "size", original_size, m_buffered_size);
|
||||
ImGui::PopStyleVar(1);
|
||||
|
||||
ImGui::Separator();
|
||||
ImGui::AlignTextToFramePadding();
|
||||
bool is_avoid_one_update{false};
|
||||
if (combox_changed) {
|
||||
combox_changed = false;
|
||||
set_coordinates_type((ECoordinatesType) selection_idx);
|
||||
UpdateAndShow(true);
|
||||
is_avoid_one_update = true;
|
||||
}
|
||||
|
||||
auto uniform_scale_size =imgui_wrapper->calc_text_size(_L("uniform scale")).x;
|
||||
ImGui::PushItemWidth(uniform_scale_size);
|
||||
int size_sel{-1};
|
||||
if (!is_avoid_one_update) {
|
||||
size_sel = update(current_active_id, "size", original_size, m_buffered_size);
|
||||
}
|
||||
ImGui::PopStyleVar(1);
|
||||
bool uniform_scale = this->m_uniform_scale;
|
||||
|
||||
// BBS: when select multiple objects, uniform scale can be deselected
|
||||
|
@ -1145,9 +1185,6 @@ void GizmoObjectManipulation::do_render_scale_input_window(ImGuiWrapper* imgui_w
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//send focus to m_glcanvas
|
||||
bool focued_on_text = false;
|
||||
for (int i = 0; i < 2; i++)
|
||||
|
|
|
@ -74,6 +74,7 @@ public:
|
|||
Vec3d m_new_rotation;
|
||||
Vec3d m_new_scale;
|
||||
Vec3d m_new_size;
|
||||
Vec3d m_unscale_size;
|
||||
Vec3d m_buffered_position;
|
||||
Vec3d m_buffered_rotation;
|
||||
Vec3d m_buffered_scale;
|
||||
|
|
|
@ -928,6 +928,63 @@ const BoundingBoxf3& Selection::get_scaled_instance_bounding_box() const
|
|||
return *m_scaled_instance_bounding_box;
|
||||
}
|
||||
|
||||
const BoundingBoxf3 &Selection::get_full_unscaled_instance_bounding_box() const
|
||||
{
|
||||
assert(is_single_full_instance());
|
||||
|
||||
if (!m_full_unscaled_instance_bounding_box.has_value()) {
|
||||
std::optional<BoundingBoxf3> *bbox = const_cast<std::optional<BoundingBoxf3> *>(&m_full_unscaled_instance_bounding_box);
|
||||
*bbox = BoundingBoxf3();
|
||||
if (m_valid) {
|
||||
for (unsigned int i : m_list) {
|
||||
const GLVolume &volume = *(*m_volumes)[i];
|
||||
Transform3d trafo = volume.get_instance_transformation().get_matrix_no_scaling_factor() * volume.get_volume_transformation().get_matrix();
|
||||
trafo.translation().z() += volume.get_sla_shift_z();
|
||||
(*bbox)->merge(volume.transformed_convex_hull_bounding_box(trafo));
|
||||
}
|
||||
}
|
||||
}
|
||||
return *m_full_unscaled_instance_bounding_box;
|
||||
}
|
||||
|
||||
const BoundingBoxf3 &Selection::get_full_scaled_instance_bounding_box() const
|
||||
{
|
||||
assert(is_single_full_instance());
|
||||
|
||||
if (!m_full_scaled_instance_bounding_box.has_value()) {
|
||||
std::optional<BoundingBoxf3> *bbox = const_cast<std::optional<BoundingBoxf3> *>(&m_full_scaled_instance_bounding_box);
|
||||
*bbox = BoundingBoxf3();
|
||||
if (m_valid) {
|
||||
for (unsigned int i : m_list) {
|
||||
const GLVolume &volume = *(*m_volumes)[i];
|
||||
Transform3d trafo = volume.get_instance_transformation().get_matrix() * volume.get_volume_transformation().get_matrix();
|
||||
trafo.translation().z() += volume.get_sla_shift_z();
|
||||
(*bbox)->merge(volume.transformed_convex_hull_bounding_box(trafo));
|
||||
}
|
||||
}
|
||||
}
|
||||
return *m_full_scaled_instance_bounding_box;
|
||||
}
|
||||
|
||||
const BoundingBoxf3 &Selection::get_full_unscaled_instance_local_bounding_box() const
|
||||
{
|
||||
assert(is_single_full_instance());
|
||||
|
||||
if (!m_full_unscaled_instance_local_bounding_box.has_value()) {
|
||||
std::optional<BoundingBoxf3> *bbox = const_cast<std::optional<BoundingBoxf3> *>(&m_full_unscaled_instance_local_bounding_box);
|
||||
*bbox = BoundingBoxf3();
|
||||
if (m_valid) {
|
||||
for (unsigned int i : m_list) {
|
||||
const GLVolume &volume = *(*m_volumes)[i];
|
||||
Transform3d trafo = volume.get_volume_transformation().get_matrix();
|
||||
trafo.translation().z() += volume.get_sla_shift_z();
|
||||
(*bbox)->merge(volume.transformed_convex_hull_bounding_box(trafo));
|
||||
}
|
||||
}
|
||||
}
|
||||
return *m_full_unscaled_instance_local_bounding_box;
|
||||
}
|
||||
|
||||
const std::pair<BoundingBoxf3, Transform3d> &Selection::get_bounding_box_in_current_reference_system() const
|
||||
{
|
||||
static int last_coordinates_type = -1;
|
||||
|
@ -986,7 +1043,8 @@ std::pair<BoundingBoxf3, Transform3d> Selection::get_bounding_box_in_reference_s
|
|||
const GLVolume & vol = *get_volume(id);
|
||||
const Transform3d vol_world_rafo = vol.world_matrix();
|
||||
const TriangleMesh *mesh = vol.convex_hull();
|
||||
if (mesh == nullptr) mesh = &m_model->objects[vol.object_idx()]->volumes[vol.volume_idx()]->mesh();
|
||||
if (mesh == nullptr)
|
||||
mesh = &m_model->objects[vol.object_idx()]->volumes[vol.volume_idx()]->mesh();
|
||||
assert(mesh != nullptr);
|
||||
for (const stl_vertex &v : mesh->its.vertices) {
|
||||
const Vec3d world_v = vol_world_rafo * v.cast<double>();
|
||||
|
@ -1433,77 +1491,7 @@ void Selection::flattening_rotate(const Vec3d& normal)
|
|||
|
||||
void Selection::scale(const Vec3d& scale, TransformationType transformation_type)
|
||||
{
|
||||
if (!m_valid)
|
||||
return;
|
||||
|
||||
for (unsigned int i : m_list) {
|
||||
GLVolume &v = *(*m_volumes)[i];
|
||||
if (is_single_full_instance()) {
|
||||
if (transformation_type.relative()) {
|
||||
Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), Vec3d::Zero(), scale);
|
||||
Eigen::Matrix<double, 3, 3, Eigen::DontAlign> new_matrix = (m * m_cache.volumes_data[i].get_instance_scale_matrix()).matrix().block(0, 0, 3, 3);
|
||||
// extracts scaling factors from the composed transformation
|
||||
Vec3d new_scale(new_matrix.col(0).norm(), new_matrix.col(1).norm(), new_matrix.col(2).norm());
|
||||
if (transformation_type.joint())
|
||||
v.set_instance_offset(m_cache.dragging_center + m * (m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center));
|
||||
|
||||
v.set_instance_scaling_factor(new_scale);
|
||||
}
|
||||
else {
|
||||
if (transformation_type.world() && (std::abs(scale.x() - scale.y()) > EPSILON || std::abs(scale.x() - scale.z()) > EPSILON)) {
|
||||
// Non-uniform scaling. Transform the scaling factors into the local coordinate system.
|
||||
// This is only possible, if the instance rotation is mulitples of ninety degrees.
|
||||
assert(Geometry::is_rotation_ninety_degrees(v.get_instance_rotation()));
|
||||
v.set_instance_scaling_factor((v.get_instance_transformation().get_matrix(true, false, true, true).matrix().block<3, 3>(0, 0).transpose() * scale).cwiseAbs());
|
||||
}
|
||||
else
|
||||
v.set_instance_scaling_factor(scale);
|
||||
}
|
||||
|
||||
// update the instance assemble transform
|
||||
ModelObject* object = m_model->objects[v.object_idx()];
|
||||
Geometry::Transformation assemble_transform = object->instances[v.instance_idx()]->get_assemble_transformation();
|
||||
assemble_transform.set_scaling_factor(v.get_instance_scaling_factor());
|
||||
object->instances[v.instance_idx()]->set_assemble_transformation(assemble_transform);
|
||||
}
|
||||
else if (is_single_volume() || is_single_modifier())
|
||||
v.set_volume_scaling_factor(scale);
|
||||
else {
|
||||
Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), Vec3d::Zero(), scale);
|
||||
if (m_mode == Instance) {
|
||||
Eigen::Matrix<double, 3, 3, Eigen::DontAlign> new_matrix = (m * m_cache.volumes_data[i].get_instance_scale_matrix()).matrix().block(0, 0, 3, 3);
|
||||
// extracts scaling factors from the composed transformation
|
||||
Vec3d new_scale(new_matrix.col(0).norm(), new_matrix.col(1).norm(), new_matrix.col(2).norm());
|
||||
if (transformation_type.joint())
|
||||
v.set_instance_offset(m_cache.dragging_center + m * (m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center));
|
||||
|
||||
v.set_instance_scaling_factor(new_scale);
|
||||
}
|
||||
else if (m_mode == Volume) {
|
||||
Eigen::Matrix<double, 3, 3, Eigen::DontAlign> new_matrix = (m * m_cache.volumes_data[i].get_volume_scale_matrix()).matrix().block(0, 0, 3, 3);
|
||||
// extracts scaling factors from the composed transformation
|
||||
Vec3d new_scale(new_matrix.col(0).norm(), new_matrix.col(1).norm(), new_matrix.col(2).norm());
|
||||
if (transformation_type.joint()) {
|
||||
Vec3d offset = m * (m_cache.volumes_data[i].get_volume_position() + m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center);
|
||||
v.set_volume_offset(m_cache.dragging_center - m_cache.volumes_data[i].get_instance_position() + offset);
|
||||
}
|
||||
v.set_volume_scaling_factor(new_scale);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if !DISABLE_INSTANCES_SYNCH
|
||||
if (m_mode == Instance)
|
||||
synchronize_unselected_instances(SYNC_ROTATION_NONE);
|
||||
else if (m_mode == Volume)
|
||||
synchronize_unselected_volumes();
|
||||
#endif // !DISABLE_INSTANCES_SYNCH
|
||||
|
||||
ensure_on_bed();
|
||||
set_bounding_boxes_dirty();
|
||||
if (wxGetApp().plater()->canvas3D()->get_canvas_type() != GLCanvas3D::ECanvasType::CanvasAssembleView) {
|
||||
wxGetApp().plater()->canvas3D()->requires_check_outside_state();
|
||||
}
|
||||
scale_and_translate(scale, Vec3d::Zero(), transformation_type);
|
||||
}
|
||||
|
||||
#if ENABLE_ENHANCED_PRINT_VOLUME_FIT
|
||||
|
@ -1641,27 +1629,89 @@ void Selection::scale_to_fit_print_volume(const DynamicPrintConfig& config)
|
|||
}
|
||||
#endif // ENABLE_ENHANCED_PRINT_VOLUME_FIT
|
||||
|
||||
void Selection::mirror(Axis axis)
|
||||
void Selection::scale_and_translate(const Vec3d &scale, const Vec3d &world_translation, TransformationType transformation_type)
|
||||
{
|
||||
if (!m_valid)
|
||||
return;
|
||||
if (!m_valid) return;
|
||||
|
||||
Vec3d relative_scale = scale;
|
||||
if (transformation_type.absolute()) {
|
||||
// converts to relative scale
|
||||
if (m_mode == Instance) {
|
||||
if (is_single_full_instance()) {
|
||||
BoundingBoxf3 current_box = get_bounding_box_in_current_reference_system().first;
|
||||
BoundingBoxf3 original_box;
|
||||
if (transformation_type.world())
|
||||
original_box = get_full_unscaled_instance_bounding_box();
|
||||
else
|
||||
original_box = get_full_unscaled_instance_local_bounding_box();
|
||||
|
||||
relative_scale = original_box.size().cwiseProduct(scale).cwiseQuotient(current_box.size());
|
||||
}
|
||||
}
|
||||
transformation_type.set_relative();
|
||||
}
|
||||
|
||||
for (unsigned int i : m_list) {
|
||||
GLVolume& v = *(*m_volumes)[i];
|
||||
if (is_single_full_instance())
|
||||
v.set_instance_mirror(axis, -v.get_instance_mirror(axis));
|
||||
else if (m_mode == Volume)
|
||||
v.set_volume_mirror(axis, -v.get_volume_mirror(axis));
|
||||
GLVolume & v = *(*m_volumes)[i];
|
||||
const VolumeCache & volume_data = m_cache.volumes_data[i];
|
||||
const Geometry::Transformation &inst_trafo = volume_data.get_instance_transform();
|
||||
auto old_rotate = inst_trafo.get_rotation();
|
||||
if (m_mode == Instance) {
|
||||
if (transformation_type.instance()) {
|
||||
const Vec3d world_inst_pivot = m_cache.dragging_center - inst_trafo.get_offset();
|
||||
const Vec3d local_inst_pivot = inst_trafo.get_matrix_no_offset().inverse() * world_inst_pivot;
|
||||
Matrix3d inst_rotation, inst_scale;
|
||||
inst_trafo.get_matrix().computeRotationScaling(&inst_rotation, &inst_scale);
|
||||
const Transform3d offset_trafo = Geometry::translation_transform(inst_trafo.get_offset() + world_translation);
|
||||
const Transform3d scale_trafo = Transform3d(inst_scale) * Geometry::scale_transform(relative_scale);
|
||||
v.set_instance_transformation(Geometry::translation_transform(world_inst_pivot) * offset_trafo * Transform3d(inst_rotation) * scale_trafo *
|
||||
Geometry::translation_transform(-local_inst_pivot));
|
||||
} else
|
||||
transform_instance_relative(v, volume_data, transformation_type, Geometry::translation_transform(world_translation) * Geometry::scale_transform(relative_scale),
|
||||
m_cache.dragging_center);
|
||||
std::cout << "";
|
||||
} else {
|
||||
if (!is_single_volume_or_modifier()) {
|
||||
assert(transformation_type.world());
|
||||
transform_volume_relative(v, volume_data, transformation_type, Geometry::translation_transform(world_translation) * Geometry::scale_transform(scale),
|
||||
m_cache.dragging_center);
|
||||
} else {
|
||||
transformation_type.set_independent();
|
||||
Vec3d translation;
|
||||
if (transformation_type.local()) {
|
||||
translation = volume_data.get_volume_transform().get_matrix_no_offset().inverse() * inst_trafo.get_matrix_no_offset().inverse() * world_translation;
|
||||
}
|
||||
else if (transformation_type.instance())
|
||||
translation = inst_trafo.get_matrix_no_offset().inverse() * world_translation;
|
||||
else
|
||||
translation = world_translation;
|
||||
transform_volume_relative(v, volume_data, transformation_type, Geometry::translation_transform(translation) * Geometry::scale_transform(scale),
|
||||
m_cache.dragging_center);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if !DISABLE_INSTANCES_SYNCH
|
||||
if (m_mode == Instance)
|
||||
synchronize_unselected_instances(SYNC_ROTATION_NONE);
|
||||
// even if there is no rotation, we pass SyncRotationType::GENERAL to force
|
||||
// synchronize_unselected_instances() to apply the scale to the other instances
|
||||
synchronize_unselected_instances(SyncRotationType::SYNC_ROTATION_GENERAL);
|
||||
else if (m_mode == Volume)
|
||||
synchronize_unselected_volumes();
|
||||
#endif // !DISABLE_INSTANCES_SYNCH
|
||||
|
||||
ensure_on_bed();
|
||||
set_bounding_boxes_dirty();
|
||||
if (wxGetApp().plater()->canvas3D()->get_canvas_type() != GLCanvas3D::ECanvasType::CanvasAssembleView) {
|
||||
wxGetApp().plater()->canvas3D()->requires_check_outside_state();
|
||||
}
|
||||
}
|
||||
|
||||
void Selection::mirror(Axis axis, TransformationType transformation_type)
|
||||
{
|
||||
const Vec3d mirror((axis == X) ? -1.0 : 1.0, (axis == Y) ? -1.0 : 1.0, (axis == Z) ? -1.0 : 1.0);
|
||||
scale_and_translate(mirror, Vec3d::Zero(), transformation_type);
|
||||
|
||||
}
|
||||
|
||||
void Selection::translate(unsigned int object_idx, const Vec3d& displacement)
|
||||
|
@ -3031,8 +3081,8 @@ void Selection::paste_volumes_from_clipboard()
|
|||
{
|
||||
ModelInstance* dst_instance = dst_object->instances[dst_inst_idx];
|
||||
BoundingBoxf3 dst_instance_bb = dst_object->instance_bounding_box(dst_inst_idx);
|
||||
Transform3d src_matrix = src_object->instances[0]->get_transformation().get_matrix(true);
|
||||
Transform3d dst_matrix = dst_instance->get_transformation().get_matrix(true);
|
||||
Transform3d src_matrix = src_object->instances[0]->get_transformation().get_matrix_no_offset();
|
||||
Transform3d dst_matrix = dst_instance->get_transformation().get_matrix_no_offset();
|
||||
bool from_same_object = (src_object->input_file == dst_object->input_file) && src_matrix.isApprox(dst_matrix);
|
||||
|
||||
// used to keep relative position of multivolume selections when pasting from another object
|
||||
|
|
|
@ -29,7 +29,7 @@ using ModelObjectPtrs = std::vector<ModelObject*>;
|
|||
|
||||
namespace GUI {
|
||||
enum ECoordinatesType : unsigned char {
|
||||
World,
|
||||
World = 0,
|
||||
Instance,
|
||||
Local
|
||||
};
|
||||
|
@ -249,7 +249,15 @@ private:
|
|||
// is useful for absolute scaling of tilted objects in world coordinate space.
|
||||
std::optional<BoundingBoxf3> m_unscaled_instance_bounding_box;
|
||||
std::optional<BoundingBoxf3> m_scaled_instance_bounding_box;
|
||||
|
||||
// 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;
|
||||
// Bounding box aligned to the axis of the currently selected reference system (World/Object/Part)
|
||||
// and transform to place and orient it in world coordinates
|
||||
std::optional<std::pair<BoundingBoxf3, Transform3d>> m_bounding_box_in_current_reference_system;
|
||||
|
@ -377,7 +385,15 @@ public:
|
|||
// is useful for absolute scaling of tilted objects in world coordinate space.
|
||||
const BoundingBoxf3& get_unscaled_instance_bounding_box() const;
|
||||
const BoundingBoxf3& get_scaled_instance_bounding_box() const;
|
||||
|
||||
// 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;
|
||||
// Returns the bounding box aligned to the axes of the currently selected reference system (World/Object/Part)
|
||||
// and the transform to place and orient it in world coordinates
|
||||
const std::pair<BoundingBoxf3, Transform3d> &get_bounding_box_in_current_reference_system() const;
|
||||
|
@ -403,7 +419,8 @@ public:
|
|||
#else
|
||||
void scale_to_fit_print_volume(const DynamicPrintConfig& config);
|
||||
#endif // ENABLE_ENHANCED_PRINT_VOLUME_FIT
|
||||
void mirror(Axis axis);
|
||||
void scale_and_translate(const Vec3d &scale, const Vec3d &world_translation, TransformationType transformation_type);
|
||||
void mirror(Axis axis, TransformationType transformation_type);
|
||||
|
||||
void translate(unsigned int object_idx, const Vec3d& displacement);
|
||||
void translate(unsigned int object_idx, unsigned int instance_idx, const Vec3d& displacement);
|
||||
|
@ -468,6 +485,9 @@ private:
|
|||
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();
|
||||
m_bounding_box_in_current_reference_system.reset();
|
||||
m_bounding_sphere.reset();
|
||||
}
|
||||
|
@ -486,6 +506,8 @@ public:
|
|||
SYNC_ROTATION_NONE = 0,
|
||||
// Synchronize after rotation by an axis not parallel with Z.
|
||||
SYNC_ROTATION_GENERAL = 1,
|
||||
// Synchronize after rotation reset.
|
||||
SYNC_ROTATION_RESET = 2
|
||||
};
|
||||
void synchronize_unselected_instances(SyncRotationType sync_rotation_type);
|
||||
void synchronize_unselected_volumes();
|
||||
|
|
Loading…
Reference in New Issue