diff --git a/src/libslic3r/Geometry.cpp b/src/libslic3r/Geometry.cpp index 92f45f023..7238ce8e4 100644 --- a/src/libslic3r/Geometry.cpp +++ b/src/libslic3r/Geometry.cpp @@ -93,7 +93,7 @@ Pointfs arrange(size_t num_parts, const Vec2d &part_size, coordf_t gap, const Bo // Use actual part size (the largest) plus separation distance (half on each side) in spacing algorithm. const Vec2d cell_size(part_size(0) + gap, part_size(1) + gap); - const BoundingBoxf bed_bbox = (bed_bounding_box != NULL && bed_bounding_box->defined) ? + const BoundingBoxf bed_bbox = (bed_bounding_box != NULL && bed_bounding_box->defined) ? *bed_bounding_box : // Bogus bed size, large enough not to trigger the unsufficient bed size error. BoundingBoxf( @@ -105,12 +105,12 @@ Pointfs arrange(size_t num_parts, const Vec2d &part_size, coordf_t gap, const Bo size_t cellh = size_t(floor((bed_bbox.size()(1) + gap) / cell_size(1))); if (num_parts > cellw * cellh) throw Slic3r::InvalidArgument("%zu parts won't fit in your print area!\n", num_parts); - + // Get a bounding box of cellw x cellh cells, centered at the center of the bed. Vec2d cells_size(cellw * cell_size(0) - gap, cellh * cell_size(1) - gap); Vec2d cells_offset(bed_bbox.center() - 0.5 * cells_size); BoundingBoxf cells_bb(cells_offset, cells_size + cells_offset); - + // List of cells, sorted by distance from center. std::vector cellsorder(cellw * cellh, ArrangeItem()); for (size_t j = 0; j < cellh; ++ j) { @@ -167,7 +167,7 @@ arrange(size_t total_parts, const Vec2d &part_size, coordf_t dist, const Boundin // use actual part size (the largest) plus separation distance (half on each side) in spacing algorithm part(0) += dist; part(1) += dist; - + Vec2d area(Vec2d::Zero()); if (bb != NULL && bb->defined) { area = bb->size(); @@ -176,46 +176,46 @@ arrange(size_t total_parts, const Vec2d &part_size, coordf_t dist, const Boundin area(0) = part(0) * total_parts; area(1) = part(1) * total_parts; } - + // this is how many cells we have available into which to put parts size_t cellw = floor((area(0) + dist) / part(0)); size_t cellh = floor((area(1) + dist) / part(1)); if (total_parts > (cellw * cellh)) return false; - + // total space used by cells Vec2d cells(cellw * part(0), cellh * part(1)); - + // bounding box of total space used by cells BoundingBoxf cells_bb; cells_bb.merge(Vec2d(0,0)); // min cells_bb.merge(cells); // max - + // center bounding box to area cells_bb.translate( (area(0) - cells(0)) / 2, (area(1) - cells(1)) / 2 ); - + // list of cells, sorted by distance from center std::vector cellsorder; - + // work out distance for all cells, sort into list for (size_t i = 0; i <= cellw-1; ++i) { for (size_t j = 0; j <= cellh-1; ++j) { coordf_t cx = linint(i + 0.5, 0, cellw, cells_bb.min(0), cells_bb.max(0)); coordf_t cy = linint(j + 0.5, 0, cellh, cells_bb.min(1), cells_bb.max(1)); - + coordf_t xd = fabs((area(0) / 2) - cx); coordf_t yd = fabs((area(1) / 2) - cy); - + ArrangeItem c; c.pos(0) = cx; c.pos(1) = cy; c.index_x = i; c.index_y = j; c.dist = xd * xd + yd * yd - fabs((cellw / 2) - (i + 0.5)); - + // binary insertion sort { coordf_t index = c.dist; @@ -224,7 +224,7 @@ arrange(size_t total_parts, const Vec2d &part_size, coordf_t dist, const Boundin while (low < high) { size_t mid = (low + ((high - low) / 2)) | 0; coordf_t midval = cellsorder[mid].index; - + if (midval < index) { low = mid + 1; } else if (midval > index) { @@ -239,7 +239,7 @@ arrange(size_t total_parts, const Vec2d &part_size, coordf_t dist, const Boundin ENDSORT: ; } } - + // the extents of cells actually used by objects coordf_t lx = 0; coordf_t ty = 0; @@ -267,17 +267,17 @@ arrange(size_t total_parts, const Vec2d &part_size, coordf_t dist, const Boundin cellsorder.erase(cellsorder.begin()); coordf_t cx = c.item.index_x - lx; coordf_t cy = c.item.index_y - ty; - + positions.push_back(Vec2d(cx * part(0), cy * part(1))); } - + if (bb != NULL && bb->defined) { for (Pointfs::iterator p = positions.begin(); p != positions.end(); ++p) { p->x() += bb->min(0); p->y() += bb->min(1); } } - + return true; } #endif @@ -330,6 +330,10 @@ Vec3d extract_euler_angles(const Eigen::Matrix& 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 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 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; } - - 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) { diff --git a/src/libslic3r/Geometry.hpp b/src/libslic3r/Geometry.hpp index 12e614276..2e52a2be2 100644 --- a/src/libslic3r/Geometry.hpp +++ b/src/libslic3r/Geometry.hpp @@ -10,7 +10,7 @@ // Serialization through the Cereal library #include -namespace Slic3r { +namespace Slic3r { namespace ClipperLib { class PolyNode; @@ -115,9 +115,9 @@ inline bool segment_segment_intersection(const Vec2d &p1, const Vec2d &v1, const } inline bool segments_intersect( - const Slic3r::Point &ip1, const Slic3r::Point &ip2, + const Slic3r::Point &ip1, const Slic3r::Point &ip2, const Slic3r::Point &jp1, const Slic3r::Point &jp2) -{ +{ assert(ip1 != ip2); assert(jp1 != jp2); @@ -313,7 +313,7 @@ void simplify_polygons(const Polygons &polygons, double tolerance, Polygons* ret double linint(double value, double oldmin, double oldmax, double newmin, double newmax); bool arrange( // input - size_t num_parts, const Vec2d &part_size, coordf_t gap, const BoundingBoxf* bed_bounding_box, + size_t num_parts, const Vec2d &part_size, coordf_t gap, const BoundingBoxf* bed_bounding_box, // output Pointfs &positions); @@ -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); - 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); } + const Vec3d &get_scaling_factor() const; + double get_scaling_factor(Axis axis) const { return get_scaling_factor()[axis]; } - void set_scaling_factor(const Vec3d& scaling_factor); + 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; + } + + 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,32 +425,28 @@ 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); - - // 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; - } - + 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_matrix.isApprox(r.m_matrix); } + friend bool operator!=(Transformation const &l, Transformation const &r) { return !(l == r); } private: - friend class cereal::access; - template void serialize(Archive & ar) { ar(m_offset, m_rotation, m_scaling_factor, m_mirror); } - explicit Transformation(int) : m_dirty(true) {} - template static void load_and_construct(Archive &ar, cereal::construct &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); - } + friend class cereal::access; + template void serialize(Archive &ar) { ar(m_matrix); } + explicit Transformation(int) {} + template static void load_and_construct(Archive &ar, cereal::construct &construct) + { + // Calling a private constructor with special "int" parameter to indicate that no construction is necessary. + construct(1); + ar(construct.ptr()->m_matrix); + } }; struct TransformationSVD diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index af0be6240..562c47247 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -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) { diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index daf3699d5..afea23735 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -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; } diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index a890dab1a..2c06c77e2 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -2278,7 +2278,11 @@ std::vector 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); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp b/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp index 125cd3c3d..d51d971dc 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp @@ -5,7 +5,7 @@ #include -#include +#include namespace Slic3r { namespace GUI { @@ -51,7 +51,7 @@ std::string GLGizmoScale3D::get_tooltip() const return "Y: " + format(scale(1), 4) + "%"; else if (m_hover_id == 4 || m_hover_id == 5 || m_grabbers[4].dragging || m_grabbers[5].dragging) return "Z: " + format(scale(2), 4) + "%"; - else if (m_hover_id == 6 || m_hover_id == 7 || m_hover_id == 8 || m_hover_id == 9 || + else if (m_hover_id == 6 || m_hover_id == 7 || m_hover_id == 8 || m_hover_id == 9 || m_grabbers[6].dragging || m_grabbers[7].dragging || m_grabbers[8].dragging || m_grabbers[9].dragging) { std::string tooltip = "X: " + format(scale(0), 2) + "%\n"; @@ -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,30 +108,52 @@ 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 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) { if ((m_hover_id == 0) || (m_hover_id == 1)) @@ -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(); + 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) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoScale.hpp b/src/slic3r/GUI/Gizmos/GLGizmoScale.hpp index f24f248ad..bfcd102e1 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoScale.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoScale.hpp @@ -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 + 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; }; diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index aacf21d51..611d307e1 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -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; diff --git a/src/slic3r/GUI/Gizmos/GizmoObjectManipulation.cpp b/src/slic3r/GUI/Gizmos/GizmoObjectManipulation.cpp index 11365b0a2..109ee3d5b 100644 --- a/src/slic3r/GUI/Gizmos/GizmoObjectManipulation.cpp +++ b/src/slic3r/GUI/Gizmos/GizmoObjectManipulation.cpp @@ -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 scale = m_cache.scale; + scale(axis) = value; + 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()) - transformation_type.set_local(); + 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 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 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 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++) diff --git a/src/slic3r/GUI/Gizmos/GizmoObjectManipulation.hpp b/src/slic3r/GUI/Gizmos/GizmoObjectManipulation.hpp index c17aa845d..1186568cc 100644 --- a/src/slic3r/GUI/Gizmos/GizmoObjectManipulation.hpp +++ b/src/slic3r/GUI/Gizmos/GizmoObjectManipulation.hpp @@ -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; diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index 59744ef53..c9951f334 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -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 *bbox = const_cast *>(&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 *bbox = const_cast *>(&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 *bbox = const_cast *>(&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 &Selection::get_bounding_box_in_current_reference_system() const { static int last_coordinates_type = -1; @@ -986,7 +1043,8 @@ std::pair 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(); @@ -1339,7 +1397,7 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_ else { - if (transformation_type.instance()) {//in object Coordinate System + if (transformation_type.instance()) {//in object Coordinate System // ensure that the volume rotates as a rigid body const Transform3d inst_scale_matrix = inst_trafo.get_scaling_factor_matrix(); rotation_matrix = inst_scale_matrix.inverse() * rotation_matrix * inst_scale_matrix; @@ -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 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 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 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 diff --git a/src/slic3r/GUI/Selection.hpp b/src/slic3r/GUI/Selection.hpp index 41df2f9c2..b1c96b336 100644 --- a/src/slic3r/GUI/Selection.hpp +++ b/src/slic3r/GUI/Selection.hpp @@ -29,7 +29,7 @@ using ModelObjectPtrs = std::vector; 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 m_unscaled_instance_bounding_box; std::optional 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 m_full_unscaled_instance_bounding_box; + // Bounding box of a single full instance selection, in world coordinates. + // Modifiers are taken in account + std::optional 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 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> 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 &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();