Tech ENABLE_TRANSFORMATIONS_BY_MATRICES - 1st installment. Geometry::Transformation modified to store data in a single matrix, without store the matrix components

Fixed conflicts during rebase with master
This commit is contained in:
enricoturri1966 2022-04-29 13:51:58 +02:00
parent a4c0d99616
commit 7e72963293
23 changed files with 9768 additions and 9095 deletions

View file

@ -313,6 +313,34 @@ Transform3d assemble_transform(const Vec3d& translation, const Vec3d& rotation,
return transform; return transform;
} }
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
void rotation_transform(Transform3d& transform, const Vec3d& rotation)
{
transform = Transform3d::Identity();
transform.rotate(Eigen::AngleAxisd(rotation.z(), Vec3d::UnitZ()) * Eigen::AngleAxisd(rotation.y(), Vec3d::UnitY()) * Eigen::AngleAxisd(rotation.x(), Vec3d::UnitX()));
}
Transform3d rotation_transform(const Vec3d& rotation)
{
Transform3d transform;
rotation_transform(transform, rotation);
return transform;
}
void scale_transform(Transform3d& transform, const Vec3d& scale)
{
transform = Transform3d::Identity();
transform.scale(scale);
}
Transform3d scale_transform(const Vec3d& scale)
{
Transform3d transform;
scale_transform(transform, scale);
return transform;
}
#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES
Vec3d extract_euler_angles(const Eigen::Matrix<double, 3, 3, Eigen::DontAlign>& rotation_matrix) Vec3d extract_euler_angles(const Eigen::Matrix<double, 3, 3, Eigen::DontAlign>& rotation_matrix)
{ {
// reference: http://eecs.qmul.ac.uk/~gslabaugh/publications/euler.pdf // reference: http://eecs.qmul.ac.uk/~gslabaugh/publications/euler.pdf
@ -363,6 +391,46 @@ Vec3d extract_euler_angles(const Transform3d& transform)
return extract_euler_angles(m); return extract_euler_angles(m);
} }
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
Transform3d Transformation::get_offset_matrix() const
{
return assemble_transform(get_offset());
}
static Transform3d extract_rotation(const Transform3d& trafo)
{
Matrix3d rotation;
Matrix3d scale;
trafo.computeRotationScaling(&rotation, &scale);
return Transform3d(rotation);
}
static Transform3d extract_scale(const Transform3d& trafo)
{
Matrix3d rotation;
Matrix3d scale;
trafo.computeRotationScaling(&rotation, &scale);
return Transform3d(scale);
}
static std::pair<Transform3d, Transform3d> extract_rotation_scale(const Transform3d& trafo)
{
Matrix3d rotation;
Matrix3d scale;
trafo.computeRotationScaling(&rotation, &scale);
return { Transform3d(rotation), Transform3d(scale) };
}
Vec3d Transformation::get_rotation() const
{
return extract_euler_angles(extract_rotation(m_matrix));
}
Transform3d Transformation::get_rotation_matrix() const
{
return extract_rotation(m_matrix);
}
#else
bool Transformation::Flags::needs_update(bool dont_translate, bool dont_rotate, bool dont_scale, bool dont_mirror) const bool Transformation::Flags::needs_update(bool dont_translate, bool dont_rotate, bool dont_scale, bool dont_mirror) const
{ {
return (this->dont_translate != dont_translate) || (this->dont_rotate != dont_rotate) || (this->dont_scale != dont_scale) || (this->dont_mirror != dont_mirror); return (this->dont_translate != dont_translate) || (this->dont_rotate != dont_rotate) || (this->dont_scale != dont_scale) || (this->dont_mirror != dont_mirror);
@ -400,12 +468,19 @@ void Transformation::set_offset(Axis axis, double offset)
m_dirty = true; m_dirty = true;
} }
} }
#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES
void Transformation::set_rotation(const Vec3d& rotation) void Transformation::set_rotation(const Vec3d& rotation)
{ {
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
const Vec3d offset = get_offset();
m_matrix = rotation_transform(rotation) * extract_scale(m_matrix);
m_matrix.translation() = offset;
#else
set_rotation(X, rotation.x()); set_rotation(X, rotation.x());
set_rotation(Y, rotation.y()); set_rotation(Y, rotation.y());
set_rotation(Z, rotation.z()); set_rotation(Z, rotation.z());
#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES
} }
void Transformation::set_rotation(Axis axis, double rotation) void Transformation::set_rotation(Axis axis, double rotation)
@ -414,32 +489,106 @@ void Transformation::set_rotation(Axis axis, double rotation)
if (is_approx(std::abs(rotation), 2.0 * double(PI))) if (is_approx(std::abs(rotation), 2.0 * double(PI)))
rotation = 0.0; rotation = 0.0;
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
auto [curr_rotation, scale] = extract_rotation_scale(m_matrix);
Vec3d angles = extract_euler_angles(curr_rotation);
angles[axis] = rotation;
const Vec3d offset = get_offset();
m_matrix = rotation_transform(angles) * scale;
m_matrix.translation() = offset;
#else
if (m_rotation(axis) != rotation) { if (m_rotation(axis) != rotation) {
m_rotation(axis) = rotation; m_rotation(axis) = rotation;
m_dirty = true; m_dirty = true;
} }
#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES
} }
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
Vec3d Transformation::get_scaling_factor() const
{
const Transform3d scale = extract_scale(m_matrix);
return { scale(0, 0), scale(1, 1), scale(2, 2) };
}
Transform3d Transformation::get_scaling_factor_matrix() const
{
return extract_scale(m_matrix);
}
#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES
void Transformation::set_scaling_factor(const Vec3d& scaling_factor) void Transformation::set_scaling_factor(const Vec3d& scaling_factor)
{ {
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
assert(scaling_factor.x() > 0.0 && scaling_factor.y() > 0.0 && scaling_factor.z() > 0.0);
const Vec3d offset = get_offset();
m_matrix = extract_rotation(m_matrix) * scale_transform(scaling_factor);
m_matrix.translation() = offset;
#else
set_scaling_factor(X, scaling_factor.x()); set_scaling_factor(X, scaling_factor.x());
set_scaling_factor(Y, scaling_factor.y()); set_scaling_factor(Y, scaling_factor.y());
set_scaling_factor(Z, scaling_factor.z()); set_scaling_factor(Z, scaling_factor.z());
#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES
} }
void Transformation::set_scaling_factor(Axis axis, double scaling_factor) void Transformation::set_scaling_factor(Axis axis, double scaling_factor)
{ {
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
assert(scaling_factor > 0.0);
auto [rotation, scale] = extract_rotation_scale(m_matrix);
scale(axis, axis) = scaling_factor;
const Vec3d offset = get_offset();
m_matrix = rotation * scale;
m_matrix.translation() = offset;
#else
if (m_scaling_factor(axis) != std::abs(scaling_factor)) { if (m_scaling_factor(axis) != std::abs(scaling_factor)) {
m_scaling_factor(axis) = std::abs(scaling_factor); m_scaling_factor(axis) = std::abs(scaling_factor);
m_dirty = true; m_dirty = true;
} }
#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES
} }
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
Vec3d Transformation::get_mirror() const
{
const Transform3d scale = extract_scale(m_matrix);
return { scale(0, 0) / std::abs(scale(0, 0)), scale(1, 1) / std::abs(scale(1, 1)), scale(2, 2) / std::abs(scale(2, 2)) };
}
Transform3d Transformation::get_mirror_matrix() const
{
const Vec3d scale = get_scaling_factor();
return scale_transform({ scale.x() / std::abs(scale.x()), scale.y() / std::abs(scale.y()), scale.z() / std::abs(scale.z()) });
}
#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES
void Transformation::set_mirror(const Vec3d& mirror) void Transformation::set_mirror(const Vec3d& mirror)
{ {
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
Vec3d copy(mirror);
const Vec3d abs_mirror = copy.cwiseAbs();
for (int i = 0; i < 3; ++i) {
if (abs_mirror(i) == 0.0)
copy(i) = 1.0;
else if (abs_mirror(i) != 1.0)
copy(i) /= abs_mirror(i);
}
const Vec3d curr_scale = get_scaling_factor();
const Vec3d signs = curr_scale.cwiseProduct(copy);
set_scaling_factor({
signs.x() < 0.0 ? std::abs(curr_scale.x()) * copy.x() : curr_scale.x(),
signs.y() < 0.0 ? std::abs(curr_scale.y()) * copy.y() : curr_scale.y(),
signs.z() < 0.0 ? std::abs(curr_scale.z()) * copy.z() : curr_scale.z()
});
#else
set_mirror(X, mirror.x()); set_mirror(X, mirror.x());
set_mirror(Y, mirror.y()); set_mirror(Y, mirror.y());
set_mirror(Z, mirror.z()); set_mirror(Z, mirror.z());
#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES
} }
void Transformation::set_mirror(Axis axis, double mirror) void Transformation::set_mirror(Axis axis, double mirror)
@ -450,12 +599,19 @@ void Transformation::set_mirror(Axis axis, double mirror)
else if (abs_mirror != 1.0) else if (abs_mirror != 1.0)
mirror /= abs_mirror; mirror /= abs_mirror;
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
const double curr_scale = get_scaling_factor(axis);
const double sign = curr_scale * mirror;
set_scaling_factor(axis, sign < 0.0 ? std::abs(curr_scale) * mirror : curr_scale);
#else
if (m_mirror(axis) != mirror) { if (m_mirror(axis) != mirror) {
m_mirror(axis) = mirror; m_mirror(axis) = mirror;
m_dirty = true; m_dirty = true;
} }
#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES
} }
#if !ENABLE_TRANSFORMATIONS_BY_MATRICES
void Transformation::set_from_transform(const Transform3d& transform) void Transformation::set_from_transform(const Transform3d& transform)
{ {
// offset // offset
@ -493,17 +649,38 @@ void Transformation::set_from_transform(const Transform3d& transform)
// if (!m_matrix.isApprox(transform)) // if (!m_matrix.isApprox(transform))
// std::cout << "something went wrong in extracting data from matrix" << std::endl; // std::cout << "something went wrong in extracting data from matrix" << std::endl;
} }
#endif // !ENABLE_TRANSFORMATIONS_BY_MATRICES
void Transformation::reset() void Transformation::reset()
{ {
#if !ENABLE_TRANSFORMATIONS_BY_MATRICES
m_offset = Vec3d::Zero(); m_offset = Vec3d::Zero();
m_rotation = Vec3d::Zero(); m_rotation = Vec3d::Zero();
m_scaling_factor = Vec3d::Ones(); m_scaling_factor = Vec3d::Ones();
m_mirror = Vec3d::Ones(); m_mirror = Vec3d::Ones();
#endif // !ENABLE_TRANSFORMATIONS_BY_MATRICES
m_matrix = Transform3d::Identity(); m_matrix = Transform3d::Identity();
#if !ENABLE_TRANSFORMATIONS_BY_MATRICES
m_dirty = false; m_dirty = false;
#endif // !ENABLE_TRANSFORMATIONS_BY_MATRICES
} }
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
Transform3d Transformation::get_matrix_no_offset() const
{
Transformation copy(*this);
copy.reset_offset();
return copy.get_matrix();
}
Transform3d Transformation::get_matrix_no_scaling_factor() const
{
Transformation copy(*this);
copy.reset_scaling_factor();
copy.reset_mirror();
return copy.get_matrix();
}
#else
const Transform3d& Transformation::get_matrix(bool dont_translate, bool dont_rotate, bool dont_scale, bool dont_mirror) const const Transform3d& Transformation::get_matrix(bool dont_translate, bool dont_rotate, bool dont_scale, bool dont_mirror) const
{ {
if (m_dirty || m_flags.needs_update(dont_translate, dont_rotate, dont_scale, dont_mirror)) { if (m_dirty || m_flags.needs_update(dont_translate, dont_rotate, dont_scale, dont_mirror)) {
@ -520,6 +697,7 @@ const Transform3d& Transformation::get_matrix(bool dont_translate, bool dont_rot
return m_matrix; return m_matrix;
} }
#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES
Transformation Transformation::operator * (const Transformation& other) const Transformation Transformation::operator * (const Transformation& other) const
{ {
@ -533,7 +711,11 @@ Transformation Transformation::volume_to_bed_transformation(const Transformation
if (instance_transformation.is_scaling_uniform()) { if (instance_transformation.is_scaling_uniform()) {
// No need to run the non-linear least squares fitting for uniform scaling. // No need to run the non-linear least squares fitting for uniform scaling.
// Just set the inverse. // Just set the inverse.
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
out = instance_transformation.get_matrix_no_offset().inverse();
#else
out.set_from_transform(instance_transformation.get_matrix(true).inverse()); out.set_from_transform(instance_transformation.get_matrix(true).inverse());
#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES
} }
else if (is_rotation_ninety_degrees(instance_transformation.get_rotation())) { else if (is_rotation_ninety_degrees(instance_transformation.get_rotation())) {
// Anisotropic scaling, rotation by multiples of ninety degrees. // Anisotropic scaling, rotation by multiples of ninety degrees.

View file

@ -334,6 +334,26 @@ void assemble_transform(Transform3d& transform, const Vec3d& translation = Vec3d
// 6) translate // 6) translate
Transform3d assemble_transform(const Vec3d& translation = Vec3d::Zero(), const Vec3d& rotation = Vec3d::Zero(), const Vec3d& scale = Vec3d::Ones(), const Vec3d& mirror = Vec3d::Ones()); Transform3d assemble_transform(const Vec3d& translation = Vec3d::Zero(), const Vec3d& rotation = Vec3d::Zero(), const Vec3d& scale = Vec3d::Ones(), const Vec3d& mirror = Vec3d::Ones());
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
// Sets the given transform by assembling the given rotations in the following order:
// 1) rotate X
// 2) rotate Y
// 3) rotate Z
void rotation_transform(Transform3d& transform, const Vec3d& rotation);
// Returns the transform obtained by assembling the given rotations in the following order:
// 1) rotate X
// 2) rotate Y
// 3) rotate Z
Transform3d rotation_transform(const Vec3d& rotation);
// Sets the given transform by assembling the given scale factors
void scale_transform(Transform3d& transform, const Vec3d& scale);
// Returns the transform obtained by assembling the given scale factors
Transform3d scale_transform(const Vec3d& scale);
#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES
// Returns the euler angles extracted from the given rotation matrix // Returns the euler angles extracted from the given rotation matrix
// Warning -> The matrix should not contain any scale or shear !!! // Warning -> The matrix should not contain any scale or shear !!!
Vec3d extract_euler_angles(const Eigen::Matrix<double, 3, 3, Eigen::DontAlign>& rotation_matrix); Vec3d extract_euler_angles(const Eigen::Matrix<double, 3, 3, Eigen::DontAlign>& rotation_matrix);
@ -344,6 +364,9 @@ Vec3d extract_euler_angles(const Transform3d& transform);
class Transformation class Transformation
{ {
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
Transform3d m_matrix{ Transform3d::Identity() };
#else
struct Flags struct Flags
{ {
bool dont_translate{ true }; bool dont_translate{ true };
@ -363,42 +386,104 @@ class Transformation
mutable Transform3d m_matrix{ Transform3d::Identity() }; mutable Transform3d m_matrix{ Transform3d::Identity() };
mutable Flags m_flags; mutable Flags m_flags;
mutable bool m_dirty{ false }; mutable bool m_dirty{ false };
#endif // !ENABLE_TRANSFORMATIONS_BY_MATRICES
public: public:
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
Transformation() = default;
explicit Transformation(const Transform3d & transform) : m_matrix(transform) {}
#else
Transformation(); Transformation();
explicit Transformation(const Transform3d& transform); explicit Transformation(const Transform3d & transform);
#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
Transformation& operator = (const Transform3d& transform) { m_matrix = transform; return *this; }
Vec3d get_offset() const { return m_matrix.translation(); }
double get_offset(Axis axis) const { return get_offset()[axis]; }
Transform3d get_offset_matrix() const;
void set_offset(const Vec3d& offset) { m_matrix.translation() = offset; }
void set_offset(Axis axis, double offset) { m_matrix.translation()[axis] = offset; }
#else
const Vec3d& get_offset() const { return m_offset; } const Vec3d& get_offset() const { return m_offset; }
double get_offset(Axis axis) const { return m_offset(axis); } double get_offset(Axis axis) const { return m_offset(axis); }
void set_offset(const Vec3d& offset); void set_offset(const Vec3d& offset);
void set_offset(Axis axis, double offset); void set_offset(Axis axis, double offset);
#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
Vec3d get_rotation() const;
double get_rotation(Axis axis) const { return get_rotation()[axis]; }
Transform3d get_rotation_matrix() const;
#else
const Vec3d& get_rotation() const { return m_rotation; } const Vec3d& get_rotation() const { return m_rotation; }
double get_rotation(Axis axis) const { return m_rotation(axis); } double get_rotation(Axis axis) const { return m_rotation(axis); }
#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES
void set_rotation(const Vec3d& rotation); void set_rotation(const Vec3d& rotation);
void set_rotation(Axis axis, double rotation); void set_rotation(Axis axis, double rotation);
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
Vec3d get_scaling_factor() const;
double get_scaling_factor(Axis axis) const { return get_scaling_factor()[axis]; }
Transform3d get_scaling_factor_matrix() const;
bool is_scaling_uniform() const {
const Vec3d scale = get_scaling_factor();
return std::abs(scale.x() - scale.y()) < 1e-8 && std::abs(scale.x() - scale.z()) < 1e-8;
}
#else
const Vec3d& get_scaling_factor() const { return m_scaling_factor; } const Vec3d& get_scaling_factor() const { return m_scaling_factor; }
double get_scaling_factor(Axis axis) const { return m_scaling_factor(axis); } double get_scaling_factor(Axis axis) const { return m_scaling_factor(axis); }
#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES
void set_scaling_factor(const Vec3d& scaling_factor); void set_scaling_factor(const Vec3d& scaling_factor);
void set_scaling_factor(Axis axis, double scaling_factor); void set_scaling_factor(Axis axis, double scaling_factor);
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
Vec3d get_mirror() const;
double get_mirror(Axis axis) const { return get_mirror()[axis]; }
Transform3d get_mirror_matrix() const;
bool is_left_handed() const {
const Vec3d mirror = get_mirror();
return mirror.x() * mirror.y() * mirror.z() < 0.0;
}
#else
bool is_scaling_uniform() const { return std::abs(m_scaling_factor.x() - m_scaling_factor.y()) < 1e-8 && std::abs(m_scaling_factor.x() - m_scaling_factor.z()) < 1e-8; } bool is_scaling_uniform() const { return std::abs(m_scaling_factor.x() - m_scaling_factor.y()) < 1e-8 && std::abs(m_scaling_factor.x() - m_scaling_factor.z()) < 1e-8; }
const Vec3d& get_mirror() const { return m_mirror; } const Vec3d& get_mirror() const { return m_mirror; }
double get_mirror(Axis axis) const { return m_mirror(axis); } double get_mirror(Axis axis) const { return m_mirror(axis); }
bool is_left_handed() const { return m_mirror.x() * m_mirror.y() * m_mirror.z() < 0.; } bool is_left_handed() const { return m_mirror.x() * m_mirror.y() * m_mirror.z() < 0.; }
#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES
void set_mirror(const Vec3d& mirror); void set_mirror(const Vec3d& mirror);
void set_mirror(Axis axis, double mirror); void set_mirror(Axis axis, double mirror);
#if !ENABLE_TRANSFORMATIONS_BY_MATRICES
void set_from_transform(const Transform3d& transform); void set_from_transform(const Transform3d& transform);
#endif // !ENABLE_TRANSFORMATIONS_BY_MATRICES
void reset(); void reset();
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
void reset_offset() { set_offset(Vec3d::Zero()); }
void reset_rotation() { set_rotation(Vec3d::Zero()); }
void reset_scaling_factor() { set_scaling_factor(Vec3d::Ones()); }
void reset_mirror() { set_mirror(Vec3d::Ones()); }
const Transform3d& get_matrix() const { return m_matrix; }
Transform3d get_matrix_no_offset() const;
Transform3d get_matrix_no_scaling_factor() const;
#else
const Transform3d& get_matrix(bool dont_translate = false, bool dont_rotate = false, bool dont_scale = false, bool dont_mirror = false) const; const Transform3d& get_matrix(bool dont_translate = false, bool dont_rotate = false, bool dont_scale = false, bool dont_mirror = false) const;
#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES
Transformation operator * (const Transformation& other) const; Transformation operator * (const Transformation& other) const;
@ -408,15 +493,26 @@ public:
static Transformation volume_to_bed_transformation(const Transformation& instance_transformation, const BoundingBoxf3& bbox); static Transformation volume_to_bed_transformation(const Transformation& instance_transformation, const BoundingBoxf3& bbox);
private: private:
friend class cereal::access; friend class cereal::access;
template<class Archive> void serialize(Archive & ar) { ar(m_offset, m_rotation, m_scaling_factor, m_mirror); } #if ENABLE_TRANSFORMATIONS_BY_MATRICES
explicit Transformation(int) : m_dirty(true) {} template<class Archive> void serialize(Archive& ar) { ar(m_matrix); }
template <class Archive> static void load_and_construct(Archive &ar, cereal::construct<Transformation> &construct) 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); // Calling a private constructor with special "int" parameter to indicate that no construction is necessary.
ar(construct.ptr()->m_offset, construct.ptr()->m_rotation, construct.ptr()->m_scaling_factor, construct.ptr()->m_mirror); construct(1);
} ar(construct.ptr()->m_matrix);
}
#else
template<class Archive> void serialize(Archive& ar) { ar(m_offset, m_rotation, m_scaling_factor, m_mirror); }
explicit Transformation(int) : m_dirty(true) {}
template <class Archive> static void load_and_construct(Archive& ar, cereal::construct<Transformation>& construct)
{
// 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);
}
#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES
}; };
// For parsing a transformation matrix from 3MF / AMF. // For parsing a transformation matrix from 3MF / AMF.

View file

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

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -79,6 +79,8 @@
#define ENABLE_WORLD_COORDINATE_SHOW_AXES (1 && ENABLE_WORLD_COORDINATE) #define ENABLE_WORLD_COORDINATE_SHOW_AXES (1 && ENABLE_WORLD_COORDINATE)
// Enable alternate implementation of manipulating scale for instances and volumes // Enable alternate implementation of manipulating scale for instances and volumes
#define ENABLE_WORLD_COORDINATE_SCALE_REVISITED (1 && ENABLE_WORLD_COORDINATE) #define ENABLE_WORLD_COORDINATE_SCALE_REVISITED (1 && ENABLE_WORLD_COORDINATE)
// Enable implementation of Geometry::Transformation using matrices only
#define ENABLE_TRANSFORMATIONS_BY_MATRICES (1 && ENABLE_WORLD_COORDINATE)
// Enable modified camera control using mouse // Enable modified camera control using mouse
#define ENABLE_NEW_CAMERA_MOVEMENTS (1 && ENABLE_2_5_0_ALPHA1) #define ENABLE_NEW_CAMERA_MOVEMENTS (1 && ENABLE_2_5_0_ALPHA1)
// Enable modified rectangle selection // Enable modified rectangle selection

File diff suppressed because it is too large Load diff

View file

@ -1532,7 +1532,11 @@ void ObjectList::load_modifier(const wxArrayString& input_files, ModelObject& mo
// First (any) GLVolume of the selected instance. They all share the same instance matrix. // First (any) GLVolume of the selected instance. They all share the same instance matrix.
const GLVolume* v = selection.get_volume(*selection.get_volume_idxs().begin()); const GLVolume* v = selection.get_volume(*selection.get_volume_idxs().begin());
const Geometry::Transformation inst_transform = v->get_instance_transformation(); const Geometry::Transformation inst_transform = v->get_instance_transformation();
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
const Transform3d inv_inst_transform = inst_transform.get_matrix_no_offset().inverse();
#else
const Transform3d inv_inst_transform = inst_transform.get_matrix(true).inverse(); const Transform3d inv_inst_transform = inst_transform.get_matrix(true).inverse();
#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES
const Vec3d instance_offset = v->get_instance_offset(); const Vec3d instance_offset = v->get_instance_offset();
for (size_t i = 0; i < input_files.size(); ++i) { for (size_t i = 0; i < input_files.size(); ++i) {
@ -1660,7 +1664,11 @@ void ObjectList::load_generic_subobject(const std::string& type_name, const Mode
Vec3d(0., 0., 0.5 * mesh_bb.size().z() + instance_bb.min.z() - v->get_instance_offset().z()) : Vec3d(0., 0., 0.5 * mesh_bb.size().z() + instance_bb.min.z() - v->get_instance_offset().z()) :
// Translate the new modifier to be pickable: move to the left front corner of the instance's bounding box, lift to print bed. // Translate the new modifier to be pickable: move to the left front corner of the instance's bounding box, lift to print bed.
Vec3d(instance_bb.max.x(), instance_bb.min.y(), instance_bb.min.z()) + 0.5 * mesh_bb.size() - v->get_instance_offset(); Vec3d(instance_bb.max.x(), instance_bb.min.y(), instance_bb.min.z()) + 0.5 * mesh_bb.size() - v->get_instance_offset();
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
new_volume->set_offset(v->get_instance_transformation().get_matrix_no_offset().inverse() * offset);
#else
new_volume->set_offset(v->get_instance_transformation().get_matrix(true).inverse() * offset); new_volume->set_offset(v->get_instance_transformation().get_matrix(true).inverse() * offset);
#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES
const wxString name = _L("Generic") + "-" + _(type_name); const wxString name = _L("Generic") + "-" + _(type_name);
new_volume->name = into_u8(name); new_volume->name = into_u8(name);

View file

@ -354,7 +354,11 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
const double min_z = get_volume_min_z(*volume); const double min_z = get_volume_min_z(*volume);
if (!is_world_coordinates()) { if (!is_world_coordinates()) {
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
const Vec3d diff = m_cache.position - volume->get_instance_transformation().get_matrix_no_offset().inverse() * (min_z * Vec3d::UnitZ());
#else
const Vec3d diff = m_cache.position - volume->get_instance_transformation().get_matrix(true).inverse() * (min_z * Vec3d::UnitZ()); const Vec3d diff = m_cache.position - volume->get_instance_transformation().get_matrix(true).inverse() * (min_z * Vec3d::UnitZ());
#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Drop to bed")); Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Drop to bed"));
change_position_value(0, diff.x()); change_position_value(0, diff.x());
@ -381,7 +385,11 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
const double min_z = selection.get_scaled_instance_bounding_box().min.z(); const double min_z = selection.get_scaled_instance_bounding_box().min.z();
if (!is_world_coordinates()) { if (!is_world_coordinates()) {
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
const Vec3d diff = m_cache.position - volume->get_instance_transformation().get_matrix_no_offset().inverse() * (min_z * Vec3d::UnitZ());
#else
const Vec3d diff = m_cache.position - volume->get_instance_transformation().get_matrix(true).inverse() * (min_z * Vec3d::UnitZ()); const Vec3d diff = m_cache.position - volume->get_instance_transformation().get_matrix(true).inverse() * (min_z * Vec3d::UnitZ());
#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Drop to bed")); Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Drop to bed"));
change_position_value(0, diff.x()); change_position_value(0, diff.x());

View file

@ -1,437 +1,441 @@
#include "GLGizmoFdmSupports.hpp" #include "GLGizmoFdmSupports.hpp"
#include "libslic3r/Model.hpp" #include "libslic3r/Model.hpp"
//#include "slic3r/GUI/3DScene.hpp" //#include "slic3r/GUI/3DScene.hpp"
#include "slic3r/GUI/GLCanvas3D.hpp" #include "slic3r/GUI/GLCanvas3D.hpp"
#include "slic3r/GUI/GUI_App.hpp" #include "slic3r/GUI/GUI_App.hpp"
#include "slic3r/GUI/ImGuiWrapper.hpp" #include "slic3r/GUI/ImGuiWrapper.hpp"
#include "slic3r/GUI/Plater.hpp" #include "slic3r/GUI/Plater.hpp"
#include "slic3r/GUI/GUI_ObjectList.hpp" #include "slic3r/GUI/GUI_ObjectList.hpp"
#include "slic3r/GUI/format.hpp" #include "slic3r/GUI/format.hpp"
#include "slic3r/Utils/UndoRedo.hpp" #include "slic3r/Utils/UndoRedo.hpp"
#include <GL/glew.h> #include <GL/glew.h>
namespace Slic3r::GUI { namespace Slic3r::GUI {
void GLGizmoFdmSupports::on_shutdown() void GLGizmoFdmSupports::on_shutdown()
{ {
m_highlight_by_angle_threshold_deg = 0.f; m_highlight_by_angle_threshold_deg = 0.f;
m_parent.use_slope(false); m_parent.use_slope(false);
m_parent.toggle_model_objects_visibility(true); m_parent.toggle_model_objects_visibility(true);
} }
std::string GLGizmoFdmSupports::on_get_name() const std::string GLGizmoFdmSupports::on_get_name() const
{ {
return _u8L("Paint-on supports"); return _u8L("Paint-on supports");
} }
bool GLGizmoFdmSupports::on_init() bool GLGizmoFdmSupports::on_init()
{ {
m_shortcut_key = WXK_CONTROL_L; m_shortcut_key = WXK_CONTROL_L;
m_desc["clipping_of_view"] = _L("Clipping of view") + ": "; m_desc["clipping_of_view"] = _L("Clipping of view") + ": ";
m_desc["reset_direction"] = _L("Reset direction"); m_desc["reset_direction"] = _L("Reset direction");
m_desc["cursor_size"] = _L("Brush size") + ": "; m_desc["cursor_size"] = _L("Brush size") + ": ";
m_desc["cursor_type"] = _L("Brush shape") + ": "; m_desc["cursor_type"] = _L("Brush shape") + ": ";
m_desc["enforce_caption"] = _L("Left mouse button") + ": "; m_desc["enforce_caption"] = _L("Left mouse button") + ": ";
m_desc["enforce"] = _L("Enforce supports"); m_desc["enforce"] = _L("Enforce supports");
m_desc["block_caption"] = _L("Right mouse button") + ": "; m_desc["block_caption"] = _L("Right mouse button") + ": ";
m_desc["block"] = _L("Block supports"); m_desc["block"] = _L("Block supports");
m_desc["remove_caption"] = _L("Shift + Left mouse button") + ": "; m_desc["remove_caption"] = _L("Shift + Left mouse button") + ": ";
m_desc["remove"] = _L("Remove selection"); m_desc["remove"] = _L("Remove selection");
m_desc["remove_all"] = _L("Remove all selection"); m_desc["remove_all"] = _L("Remove all selection");
m_desc["circle"] = _L("Circle"); m_desc["circle"] = _L("Circle");
m_desc["sphere"] = _L("Sphere"); m_desc["sphere"] = _L("Sphere");
m_desc["pointer"] = _L("Triangles"); m_desc["pointer"] = _L("Triangles");
m_desc["highlight_by_angle"] = _L("Highlight overhang by angle"); m_desc["highlight_by_angle"] = _L("Highlight overhang by angle");
m_desc["enforce_button"] = _L("Enforce"); m_desc["enforce_button"] = _L("Enforce");
m_desc["cancel"] = _L("Cancel"); m_desc["cancel"] = _L("Cancel");
m_desc["tool_type"] = _L("Tool type") + ": "; m_desc["tool_type"] = _L("Tool type") + ": ";
m_desc["tool_brush"] = _L("Brush"); m_desc["tool_brush"] = _L("Brush");
m_desc["tool_smart_fill"] = _L("Smart fill"); m_desc["tool_smart_fill"] = _L("Smart fill");
m_desc["smart_fill_angle"] = _L("Smart fill angle"); m_desc["smart_fill_angle"] = _L("Smart fill angle");
m_desc["split_triangles"] = _L("Split triangles"); m_desc["split_triangles"] = _L("Split triangles");
m_desc["on_overhangs_only"] = _L("On overhangs only"); m_desc["on_overhangs_only"] = _L("On overhangs only");
return true; return true;
} }
void GLGizmoFdmSupports::render_painter_gizmo() void GLGizmoFdmSupports::render_painter_gizmo()
{ {
const Selection& selection = m_parent.get_selection(); const Selection& selection = m_parent.get_selection();
glsafe(::glEnable(GL_BLEND)); glsafe(::glEnable(GL_BLEND));
glsafe(::glEnable(GL_DEPTH_TEST)); glsafe(::glEnable(GL_DEPTH_TEST));
render_triangles(selection); render_triangles(selection);
m_c->object_clipper()->render_cut(); m_c->object_clipper()->render_cut();
m_c->instances_hider()->render_cut(); m_c->instances_hider()->render_cut();
render_cursor(); render_cursor();
glsafe(::glDisable(GL_BLEND)); glsafe(::glDisable(GL_BLEND));
} }
void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_limit) void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_limit)
{ {
if (! m_c->selection_info()->model_object()) if (! m_c->selection_info()->model_object())
return; return;
const float approx_height = m_imgui->scaled(23.f); const float approx_height = m_imgui->scaled(23.f);
y = std::min(y, bottom_limit - approx_height); y = std::min(y, bottom_limit - approx_height);
m_imgui->set_next_window_pos(x, y, ImGuiCond_Always); m_imgui->set_next_window_pos(x, y, ImGuiCond_Always);
m_imgui->begin(get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse); m_imgui->begin(get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse);
// First calculate width of all the texts that are could possibly be shown. We will decide set the dialog width based on that: // First calculate width of all the texts that are could possibly be shown. We will decide set the dialog width based on that:
const float clipping_slider_left = std::max(m_imgui->calc_text_size(m_desc.at("clipping_of_view")).x, const float clipping_slider_left = std::max(m_imgui->calc_text_size(m_desc.at("clipping_of_view")).x,
m_imgui->calc_text_size(m_desc.at("reset_direction")).x) + m_imgui->scaled(1.5f); m_imgui->calc_text_size(m_desc.at("reset_direction")).x) + m_imgui->scaled(1.5f);
const float cursor_slider_left = m_imgui->calc_text_size(m_desc.at("cursor_size")).x + m_imgui->scaled(1.f); const float cursor_slider_left = m_imgui->calc_text_size(m_desc.at("cursor_size")).x + m_imgui->scaled(1.f);
const float smart_fill_slider_left = m_imgui->calc_text_size(m_desc.at("smart_fill_angle")).x + m_imgui->scaled(1.f); const float smart_fill_slider_left = m_imgui->calc_text_size(m_desc.at("smart_fill_angle")).x + m_imgui->scaled(1.f);
const float autoset_slider_label_max_width = m_imgui->scaled(7.5f); const float autoset_slider_label_max_width = m_imgui->scaled(7.5f);
const float autoset_slider_left = m_imgui->calc_text_size(m_desc.at("highlight_by_angle"), autoset_slider_label_max_width).x + m_imgui->scaled(1.f); const float autoset_slider_left = m_imgui->calc_text_size(m_desc.at("highlight_by_angle"), autoset_slider_label_max_width).x + m_imgui->scaled(1.f);
const float cursor_type_radio_circle = m_imgui->calc_text_size(m_desc["circle"]).x + m_imgui->scaled(2.5f); const float cursor_type_radio_circle = m_imgui->calc_text_size(m_desc["circle"]).x + m_imgui->scaled(2.5f);
const float cursor_type_radio_sphere = m_imgui->calc_text_size(m_desc["sphere"]).x + m_imgui->scaled(2.5f); const float cursor_type_radio_sphere = m_imgui->calc_text_size(m_desc["sphere"]).x + m_imgui->scaled(2.5f);
const float cursor_type_radio_pointer = m_imgui->calc_text_size(m_desc["pointer"]).x + m_imgui->scaled(2.5f); const float cursor_type_radio_pointer = m_imgui->calc_text_size(m_desc["pointer"]).x + m_imgui->scaled(2.5f);
const float button_width = m_imgui->calc_text_size(m_desc.at("remove_all")).x + m_imgui->scaled(1.f); const float button_width = m_imgui->calc_text_size(m_desc.at("remove_all")).x + m_imgui->scaled(1.f);
const float button_enforce_width = m_imgui->calc_text_size(m_desc.at("enforce_button")).x; const float button_enforce_width = m_imgui->calc_text_size(m_desc.at("enforce_button")).x;
const float button_cancel_width = m_imgui->calc_text_size(m_desc.at("cancel")).x; const float button_cancel_width = m_imgui->calc_text_size(m_desc.at("cancel")).x;
const float buttons_width = std::max(button_enforce_width, button_cancel_width) + m_imgui->scaled(0.5f); const float buttons_width = std::max(button_enforce_width, button_cancel_width) + m_imgui->scaled(0.5f);
const float minimal_slider_width = m_imgui->scaled(4.f); const float minimal_slider_width = m_imgui->scaled(4.f);
const float tool_type_radio_left = m_imgui->calc_text_size(m_desc["tool_type"]).x + m_imgui->scaled(1.f); const float tool_type_radio_left = m_imgui->calc_text_size(m_desc["tool_type"]).x + m_imgui->scaled(1.f);
const float tool_type_radio_brush = m_imgui->calc_text_size(m_desc["tool_brush"]).x + m_imgui->scaled(2.5f); const float tool_type_radio_brush = m_imgui->calc_text_size(m_desc["tool_brush"]).x + m_imgui->scaled(2.5f);
const float tool_type_radio_smart_fill = m_imgui->calc_text_size(m_desc["tool_smart_fill"]).x + m_imgui->scaled(2.5f); const float tool_type_radio_smart_fill = m_imgui->calc_text_size(m_desc["tool_smart_fill"]).x + m_imgui->scaled(2.5f);
const float split_triangles_checkbox_width = m_imgui->calc_text_size(m_desc["split_triangles"]).x + m_imgui->scaled(2.5f); const float split_triangles_checkbox_width = m_imgui->calc_text_size(m_desc["split_triangles"]).x + m_imgui->scaled(2.5f);
const float on_overhangs_only_checkbox_width = m_imgui->calc_text_size(m_desc["on_overhangs_only"]).x + m_imgui->scaled(2.5f); const float on_overhangs_only_checkbox_width = m_imgui->calc_text_size(m_desc["on_overhangs_only"]).x + m_imgui->scaled(2.5f);
float caption_max = 0.f; float caption_max = 0.f;
float total_text_max = 0.f; float total_text_max = 0.f;
for (const auto &t : std::array<std::string, 3>{"enforce", "block", "remove"}) { for (const auto &t : std::array<std::string, 3>{"enforce", "block", "remove"}) {
caption_max = std::max(caption_max, m_imgui->calc_text_size(m_desc[t + "_caption"]).x); caption_max = std::max(caption_max, m_imgui->calc_text_size(m_desc[t + "_caption"]).x);
total_text_max = std::max(total_text_max, m_imgui->calc_text_size(m_desc[t]).x); total_text_max = std::max(total_text_max, m_imgui->calc_text_size(m_desc[t]).x);
} }
total_text_max += caption_max + m_imgui->scaled(1.f); total_text_max += caption_max + m_imgui->scaled(1.f);
caption_max += m_imgui->scaled(1.f); caption_max += m_imgui->scaled(1.f);
const float sliders_left_width = std::max(std::max(autoset_slider_left, smart_fill_slider_left), std::max(cursor_slider_left, clipping_slider_left)); const float sliders_left_width = std::max(std::max(autoset_slider_left, smart_fill_slider_left), std::max(cursor_slider_left, clipping_slider_left));
const float slider_icon_width = m_imgui->get_slider_icon_size().x; const float slider_icon_width = m_imgui->get_slider_icon_size().x;
float window_width = minimal_slider_width + sliders_left_width + slider_icon_width; float window_width = minimal_slider_width + sliders_left_width + slider_icon_width;
window_width = std::max(window_width, total_text_max); window_width = std::max(window_width, total_text_max);
window_width = std::max(window_width, button_width); window_width = std::max(window_width, button_width);
window_width = std::max(window_width, split_triangles_checkbox_width); window_width = std::max(window_width, split_triangles_checkbox_width);
window_width = std::max(window_width, on_overhangs_only_checkbox_width); window_width = std::max(window_width, on_overhangs_only_checkbox_width);
window_width = std::max(window_width, cursor_type_radio_circle + cursor_type_radio_sphere + cursor_type_radio_pointer); window_width = std::max(window_width, cursor_type_radio_circle + cursor_type_radio_sphere + cursor_type_radio_pointer);
window_width = std::max(window_width, tool_type_radio_left + tool_type_radio_brush + tool_type_radio_smart_fill); window_width = std::max(window_width, tool_type_radio_left + tool_type_radio_brush + tool_type_radio_smart_fill);
window_width = std::max(window_width, 2.f * buttons_width + m_imgui->scaled(1.f)); window_width = std::max(window_width, 2.f * buttons_width + m_imgui->scaled(1.f));
auto draw_text_with_caption = [this, &caption_max](const wxString& caption, const wxString& text) { auto draw_text_with_caption = [this, &caption_max](const wxString& caption, const wxString& text) {
m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, caption); m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, caption);
ImGui::SameLine(caption_max); ImGui::SameLine(caption_max);
m_imgui->text(text); m_imgui->text(text);
}; };
for (const auto &t : std::array<std::string, 3>{"enforce", "block", "remove"}) for (const auto &t : std::array<std::string, 3>{"enforce", "block", "remove"})
draw_text_with_caption(m_desc.at(t + "_caption"), m_desc.at(t)); draw_text_with_caption(m_desc.at(t + "_caption"), m_desc.at(t));
ImGui::Separator(); ImGui::Separator();
float position_before_text_y = ImGui::GetCursorPos().y; float position_before_text_y = ImGui::GetCursorPos().y;
ImGui::AlignTextToFramePadding(); ImGui::AlignTextToFramePadding();
m_imgui->text_wrapped(m_desc["highlight_by_angle"] + ":", autoset_slider_label_max_width); m_imgui->text_wrapped(m_desc["highlight_by_angle"] + ":", autoset_slider_label_max_width);
ImGui::AlignTextToFramePadding(); ImGui::AlignTextToFramePadding();
float position_after_text_y = ImGui::GetCursorPos().y; float position_after_text_y = ImGui::GetCursorPos().y;
std::string format_str = std::string("%.f") + I18N::translate_utf8("°", std::string format_str = std::string("%.f") + I18N::translate_utf8("°",
"Degree sign to use in the respective slider in FDM supports gizmo," "Degree sign to use in the respective slider in FDM supports gizmo,"
"placed after the number with no whitespace in between."); "placed after the number with no whitespace in between.");
ImGui::SameLine(sliders_left_width); ImGui::SameLine(sliders_left_width);
float slider_height = m_imgui->get_slider_float_height(); float slider_height = m_imgui->get_slider_float_height();
// Makes slider to be aligned to bottom of the multi-line text. // Makes slider to be aligned to bottom of the multi-line text.
float slider_start_position_y = std::max(position_before_text_y, position_after_text_y - slider_height); float slider_start_position_y = std::max(position_before_text_y, position_after_text_y - slider_height);
ImGui::SetCursorPosY(slider_start_position_y); ImGui::SetCursorPosY(slider_start_position_y);
ImGui::PushItemWidth(window_width - sliders_left_width - slider_icon_width); ImGui::PushItemWidth(window_width - sliders_left_width - slider_icon_width);
wxString tooltip = format_wxstr(_L("Preselects faces by overhang angle. It is possible to restrict paintable facets to only preselected faces when " wxString tooltip = format_wxstr(_L("Preselects faces by overhang angle. It is possible to restrict paintable facets to only preselected faces when "
"the option \"%1%\" is enabled."), m_desc["on_overhangs_only"]); "the option \"%1%\" is enabled."), m_desc["on_overhangs_only"]);
if (m_imgui->slider_float("##angle_threshold_deg", &m_highlight_by_angle_threshold_deg, 0.f, 90.f, format_str.data(), 1.0f, true, tooltip)) { if (m_imgui->slider_float("##angle_threshold_deg", &m_highlight_by_angle_threshold_deg, 0.f, 90.f, format_str.data(), 1.0f, true, tooltip)) {
m_parent.set_slope_normal_angle(90.f - m_highlight_by_angle_threshold_deg); m_parent.set_slope_normal_angle(90.f - m_highlight_by_angle_threshold_deg);
if (! m_parent.is_using_slope()) { if (! m_parent.is_using_slope()) {
m_parent.use_slope(true); m_parent.use_slope(true);
m_parent.set_as_dirty(); m_parent.set_as_dirty();
} }
} }
// Restores the cursor position to be below the multi-line text. // Restores the cursor position to be below the multi-line text.
ImGui::SetCursorPosY(std::max(position_before_text_y + slider_height, position_after_text_y)); ImGui::SetCursorPosY(std::max(position_before_text_y + slider_height, position_after_text_y));
const float max_tooltip_width = ImGui::GetFontSize() * 20.0f; const float max_tooltip_width = ImGui::GetFontSize() * 20.0f;
m_imgui->disabled_begin(m_highlight_by_angle_threshold_deg == 0.f); m_imgui->disabled_begin(m_highlight_by_angle_threshold_deg == 0.f);
ImGui::NewLine(); ImGui::NewLine();
ImGui::SameLine(window_width - 2.f*buttons_width - m_imgui->scaled(0.5f)); ImGui::SameLine(window_width - 2.f*buttons_width - m_imgui->scaled(0.5f));
if (m_imgui->button(m_desc["enforce_button"], buttons_width, 0.f)) { if (m_imgui->button(m_desc["enforce_button"], buttons_width, 0.f)) {
select_facets_by_angle(m_highlight_by_angle_threshold_deg, false); select_facets_by_angle(m_highlight_by_angle_threshold_deg, false);
m_highlight_by_angle_threshold_deg = 0.f; m_highlight_by_angle_threshold_deg = 0.f;
m_parent.use_slope(false); m_parent.use_slope(false);
} }
ImGui::SameLine(window_width - buttons_width); ImGui::SameLine(window_width - buttons_width);
if (m_imgui->button(m_desc["cancel"], buttons_width, 0.f)) { if (m_imgui->button(m_desc["cancel"], buttons_width, 0.f)) {
m_highlight_by_angle_threshold_deg = 0.f; m_highlight_by_angle_threshold_deg = 0.f;
m_parent.use_slope(false); m_parent.use_slope(false);
} }
m_imgui->disabled_end(); m_imgui->disabled_end();
ImGui::Separator(); ImGui::Separator();
ImGui::AlignTextToFramePadding(); ImGui::AlignTextToFramePadding();
m_imgui->text(m_desc["tool_type"]); m_imgui->text(m_desc["tool_type"]);
float tool_type_offset = tool_type_radio_left + (window_width - tool_type_radio_left - tool_type_radio_brush - tool_type_radio_smart_fill + m_imgui->scaled(0.5f)) / 2.f; float tool_type_offset = tool_type_radio_left + (window_width - tool_type_radio_left - tool_type_radio_brush - tool_type_radio_smart_fill + m_imgui->scaled(0.5f)) / 2.f;
ImGui::SameLine(tool_type_offset); ImGui::SameLine(tool_type_offset);
ImGui::PushItemWidth(tool_type_radio_brush); ImGui::PushItemWidth(tool_type_radio_brush);
if (m_imgui->radio_button(m_desc["tool_brush"], m_tool_type == ToolType::BRUSH)) if (m_imgui->radio_button(m_desc["tool_brush"], m_tool_type == ToolType::BRUSH))
m_tool_type = ToolType::BRUSH; m_tool_type = ToolType::BRUSH;
if (ImGui::IsItemHovered()) if (ImGui::IsItemHovered())
m_imgui->tooltip(_L("Paints facets according to the chosen painting brush."), max_tooltip_width); m_imgui->tooltip(_L("Paints facets according to the chosen painting brush."), max_tooltip_width);
ImGui::SameLine(tool_type_offset + tool_type_radio_brush); ImGui::SameLine(tool_type_offset + tool_type_radio_brush);
ImGui::PushItemWidth(tool_type_radio_smart_fill); ImGui::PushItemWidth(tool_type_radio_smart_fill);
if (m_imgui->radio_button(m_desc["tool_smart_fill"], m_tool_type == ToolType::SMART_FILL)) if (m_imgui->radio_button(m_desc["tool_smart_fill"], m_tool_type == ToolType::SMART_FILL))
m_tool_type = ToolType::SMART_FILL; m_tool_type = ToolType::SMART_FILL;
if (ImGui::IsItemHovered()) if (ImGui::IsItemHovered())
m_imgui->tooltip(_L("Paints neighboring facets whose relative angle is less or equal to set angle."), max_tooltip_width); m_imgui->tooltip(_L("Paints neighboring facets whose relative angle is less or equal to set angle."), max_tooltip_width);
m_imgui->checkbox(m_desc["on_overhangs_only"], m_paint_on_overhangs_only); m_imgui->checkbox(m_desc["on_overhangs_only"], m_paint_on_overhangs_only);
if (ImGui::IsItemHovered()) if (ImGui::IsItemHovered())
m_imgui->tooltip(format_wxstr(_L("Allows painting only on facets selected by: \"%1%\""), m_desc["highlight_by_angle"]), max_tooltip_width); m_imgui->tooltip(format_wxstr(_L("Allows painting only on facets selected by: \"%1%\""), m_desc["highlight_by_angle"]), max_tooltip_width);
ImGui::Separator(); ImGui::Separator();
if (m_tool_type == ToolType::BRUSH) { if (m_tool_type == ToolType::BRUSH) {
m_imgui->text(m_desc.at("cursor_type")); m_imgui->text(m_desc.at("cursor_type"));
ImGui::NewLine(); ImGui::NewLine();
float cursor_type_offset = (window_width - cursor_type_radio_sphere - cursor_type_radio_circle - cursor_type_radio_pointer + m_imgui->scaled(1.5f)) / 2.f; float cursor_type_offset = (window_width - cursor_type_radio_sphere - cursor_type_radio_circle - cursor_type_radio_pointer + m_imgui->scaled(1.5f)) / 2.f;
ImGui::SameLine(cursor_type_offset); ImGui::SameLine(cursor_type_offset);
ImGui::PushItemWidth(cursor_type_radio_sphere); ImGui::PushItemWidth(cursor_type_radio_sphere);
if (m_imgui->radio_button(m_desc["sphere"], m_cursor_type == TriangleSelector::CursorType::SPHERE)) if (m_imgui->radio_button(m_desc["sphere"], m_cursor_type == TriangleSelector::CursorType::SPHERE))
m_cursor_type = TriangleSelector::CursorType::SPHERE; m_cursor_type = TriangleSelector::CursorType::SPHERE;
if (ImGui::IsItemHovered()) if (ImGui::IsItemHovered())
m_imgui->tooltip(_L("Paints all facets inside, regardless of their orientation."), max_tooltip_width); m_imgui->tooltip(_L("Paints all facets inside, regardless of their orientation."), max_tooltip_width);
ImGui::SameLine(cursor_type_offset + cursor_type_radio_sphere); ImGui::SameLine(cursor_type_offset + cursor_type_radio_sphere);
ImGui::PushItemWidth(cursor_type_radio_circle); ImGui::PushItemWidth(cursor_type_radio_circle);
if (m_imgui->radio_button(m_desc["circle"], m_cursor_type == TriangleSelector::CursorType::CIRCLE)) if (m_imgui->radio_button(m_desc["circle"], m_cursor_type == TriangleSelector::CursorType::CIRCLE))
m_cursor_type = TriangleSelector::CursorType::CIRCLE; m_cursor_type = TriangleSelector::CursorType::CIRCLE;
if (ImGui::IsItemHovered()) if (ImGui::IsItemHovered())
m_imgui->tooltip(_L("Ignores facets facing away from the camera."), max_tooltip_width); m_imgui->tooltip(_L("Ignores facets facing away from the camera."), max_tooltip_width);
ImGui::SameLine(cursor_type_offset + cursor_type_radio_sphere + cursor_type_radio_circle); ImGui::SameLine(cursor_type_offset + cursor_type_radio_sphere + cursor_type_radio_circle);
ImGui::PushItemWidth(cursor_type_radio_pointer); ImGui::PushItemWidth(cursor_type_radio_pointer);
if (m_imgui->radio_button(m_desc["pointer"], m_cursor_type == TriangleSelector::CursorType::POINTER)) if (m_imgui->radio_button(m_desc["pointer"], m_cursor_type == TriangleSelector::CursorType::POINTER))
m_cursor_type = TriangleSelector::CursorType::POINTER; m_cursor_type = TriangleSelector::CursorType::POINTER;
if (ImGui::IsItemHovered()) if (ImGui::IsItemHovered())
m_imgui->tooltip(_L("Paints only one facet."), max_tooltip_width); m_imgui->tooltip(_L("Paints only one facet."), max_tooltip_width);
m_imgui->disabled_begin(m_cursor_type != TriangleSelector::CursorType::SPHERE && m_cursor_type != TriangleSelector::CursorType::CIRCLE); m_imgui->disabled_begin(m_cursor_type != TriangleSelector::CursorType::SPHERE && m_cursor_type != TriangleSelector::CursorType::CIRCLE);
ImGui::AlignTextToFramePadding(); ImGui::AlignTextToFramePadding();
m_imgui->text(m_desc.at("cursor_size")); m_imgui->text(m_desc.at("cursor_size"));
ImGui::SameLine(sliders_left_width); ImGui::SameLine(sliders_left_width);
ImGui::PushItemWidth(window_width - sliders_left_width - slider_icon_width); ImGui::PushItemWidth(window_width - sliders_left_width - slider_icon_width);
m_imgui->slider_float("##cursor_radius", &m_cursor_radius, CursorRadiusMin, CursorRadiusMax, "%.2f", 1.0f, true, _L("Alt + Mouse wheel")); m_imgui->slider_float("##cursor_radius", &m_cursor_radius, CursorRadiusMin, CursorRadiusMax, "%.2f", 1.0f, true, _L("Alt + Mouse wheel"));
m_imgui->checkbox(m_desc["split_triangles"], m_triangle_splitting_enabled); m_imgui->checkbox(m_desc["split_triangles"], m_triangle_splitting_enabled);
if (ImGui::IsItemHovered()) if (ImGui::IsItemHovered())
m_imgui->tooltip(_L("Splits bigger facets into smaller ones while the object is painted."), max_tooltip_width); m_imgui->tooltip(_L("Splits bigger facets into smaller ones while the object is painted."), max_tooltip_width);
m_imgui->disabled_end(); m_imgui->disabled_end();
} else { } else {
assert(m_tool_type == ToolType::SMART_FILL); assert(m_tool_type == ToolType::SMART_FILL);
ImGui::AlignTextToFramePadding(); ImGui::AlignTextToFramePadding();
m_imgui->text(m_desc["smart_fill_angle"] + ":"); m_imgui->text(m_desc["smart_fill_angle"] + ":");
ImGui::SameLine(sliders_left_width); ImGui::SameLine(sliders_left_width);
ImGui::PushItemWidth(window_width - sliders_left_width - slider_icon_width); ImGui::PushItemWidth(window_width - sliders_left_width - slider_icon_width);
if (m_imgui->slider_float("##smart_fill_angle", &m_smart_fill_angle, SmartFillAngleMin, SmartFillAngleMax, format_str.data(), 1.0f, true, _L("Alt + Mouse wheel"))) if (m_imgui->slider_float("##smart_fill_angle", &m_smart_fill_angle, SmartFillAngleMin, SmartFillAngleMax, format_str.data(), 1.0f, true, _L("Alt + Mouse wheel")))
for (auto &triangle_selector : m_triangle_selectors) { for (auto &triangle_selector : m_triangle_selectors) {
triangle_selector->seed_fill_unselect_all_triangles(); triangle_selector->seed_fill_unselect_all_triangles();
triangle_selector->request_update_render_data(); triangle_selector->request_update_render_data();
} }
} }
ImGui::Separator(); ImGui::Separator();
if (m_c->object_clipper()->get_position() == 0.f) { if (m_c->object_clipper()->get_position() == 0.f) {
ImGui::AlignTextToFramePadding(); ImGui::AlignTextToFramePadding();
m_imgui->text(m_desc.at("clipping_of_view")); m_imgui->text(m_desc.at("clipping_of_view"));
} }
else { else {
if (m_imgui->button(m_desc.at("reset_direction"))) { if (m_imgui->button(m_desc.at("reset_direction"))) {
wxGetApp().CallAfter([this](){ wxGetApp().CallAfter([this](){
m_c->object_clipper()->set_position(-1., false); m_c->object_clipper()->set_position(-1., false);
}); });
} }
} }
auto clp_dist = float(m_c->object_clipper()->get_position()); auto clp_dist = float(m_c->object_clipper()->get_position());
ImGui::SameLine(sliders_left_width); ImGui::SameLine(sliders_left_width);
ImGui::PushItemWidth(window_width - sliders_left_width - slider_icon_width); ImGui::PushItemWidth(window_width - sliders_left_width - slider_icon_width);
if (m_imgui->slider_float("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f", 1.0f, true, _L("Ctrl + Mouse wheel"))) if (m_imgui->slider_float("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f", 1.0f, true, _L("Ctrl + Mouse wheel")))
m_c->object_clipper()->set_position(clp_dist, true); m_c->object_clipper()->set_position(clp_dist, true);
ImGui::Separator(); ImGui::Separator();
if (m_imgui->button(m_desc.at("remove_all"))) { if (m_imgui->button(m_desc.at("remove_all"))) {
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Reset selection"), UndoRedo::SnapshotType::GizmoAction); Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Reset selection"), UndoRedo::SnapshotType::GizmoAction);
ModelObject *mo = m_c->selection_info()->model_object(); ModelObject *mo = m_c->selection_info()->model_object();
int idx = -1; int idx = -1;
for (ModelVolume *mv : mo->volumes) for (ModelVolume *mv : mo->volumes)
if (mv->is_model_part()) { if (mv->is_model_part()) {
++idx; ++idx;
m_triangle_selectors[idx]->reset(); m_triangle_selectors[idx]->reset();
m_triangle_selectors[idx]->request_update_render_data(); m_triangle_selectors[idx]->request_update_render_data();
} }
update_model_object(); update_model_object();
m_parent.set_as_dirty(); m_parent.set_as_dirty();
} }
m_imgui->end(); m_imgui->end();
} }
void GLGizmoFdmSupports::select_facets_by_angle(float threshold_deg, bool block) void GLGizmoFdmSupports::select_facets_by_angle(float threshold_deg, bool block)
{ {
float threshold = (float(M_PI)/180.f)*threshold_deg; float threshold = (float(M_PI)/180.f)*threshold_deg;
const Selection& selection = m_parent.get_selection(); const Selection& selection = m_parent.get_selection();
const ModelObject* mo = m_c->selection_info()->model_object(); const ModelObject* mo = m_c->selection_info()->model_object();
const ModelInstance* mi = mo->instances[selection.get_instance_idx()]; const ModelInstance* mi = mo->instances[selection.get_instance_idx()];
int mesh_id = -1; int mesh_id = -1;
for (const ModelVolume* mv : mo->volumes) { for (const ModelVolume* mv : mo->volumes) {
if (! mv->is_model_part()) if (! mv->is_model_part())
continue; continue;
++mesh_id; ++mesh_id;
const Transform3d trafo_matrix = mi->get_matrix(true) * mv->get_matrix(true); #if ENABLE_TRANSFORMATIONS_BY_MATRICES
Vec3f down = (trafo_matrix.inverse() * (-Vec3d::UnitZ())).cast<float>().normalized(); const Transform3d trafo_matrix = mi->get_matrix_no_offset() * mv->get_matrix_no_offset();
Vec3f limit = (trafo_matrix.inverse() * Vec3d(std::sin(threshold), 0, -std::cos(threshold))).cast<float>().normalized(); #else
const Transform3d trafo_matrix = mi->get_matrix(true) * mv->get_matrix(true);
float dot_limit = limit.dot(down); #endif // ENABLE_TRANSFORMATIONS_BY_MATRICES
Vec3f down = (trafo_matrix.inverse() * (-Vec3d::UnitZ())).cast<float>().normalized();
// Now calculate dot product of vert_direction and facets' normals. Vec3f limit = (trafo_matrix.inverse() * Vec3d(std::sin(threshold), 0, -std::cos(threshold))).cast<float>().normalized();
int idx = 0;
const indexed_triangle_set &its = mv->mesh().its; float dot_limit = limit.dot(down);
for (const stl_triangle_vertex_indices &face : its.indices) {
if (its_face_normal(its, face).dot(down) > dot_limit) { // Now calculate dot product of vert_direction and facets' normals.
m_triangle_selectors[mesh_id]->set_facet(idx, block ? EnforcerBlockerType::BLOCKER : EnforcerBlockerType::ENFORCER); int idx = 0;
m_triangle_selectors.back()->request_update_render_data(); const indexed_triangle_set &its = mv->mesh().its;
} for (const stl_triangle_vertex_indices &face : its.indices) {
++ idx; if (its_face_normal(its, face).dot(down) > dot_limit) {
} m_triangle_selectors[mesh_id]->set_facet(idx, block ? EnforcerBlockerType::BLOCKER : EnforcerBlockerType::ENFORCER);
} m_triangle_selectors.back()->request_update_render_data();
}
Plater::TakeSnapshot snapshot(wxGetApp().plater(), block ? _L("Block supports by angle") ++ idx;
: _L("Add supports by angle")); }
update_model_object(); }
m_parent.set_as_dirty();
} Plater::TakeSnapshot snapshot(wxGetApp().plater(), block ? _L("Block supports by angle")
: _L("Add supports by angle"));
update_model_object();
m_parent.set_as_dirty();
void GLGizmoFdmSupports::update_model_object() const }
{
bool updated = false;
ModelObject* mo = m_c->selection_info()->model_object();
int idx = -1; void GLGizmoFdmSupports::update_model_object() const
for (ModelVolume* mv : mo->volumes) { {
if (! mv->is_model_part()) bool updated = false;
continue; ModelObject* mo = m_c->selection_info()->model_object();
++idx; int idx = -1;
updated |= mv->supported_facets.set(*m_triangle_selectors[idx].get()); for (ModelVolume* mv : mo->volumes) {
} if (! mv->is_model_part())
continue;
if (updated) { ++idx;
const ModelObjectPtrs& mos = wxGetApp().model().objects; updated |= mv->supported_facets.set(*m_triangle_selectors[idx].get());
wxGetApp().obj_list()->update_info_items(std::find(mos.begin(), mos.end(), mo) - mos.begin()); }
m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); if (updated) {
} const ModelObjectPtrs& mos = wxGetApp().model().objects;
} wxGetApp().obj_list()->update_info_items(std::find(mos.begin(), mos.end(), mo) - mos.begin());
m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
}
void GLGizmoFdmSupports::update_from_model_object() }
{
wxBusyCursor wait;
const ModelObject* mo = m_c->selection_info()->model_object(); void GLGizmoFdmSupports::update_from_model_object()
m_triangle_selectors.clear(); {
wxBusyCursor wait;
int volume_id = -1;
for (const ModelVolume* mv : mo->volumes) { const ModelObject* mo = m_c->selection_info()->model_object();
if (! mv->is_model_part()) m_triangle_selectors.clear();
continue;
int volume_id = -1;
++volume_id; for (const ModelVolume* mv : mo->volumes) {
if (! mv->is_model_part())
// This mesh does not account for the possible Z up SLA offset. continue;
const TriangleMesh* mesh = &mv->mesh();
++volume_id;
m_triangle_selectors.emplace_back(std::make_unique<TriangleSelectorGUI>(*mesh));
// Reset of TriangleSelector is done inside TriangleSelectorGUI's constructor, so we don't need it to perform it again in deserialize(). // This mesh does not account for the possible Z up SLA offset.
m_triangle_selectors.back()->deserialize(mv->supported_facets.get_data(), false); const TriangleMesh* mesh = &mv->mesh();
m_triangle_selectors.back()->request_update_render_data();
} m_triangle_selectors.emplace_back(std::make_unique<TriangleSelectorGUI>(*mesh));
} // Reset of TriangleSelector is done inside TriangleSelectorGUI's constructor, so we don't need it to perform it again in deserialize().
m_triangle_selectors.back()->deserialize(mv->supported_facets.get_data(), false);
m_triangle_selectors.back()->request_update_render_data();
}
PainterGizmoType GLGizmoFdmSupports::get_painter_type() const }
{
return PainterGizmoType::FDM_SUPPORTS;
}
PainterGizmoType GLGizmoFdmSupports::get_painter_type() const
wxString GLGizmoFdmSupports::handle_snapshot_action_name(bool shift_down, GLGizmoPainterBase::Button button_down) const {
{ return PainterGizmoType::FDM_SUPPORTS;
wxString action_name; }
if (shift_down)
action_name = _L("Remove selection"); wxString GLGizmoFdmSupports::handle_snapshot_action_name(bool shift_down, GLGizmoPainterBase::Button button_down) const
else { {
if (button_down == Button::Left) wxString action_name;
action_name = _L("Add supports"); if (shift_down)
else action_name = _L("Remove selection");
action_name = _L("Block supports"); else {
} if (button_down == Button::Left)
return action_name; action_name = _L("Add supports");
} else
action_name = _L("Block supports");
} // namespace Slic3r::GUI }
return action_name;
}
} // namespace Slic3r::GUI

View file

@ -1,475 +1,479 @@
// Include GLGizmoBase.hpp before I18N.hpp as it includes some libigl code, which overrides our localization "L" macro. // Include GLGizmoBase.hpp before I18N.hpp as it includes some libigl code, which overrides our localization "L" macro.
#include "GLGizmoFlatten.hpp" #include "GLGizmoFlatten.hpp"
#include "slic3r/GUI/GLCanvas3D.hpp" #include "slic3r/GUI/GLCanvas3D.hpp"
#if ENABLE_LEGACY_OPENGL_REMOVAL #if ENABLE_LEGACY_OPENGL_REMOVAL
#include "slic3r/GUI/GUI_App.hpp" #include "slic3r/GUI/GUI_App.hpp"
#endif // ENABLE_LEGACY_OPENGL_REMOVAL #endif // ENABLE_LEGACY_OPENGL_REMOVAL
#if ENABLE_GL_SHADERS_ATTRIBUTES #if ENABLE_GL_SHADERS_ATTRIBUTES
#include "slic3r/GUI/Plater.hpp" #include "slic3r/GUI/Plater.hpp"
#endif // ENABLE_GL_SHADERS_ATTRIBUTES #endif // ENABLE_GL_SHADERS_ATTRIBUTES
#include "slic3r/GUI/Gizmos/GLGizmosCommon.hpp" #include "slic3r/GUI/Gizmos/GLGizmosCommon.hpp"
#include "libslic3r/Geometry/ConvexHull.hpp" #include "libslic3r/Geometry/ConvexHull.hpp"
#include "libslic3r/Model.hpp" #include "libslic3r/Model.hpp"
#include <numeric> #include <numeric>
#include <GL/glew.h> #include <GL/glew.h>
namespace Slic3r { namespace Slic3r {
namespace GUI { namespace GUI {
static const Slic3r::ColorRGBA DEFAULT_PLANE_COLOR = { 0.9f, 0.9f, 0.9f, 0.5f }; static const Slic3r::ColorRGBA DEFAULT_PLANE_COLOR = { 0.9f, 0.9f, 0.9f, 0.5f };
static const Slic3r::ColorRGBA DEFAULT_HOVER_PLANE_COLOR = { 0.9f, 0.9f, 0.9f, 0.75f }; static const Slic3r::ColorRGBA DEFAULT_HOVER_PLANE_COLOR = { 0.9f, 0.9f, 0.9f, 0.75f };
GLGizmoFlatten::GLGizmoFlatten(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) GLGizmoFlatten::GLGizmoFlatten(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id)
: GLGizmoBase(parent, icon_filename, sprite_id) : GLGizmoBase(parent, icon_filename, sprite_id)
{} {}
bool GLGizmoFlatten::on_mouse(const wxMouseEvent &mouse_event) bool GLGizmoFlatten::on_mouse(const wxMouseEvent &mouse_event)
{ {
if (mouse_event.Moving()) { if (mouse_event.Moving()) {
// only for sure // only for sure
m_mouse_left_down = false; m_mouse_left_down = false;
return false; return false;
} }
if (mouse_event.LeftDown()) { if (mouse_event.LeftDown()) {
if (m_hover_id != -1) { if (m_hover_id != -1) {
m_mouse_left_down = true; m_mouse_left_down = true;
Selection &selection = m_parent.get_selection(); Selection &selection = m_parent.get_selection();
if (selection.is_single_full_instance()) { if (selection.is_single_full_instance()) {
// Rotate the object so the normal points downward: // Rotate the object so the normal points downward:
selection.flattening_rotate(m_planes[m_hover_id].normal); selection.flattening_rotate(m_planes[m_hover_id].normal);
m_parent.do_rotate(L("Gizmo-Place on Face")); m_parent.do_rotate(L("Gizmo-Place on Face"));
} }
return true; return true;
} }
// fix: prevent restart gizmo when reselect object // fix: prevent restart gizmo when reselect object
// take responsibility for left up // take responsibility for left up
if (m_parent.get_first_hover_volume_idx() >= 0) m_mouse_left_down = true; if (m_parent.get_first_hover_volume_idx() >= 0) m_mouse_left_down = true;
} else if (mouse_event.LeftUp()) { } else if (mouse_event.LeftUp()) {
if (m_mouse_left_down) { if (m_mouse_left_down) {
// responsible for mouse left up after selecting plane // responsible for mouse left up after selecting plane
m_mouse_left_down = false; m_mouse_left_down = false;
return true; return true;
} }
} else if (mouse_event.Leaving()) { } else if (mouse_event.Leaving()) {
m_mouse_left_down = false; m_mouse_left_down = false;
} }
return false; return false;
} }
void GLGizmoFlatten::data_changed() void GLGizmoFlatten::data_changed()
{ {
const Selection & selection = m_parent.get_selection(); const Selection & selection = m_parent.get_selection();
const ModelObject *model_object = nullptr; const ModelObject *model_object = nullptr;
if (selection.is_single_full_instance() || if (selection.is_single_full_instance() ||
selection.is_from_single_object() ) { selection.is_from_single_object() ) {
model_object = selection.get_model()->objects[selection.get_object_idx()]; model_object = selection.get_model()->objects[selection.get_object_idx()];
} }
set_flattening_data(model_object); set_flattening_data(model_object);
} }
bool GLGizmoFlatten::on_init() bool GLGizmoFlatten::on_init()
{ {
m_shortcut_key = WXK_CONTROL_F; m_shortcut_key = WXK_CONTROL_F;
return true; return true;
} }
void GLGizmoFlatten::on_set_state() void GLGizmoFlatten::on_set_state()
{ {
} }
CommonGizmosDataID GLGizmoFlatten::on_get_requirements() const CommonGizmosDataID GLGizmoFlatten::on_get_requirements() const
{ {
return CommonGizmosDataID::SelectionInfo; return CommonGizmosDataID::SelectionInfo;
} }
std::string GLGizmoFlatten::on_get_name() const std::string GLGizmoFlatten::on_get_name() const
{ {
return _u8L("Place on face"); return _u8L("Place on face");
} }
bool GLGizmoFlatten::on_is_activable() const bool GLGizmoFlatten::on_is_activable() const
{ {
// This is assumed in GLCanvas3D::do_rotate, do not change this // This is assumed in GLCanvas3D::do_rotate, do not change this
// without updating that function too. // without updating that function too.
return m_parent.get_selection().is_single_full_instance(); return m_parent.get_selection().is_single_full_instance();
} }
void GLGizmoFlatten::on_render() void GLGizmoFlatten::on_render()
{ {
const Selection& selection = m_parent.get_selection(); const Selection& selection = m_parent.get_selection();
#if ENABLE_LEGACY_OPENGL_REMOVAL #if ENABLE_LEGACY_OPENGL_REMOVAL
GLShaderProgram* shader = wxGetApp().get_shader("flat"); GLShaderProgram* shader = wxGetApp().get_shader("flat");
if (shader == nullptr) if (shader == nullptr)
return; return;
shader->start_using(); shader->start_using();
#endif // ENABLE_LEGACY_OPENGL_REMOVAL #endif // ENABLE_LEGACY_OPENGL_REMOVAL
glsafe(::glClear(GL_DEPTH_BUFFER_BIT)); glsafe(::glClear(GL_DEPTH_BUFFER_BIT));
glsafe(::glEnable(GL_DEPTH_TEST)); glsafe(::glEnable(GL_DEPTH_TEST));
glsafe(::glEnable(GL_BLEND)); glsafe(::glEnable(GL_BLEND));
if (selection.is_single_full_instance()) { if (selection.is_single_full_instance()) {
const Transform3d& m = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(); const Transform3d& m = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix();
#if ENABLE_GL_SHADERS_ATTRIBUTES #if ENABLE_GL_SHADERS_ATTRIBUTES
const Camera& camera = wxGetApp().plater()->get_camera(); const Camera& camera = wxGetApp().plater()->get_camera();
const Transform3d view_model_matrix = camera.get_view_matrix() * const Transform3d view_model_matrix = camera.get_view_matrix() *
Geometry::assemble_transform(selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z() * Vec3d::UnitZ()) * m; Geometry::assemble_transform(selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z() * Vec3d::UnitZ()) * m;
shader->set_uniform("view_model_matrix", view_model_matrix); shader->set_uniform("view_model_matrix", view_model_matrix);
shader->set_uniform("projection_matrix", camera.get_projection_matrix()); shader->set_uniform("projection_matrix", camera.get_projection_matrix());
#else #else
glsafe(::glPushMatrix()); glsafe(::glPushMatrix());
glsafe(::glTranslatef(0.f, 0.f, selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z())); glsafe(::glTranslatef(0.f, 0.f, selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z()));
glsafe(::glMultMatrixd(m.data())); glsafe(::glMultMatrixd(m.data()));
#endif // ENABLE_GL_SHADERS_ATTRIBUTES #endif // ENABLE_GL_SHADERS_ATTRIBUTES
if (this->is_plane_update_necessary()) if (this->is_plane_update_necessary())
update_planes(); update_planes();
for (int i = 0; i < (int)m_planes.size(); ++i) { for (int i = 0; i < (int)m_planes.size(); ++i) {
#if ENABLE_LEGACY_OPENGL_REMOVAL #if ENABLE_LEGACY_OPENGL_REMOVAL
m_planes[i].vbo.set_color(i == m_hover_id ? DEFAULT_HOVER_PLANE_COLOR : DEFAULT_PLANE_COLOR); m_planes[i].vbo.set_color(i == m_hover_id ? DEFAULT_HOVER_PLANE_COLOR : DEFAULT_PLANE_COLOR);
m_planes[i].vbo.render(); m_planes[i].vbo.render();
#else #else
glsafe(::glColor4fv(i == m_hover_id ? DEFAULT_HOVER_PLANE_COLOR.data() : DEFAULT_PLANE_COLOR.data())); glsafe(::glColor4fv(i == m_hover_id ? DEFAULT_HOVER_PLANE_COLOR.data() : DEFAULT_PLANE_COLOR.data()));
if (m_planes[i].vbo.has_VBOs()) if (m_planes[i].vbo.has_VBOs())
m_planes[i].vbo.render(); m_planes[i].vbo.render();
#endif // ENABLE_LEGACY_OPENGL_REMOVAL #endif // ENABLE_LEGACY_OPENGL_REMOVAL
} }
#if !ENABLE_GL_SHADERS_ATTRIBUTES #if !ENABLE_GL_SHADERS_ATTRIBUTES
glsafe(::glPopMatrix()); glsafe(::glPopMatrix());
#endif // !ENABLE_GL_SHADERS_ATTRIBUTES #endif // !ENABLE_GL_SHADERS_ATTRIBUTES
} }
glsafe(::glEnable(GL_CULL_FACE)); glsafe(::glEnable(GL_CULL_FACE));
glsafe(::glDisable(GL_BLEND)); glsafe(::glDisable(GL_BLEND));
#if ENABLE_LEGACY_OPENGL_REMOVAL #if ENABLE_LEGACY_OPENGL_REMOVAL
shader->stop_using(); shader->stop_using();
#endif // ENABLE_LEGACY_OPENGL_REMOVAL #endif // ENABLE_LEGACY_OPENGL_REMOVAL
} }
void GLGizmoFlatten::on_render_for_picking() void GLGizmoFlatten::on_render_for_picking()
{ {
const Selection& selection = m_parent.get_selection(); const Selection& selection = m_parent.get_selection();
#if ENABLE_LEGACY_OPENGL_REMOVAL #if ENABLE_LEGACY_OPENGL_REMOVAL
GLShaderProgram* shader = wxGetApp().get_shader("flat"); GLShaderProgram* shader = wxGetApp().get_shader("flat");
if (shader == nullptr) if (shader == nullptr)
return; return;
shader->start_using(); shader->start_using();
#endif // ENABLE_LEGACY_OPENGL_REMOVAL #endif // ENABLE_LEGACY_OPENGL_REMOVAL
glsafe(::glDisable(GL_DEPTH_TEST)); glsafe(::glDisable(GL_DEPTH_TEST));
glsafe(::glDisable(GL_BLEND)); glsafe(::glDisable(GL_BLEND));
if (selection.is_single_full_instance() && !wxGetKeyState(WXK_CONTROL)) { if (selection.is_single_full_instance() && !wxGetKeyState(WXK_CONTROL)) {
const Transform3d& m = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(); const Transform3d& m = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix();
#if ENABLE_GL_SHADERS_ATTRIBUTES #if ENABLE_GL_SHADERS_ATTRIBUTES
const Camera& camera = wxGetApp().plater()->get_camera(); const Camera& camera = wxGetApp().plater()->get_camera();
const Transform3d view_model_matrix = camera.get_view_matrix() * const Transform3d view_model_matrix = camera.get_view_matrix() *
Geometry::assemble_transform(selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z() * Vec3d::UnitZ()) * m; Geometry::assemble_transform(selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z() * Vec3d::UnitZ()) * m;
shader->set_uniform("view_model_matrix", view_model_matrix); shader->set_uniform("view_model_matrix", view_model_matrix);
shader->set_uniform("projection_matrix", camera.get_projection_matrix()); shader->set_uniform("projection_matrix", camera.get_projection_matrix());
#else #else
glsafe(::glPushMatrix()); glsafe(::glPushMatrix());
glsafe(::glTranslatef(0.f, 0.f, selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z())); glsafe(::glTranslatef(0.f, 0.f, selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z()));
glsafe(::glMultMatrixd(m.data())); glsafe(::glMultMatrixd(m.data()));
#endif // ENABLE_GL_SHADERS_ATTRIBUTES #endif // ENABLE_GL_SHADERS_ATTRIBUTES
if (this->is_plane_update_necessary()) if (this->is_plane_update_necessary())
update_planes(); update_planes();
for (int i = 0; i < (int)m_planes.size(); ++i) { for (int i = 0; i < (int)m_planes.size(); ++i) {
#if ENABLE_LEGACY_OPENGL_REMOVAL #if ENABLE_LEGACY_OPENGL_REMOVAL
m_planes[i].vbo.set_color(picking_color_component(i)); m_planes[i].vbo.set_color(picking_color_component(i));
#else #else
glsafe(::glColor4fv(picking_color_component(i).data())); glsafe(::glColor4fv(picking_color_component(i).data()));
#endif // ENABLE_LEGACY_OPENGL_REMOVAL #endif // ENABLE_LEGACY_OPENGL_REMOVAL
m_planes[i].vbo.render(); m_planes[i].vbo.render();
} }
#if !ENABLE_GL_SHADERS_ATTRIBUTES #if !ENABLE_GL_SHADERS_ATTRIBUTES
glsafe(::glPopMatrix()); glsafe(::glPopMatrix());
#endif // !ENABLE_GL_SHADERS_ATTRIBUTES #endif // !ENABLE_GL_SHADERS_ATTRIBUTES
} }
glsafe(::glEnable(GL_CULL_FACE)); glsafe(::glEnable(GL_CULL_FACE));
#if ENABLE_LEGACY_OPENGL_REMOVAL #if ENABLE_LEGACY_OPENGL_REMOVAL
shader->stop_using(); shader->stop_using();
#endif // ENABLE_LEGACY_OPENGL_REMOVAL #endif // ENABLE_LEGACY_OPENGL_REMOVAL
} }
void GLGizmoFlatten::set_flattening_data(const ModelObject* model_object) void GLGizmoFlatten::set_flattening_data(const ModelObject* model_object)
{ {
if (model_object != m_old_model_object) { if (model_object != m_old_model_object) {
m_planes.clear(); m_planes.clear();
m_planes_valid = false; m_planes_valid = false;
} }
} }
void GLGizmoFlatten::update_planes() void GLGizmoFlatten::update_planes()
{ {
const ModelObject* mo = m_c->selection_info()->model_object(); const ModelObject* mo = m_c->selection_info()->model_object();
TriangleMesh ch; TriangleMesh ch;
for (const ModelVolume* vol : mo->volumes) { for (const ModelVolume* vol : mo->volumes) {
if (vol->type() != ModelVolumeType::MODEL_PART) if (vol->type() != ModelVolumeType::MODEL_PART)
continue; continue;
TriangleMesh vol_ch = vol->get_convex_hull(); TriangleMesh vol_ch = vol->get_convex_hull();
vol_ch.transform(vol->get_matrix()); vol_ch.transform(vol->get_matrix());
ch.merge(vol_ch); ch.merge(vol_ch);
} }
ch = ch.convex_hull_3d(); ch = ch.convex_hull_3d();
m_planes.clear(); m_planes.clear();
const Transform3d& inst_matrix = mo->instances.front()->get_matrix(true); #if ENABLE_TRANSFORMATIONS_BY_MATRICES
const Transform3d inst_matrix = mo->instances.front()->get_matrix_no_offset();
// Following constants are used for discarding too small polygons. #else
const float minimal_area = 5.f; // in square mm (world coordinates) const Transform3d& inst_matrix = mo->instances.front()->get_matrix(true);
const float minimal_side = 1.f; // mm #endif // ENABLE_TRANSFORMATIONS_BY_MATRICES
// Now we'll go through all the facets and append Points of facets sharing the same normal. // Following constants are used for discarding too small polygons.
// This part is still performed in mesh coordinate system. const float minimal_area = 5.f; // in square mm (world coordinates)
const int num_of_facets = ch.facets_count(); const float minimal_side = 1.f; // mm
const std::vector<Vec3f> face_normals = its_face_normals(ch.its);
const std::vector<Vec3i> face_neighbors = its_face_neighbors(ch.its); // Now we'll go through all the facets and append Points of facets sharing the same normal.
std::vector<int> facet_queue(num_of_facets, 0); // This part is still performed in mesh coordinate system.
std::vector<bool> facet_visited(num_of_facets, false); const int num_of_facets = ch.facets_count();
int facet_queue_cnt = 0; const std::vector<Vec3f> face_normals = its_face_normals(ch.its);
const stl_normal* normal_ptr = nullptr; const std::vector<Vec3i> face_neighbors = its_face_neighbors(ch.its);
int facet_idx = 0; std::vector<int> facet_queue(num_of_facets, 0);
while (1) { std::vector<bool> facet_visited(num_of_facets, false);
// Find next unvisited triangle: int facet_queue_cnt = 0;
for (; facet_idx < num_of_facets; ++ facet_idx) const stl_normal* normal_ptr = nullptr;
if (!facet_visited[facet_idx]) { int facet_idx = 0;
facet_queue[facet_queue_cnt ++] = facet_idx; while (1) {
facet_visited[facet_idx] = true; // Find next unvisited triangle:
normal_ptr = &face_normals[facet_idx]; for (; facet_idx < num_of_facets; ++ facet_idx)
m_planes.emplace_back(); if (!facet_visited[facet_idx]) {
break; facet_queue[facet_queue_cnt ++] = facet_idx;
} facet_visited[facet_idx] = true;
if (facet_idx == num_of_facets) normal_ptr = &face_normals[facet_idx];
break; // Everything was visited already m_planes.emplace_back();
break;
while (facet_queue_cnt > 0) { }
int facet_idx = facet_queue[-- facet_queue_cnt]; if (facet_idx == num_of_facets)
const stl_normal& this_normal = face_normals[facet_idx]; break; // Everything was visited already
if (std::abs(this_normal(0) - (*normal_ptr)(0)) < 0.001 && std::abs(this_normal(1) - (*normal_ptr)(1)) < 0.001 && std::abs(this_normal(2) - (*normal_ptr)(2)) < 0.001) {
const Vec3i face = ch.its.indices[facet_idx]; while (facet_queue_cnt > 0) {
for (int j=0; j<3; ++j) int facet_idx = facet_queue[-- facet_queue_cnt];
m_planes.back().vertices.emplace_back(ch.its.vertices[face[j]].cast<double>()); const stl_normal& this_normal = face_normals[facet_idx];
if (std::abs(this_normal(0) - (*normal_ptr)(0)) < 0.001 && std::abs(this_normal(1) - (*normal_ptr)(1)) < 0.001 && std::abs(this_normal(2) - (*normal_ptr)(2)) < 0.001) {
facet_visited[facet_idx] = true; const Vec3i face = ch.its.indices[facet_idx];
for (int j = 0; j < 3; ++ j) for (int j=0; j<3; ++j)
if (int neighbor_idx = face_neighbors[facet_idx][j]; neighbor_idx >= 0 && ! facet_visited[neighbor_idx]) m_planes.back().vertices.emplace_back(ch.its.vertices[face[j]].cast<double>());
facet_queue[facet_queue_cnt ++] = neighbor_idx;
} facet_visited[facet_idx] = true;
} for (int j = 0; j < 3; ++ j)
m_planes.back().normal = normal_ptr->cast<double>(); if (int neighbor_idx = face_neighbors[facet_idx][j]; neighbor_idx >= 0 && ! facet_visited[neighbor_idx])
facet_queue[facet_queue_cnt ++] = neighbor_idx;
Pointf3s& verts = m_planes.back().vertices; }
// Now we'll transform all the points into world coordinates, so that the areas, angles and distances }
// make real sense. m_planes.back().normal = normal_ptr->cast<double>();
verts = transform(verts, inst_matrix);
Pointf3s& verts = m_planes.back().vertices;
// if this is a just a very small triangle, remove it to speed up further calculations (it would be rejected later anyway): // Now we'll transform all the points into world coordinates, so that the areas, angles and distances
if (verts.size() == 3 && // make real sense.
((verts[0] - verts[1]).norm() < minimal_side verts = transform(verts, inst_matrix);
|| (verts[0] - verts[2]).norm() < minimal_side
|| (verts[1] - verts[2]).norm() < minimal_side)) // if this is a just a very small triangle, remove it to speed up further calculations (it would be rejected later anyway):
m_planes.pop_back(); if (verts.size() == 3 &&
} ((verts[0] - verts[1]).norm() < minimal_side
|| (verts[0] - verts[2]).norm() < minimal_side
// Let's prepare transformation of the normal vector from mesh to instance coordinates. || (verts[1] - verts[2]).norm() < minimal_side))
Geometry::Transformation t(inst_matrix); m_planes.pop_back();
Vec3d scaling = t.get_scaling_factor(); }
t.set_scaling_factor(Vec3d(1./scaling(0), 1./scaling(1), 1./scaling(2)));
// Let's prepare transformation of the normal vector from mesh to instance coordinates.
// Now we'll go through all the polygons, transform the points into xy plane to process them: Geometry::Transformation t(inst_matrix);
for (unsigned int polygon_id=0; polygon_id < m_planes.size(); ++polygon_id) { Vec3d scaling = t.get_scaling_factor();
Pointf3s& polygon = m_planes[polygon_id].vertices; t.set_scaling_factor(Vec3d(1./scaling(0), 1./scaling(1), 1./scaling(2)));
const Vec3d& normal = m_planes[polygon_id].normal;
// Now we'll go through all the polygons, transform the points into xy plane to process them:
// transform the normal according to the instance matrix: for (unsigned int polygon_id=0; polygon_id < m_planes.size(); ++polygon_id) {
Vec3d normal_transformed = t.get_matrix() * normal; Pointf3s& polygon = m_planes[polygon_id].vertices;
const Vec3d& normal = m_planes[polygon_id].normal;
// We are going to rotate about z and y to flatten the plane
Eigen::Quaterniond q; // transform the normal according to the instance matrix:
Transform3d m = Transform3d::Identity(); Vec3d normal_transformed = t.get_matrix() * normal;
m.matrix().block(0, 0, 3, 3) = q.setFromTwoVectors(normal_transformed, Vec3d::UnitZ()).toRotationMatrix();
polygon = transform(polygon, m); // We are going to rotate about z and y to flatten the plane
Eigen::Quaterniond q;
// Now to remove the inner points. We'll misuse Geometry::convex_hull for that, but since Transform3d m = Transform3d::Identity();
// it works in fixed point representation, we will rescale the polygon to avoid overflows. m.matrix().block(0, 0, 3, 3) = q.setFromTwoVectors(normal_transformed, Vec3d::UnitZ()).toRotationMatrix();
// And yes, it is a nasty thing to do. Whoever has time is free to refactor. polygon = transform(polygon, m);
Vec3d bb_size = BoundingBoxf3(polygon).size();
float sf = std::min(1./bb_size(0), 1./bb_size(1)); // Now to remove the inner points. We'll misuse Geometry::convex_hull for that, but since
Transform3d tr = Geometry::assemble_transform(Vec3d::Zero(), Vec3d::Zero(), Vec3d(sf, sf, 1.f)); // it works in fixed point representation, we will rescale the polygon to avoid overflows.
polygon = transform(polygon, tr); // And yes, it is a nasty thing to do. Whoever has time is free to refactor.
polygon = Slic3r::Geometry::convex_hull(polygon); Vec3d bb_size = BoundingBoxf3(polygon).size();
polygon = transform(polygon, tr.inverse()); float sf = std::min(1./bb_size(0), 1./bb_size(1));
Transform3d tr = Geometry::assemble_transform(Vec3d::Zero(), Vec3d::Zero(), Vec3d(sf, sf, 1.f));
// Calculate area of the polygons and discard ones that are too small polygon = transform(polygon, tr);
float& area = m_planes[polygon_id].area; polygon = Slic3r::Geometry::convex_hull(polygon);
area = 0.f; polygon = transform(polygon, tr.inverse());
for (unsigned int i = 0; i < polygon.size(); i++) // Shoelace formula
area += polygon[i](0)*polygon[i + 1 < polygon.size() ? i + 1 : 0](1) - polygon[i + 1 < polygon.size() ? i + 1 : 0](0)*polygon[i](1); // Calculate area of the polygons and discard ones that are too small
area = 0.5f * std::abs(area); float& area = m_planes[polygon_id].area;
area = 0.f;
bool discard = false; for (unsigned int i = 0; i < polygon.size(); i++) // Shoelace formula
if (area < minimal_area) area += polygon[i](0)*polygon[i + 1 < polygon.size() ? i + 1 : 0](1) - polygon[i + 1 < polygon.size() ? i + 1 : 0](0)*polygon[i](1);
discard = true; area = 0.5f * std::abs(area);
else {
// We also check the inner angles and discard polygons with angles smaller than the following threshold bool discard = false;
const double angle_threshold = ::cos(10.0 * (double)PI / 180.0); if (area < minimal_area)
discard = true;
for (unsigned int i = 0; i < polygon.size(); ++i) { else {
const Vec3d& prec = polygon[(i == 0) ? polygon.size() - 1 : i - 1]; // We also check the inner angles and discard polygons with angles smaller than the following threshold
const Vec3d& curr = polygon[i]; const double angle_threshold = ::cos(10.0 * (double)PI / 180.0);
const Vec3d& next = polygon[(i == polygon.size() - 1) ? 0 : i + 1];
for (unsigned int i = 0; i < polygon.size(); ++i) {
if ((prec - curr).normalized().dot((next - curr).normalized()) > angle_threshold) { const Vec3d& prec = polygon[(i == 0) ? polygon.size() - 1 : i - 1];
discard = true; const Vec3d& curr = polygon[i];
break; const Vec3d& next = polygon[(i == polygon.size() - 1) ? 0 : i + 1];
}
} if ((prec - curr).normalized().dot((next - curr).normalized()) > angle_threshold) {
} discard = true;
break;
if (discard) { }
m_planes[polygon_id--] = std::move(m_planes.back()); }
m_planes.pop_back(); }
continue;
} if (discard) {
m_planes[polygon_id--] = std::move(m_planes.back());
// We will shrink the polygon a little bit so it does not touch the object edges: m_planes.pop_back();
Vec3d centroid = std::accumulate(polygon.begin(), polygon.end(), Vec3d(0.0, 0.0, 0.0)); continue;
centroid /= (double)polygon.size(); }
for (auto& vertex : polygon)
vertex = 0.9f*vertex + 0.1f*centroid; // We will shrink the polygon a little bit so it does not touch the object edges:
Vec3d centroid = std::accumulate(polygon.begin(), polygon.end(), Vec3d(0.0, 0.0, 0.0));
// Polygon is now simple and convex, we'll round the corners to make them look nicer. centroid /= (double)polygon.size();
// The algorithm takes a vertex, calculates middles of respective sides and moves the vertex for (auto& vertex : polygon)
// towards their average (controlled by 'aggressivity'). This is repeated k times. vertex = 0.9f*vertex + 0.1f*centroid;
// In next iterations, the neighbours are not always taken at the middle (to increase the
// rounding effect at the corners, where we need it most). // Polygon is now simple and convex, we'll round the corners to make them look nicer.
const unsigned int k = 10; // number of iterations // The algorithm takes a vertex, calculates middles of respective sides and moves the vertex
const float aggressivity = 0.2f; // agressivity // towards their average (controlled by 'aggressivity'). This is repeated k times.
const unsigned int N = polygon.size(); // In next iterations, the neighbours are not always taken at the middle (to increase the
std::vector<std::pair<unsigned int, unsigned int>> neighbours; // rounding effect at the corners, where we need it most).
if (k != 0) { const unsigned int k = 10; // number of iterations
Pointf3s points_out(2*k*N); // vector long enough to store the future vertices const float aggressivity = 0.2f; // agressivity
for (unsigned int j=0; j<N; ++j) { const unsigned int N = polygon.size();
points_out[j*2*k] = polygon[j]; std::vector<std::pair<unsigned int, unsigned int>> neighbours;
neighbours.push_back(std::make_pair((int)(j*2*k-k) < 0 ? (N-1)*2*k+k : j*2*k-k, j*2*k+k)); if (k != 0) {
} Pointf3s points_out(2*k*N); // vector long enough to store the future vertices
for (unsigned int j=0; j<N; ++j) {
for (unsigned int i=0; i<k; ++i) { points_out[j*2*k] = polygon[j];
// Calculate middle of each edge so that neighbours points to something useful: neighbours.push_back(std::make_pair((int)(j*2*k-k) < 0 ? (N-1)*2*k+k : j*2*k-k, j*2*k+k));
for (unsigned int j=0; j<N; ++j) }
if (i==0)
points_out[j*2*k+k] = 0.5f * (points_out[j*2*k] + points_out[j==N-1 ? 0 : (j+1)*2*k]); for (unsigned int i=0; i<k; ++i) {
else { // Calculate middle of each edge so that neighbours points to something useful:
float r = 0.2+0.3/(k-1)*i; // the neighbours are not always taken in the middle for (unsigned int j=0; j<N; ++j)
points_out[neighbours[j].first] = r*points_out[j*2*k] + (1-r) * points_out[neighbours[j].first-1]; if (i==0)
points_out[neighbours[j].second] = r*points_out[j*2*k] + (1-r) * points_out[neighbours[j].second+1]; points_out[j*2*k+k] = 0.5f * (points_out[j*2*k] + points_out[j==N-1 ? 0 : (j+1)*2*k]);
} else {
// Now we have a triangle and valid neighbours, we can do an iteration: float r = 0.2+0.3/(k-1)*i; // the neighbours are not always taken in the middle
for (unsigned int j=0; j<N; ++j) points_out[neighbours[j].first] = r*points_out[j*2*k] + (1-r) * points_out[neighbours[j].first-1];
points_out[2*k*j] = (1-aggressivity) * points_out[2*k*j] + points_out[neighbours[j].second] = r*points_out[j*2*k] + (1-r) * points_out[neighbours[j].second+1];
aggressivity*0.5f*(points_out[neighbours[j].first] + points_out[neighbours[j].second]); }
// Now we have a triangle and valid neighbours, we can do an iteration:
for (auto& n : neighbours) { for (unsigned int j=0; j<N; ++j)
++n.first; points_out[2*k*j] = (1-aggressivity) * points_out[2*k*j] +
--n.second; aggressivity*0.5f*(points_out[neighbours[j].first] + points_out[neighbours[j].second]);
}
} for (auto& n : neighbours) {
polygon = points_out; // replace the coarse polygon with the smooth one that we just created ++n.first;
} --n.second;
}
}
// Raise a bit above the object surface to avoid flickering: polygon = points_out; // replace the coarse polygon with the smooth one that we just created
for (auto& b : polygon) }
b(2) += 0.1f;
// Transform back to 3D (and also back to mesh coordinates) // Raise a bit above the object surface to avoid flickering:
polygon = transform(polygon, inst_matrix.inverse() * m.inverse()); for (auto& b : polygon)
} b(2) += 0.1f;
// We'll sort the planes by area and only keep the 254 largest ones (because of the picking pass limitations): // Transform back to 3D (and also back to mesh coordinates)
std::sort(m_planes.rbegin(), m_planes.rend(), [](const PlaneData& a, const PlaneData& b) { return a.area < b.area; }); polygon = transform(polygon, inst_matrix.inverse() * m.inverse());
m_planes.resize(std::min((int)m_planes.size(), 254)); }
// Planes are finished - let's save what we calculated it from: // We'll sort the planes by area and only keep the 254 largest ones (because of the picking pass limitations):
m_volumes_matrices.clear(); std::sort(m_planes.rbegin(), m_planes.rend(), [](const PlaneData& a, const PlaneData& b) { return a.area < b.area; });
m_volumes_types.clear(); m_planes.resize(std::min((int)m_planes.size(), 254));
for (const ModelVolume* vol : mo->volumes) {
m_volumes_matrices.push_back(vol->get_matrix()); // Planes are finished - let's save what we calculated it from:
m_volumes_types.push_back(vol->type()); m_volumes_matrices.clear();
} m_volumes_types.clear();
m_first_instance_scale = mo->instances.front()->get_scaling_factor(); for (const ModelVolume* vol : mo->volumes) {
m_first_instance_mirror = mo->instances.front()->get_mirror(); m_volumes_matrices.push_back(vol->get_matrix());
m_old_model_object = mo; m_volumes_types.push_back(vol->type());
}
// And finally create respective VBOs. The polygon is convex with m_first_instance_scale = mo->instances.front()->get_scaling_factor();
// the vertices in order, so triangulation is trivial. m_first_instance_mirror = mo->instances.front()->get_mirror();
for (auto& plane : m_planes) { m_old_model_object = mo;
#if ENABLE_LEGACY_OPENGL_REMOVAL
GLModel::Geometry init_data; // And finally create respective VBOs. The polygon is convex with
init_data.format = { GLModel::Geometry::EPrimitiveType::TriangleFan, GLModel::Geometry::EVertexLayout::P3N3 }; // the vertices in order, so triangulation is trivial.
init_data.reserve_vertices(plane.vertices.size()); for (auto& plane : m_planes) {
init_data.reserve_indices(plane.vertices.size()); #if ENABLE_LEGACY_OPENGL_REMOVAL
// vertices + indices GLModel::Geometry init_data;
for (size_t i = 0; i < plane.vertices.size(); ++i) { init_data.format = { GLModel::Geometry::EPrimitiveType::TriangleFan, GLModel::Geometry::EVertexLayout::P3N3 };
init_data.add_vertex((Vec3f)plane.vertices[i].cast<float>(), (Vec3f)plane.normal.cast<float>()); init_data.reserve_vertices(plane.vertices.size());
init_data.add_index((unsigned int)i); init_data.reserve_indices(plane.vertices.size());
} // vertices + indices
plane.vbo.init_from(std::move(init_data)); for (size_t i = 0; i < plane.vertices.size(); ++i) {
#else init_data.add_vertex((Vec3f)plane.vertices[i].cast<float>(), (Vec3f)plane.normal.cast<float>());
plane.vbo.reserve(plane.vertices.size()); init_data.add_index((unsigned int)i);
for (const auto& vert : plane.vertices) }
plane.vbo.push_geometry(vert, plane.normal); plane.vbo.init_from(std::move(init_data));
for (size_t i=1; i<plane.vertices.size()-1; ++i) #else
plane.vbo.push_triangle(0, i, i+1); // triangle fan plane.vbo.reserve(plane.vertices.size());
plane.vbo.finalize_geometry(true); for (const auto& vert : plane.vertices)
#endif // ENABLE_LEGACY_OPENGL_REMOVAL plane.vbo.push_geometry(vert, plane.normal);
// FIXME: vertices should really be local, they need not for (size_t i=1; i<plane.vertices.size()-1; ++i)
// persist now when we use VBOs plane.vbo.push_triangle(0, i, i+1); // triangle fan
plane.vertices.clear(); plane.vbo.finalize_geometry(true);
plane.vertices.shrink_to_fit(); #endif // ENABLE_LEGACY_OPENGL_REMOVAL
} // FIXME: vertices should really be local, they need not
// persist now when we use VBOs
m_planes_valid = true; plane.vertices.clear();
} plane.vertices.shrink_to_fit();
}
bool GLGizmoFlatten::is_plane_update_necessary() const m_planes_valid = true;
{ }
const ModelObject* mo = m_c->selection_info()->model_object();
if (m_state != On || ! mo || mo->instances.empty())
return false; bool GLGizmoFlatten::is_plane_update_necessary() const
{
if (! m_planes_valid || mo != m_old_model_object const ModelObject* mo = m_c->selection_info()->model_object();
|| mo->volumes.size() != m_volumes_matrices.size()) if (m_state != On || ! mo || mo->instances.empty())
return true; return false;
// We want to recalculate when the scale changes - some planes could (dis)appear. if (! m_planes_valid || mo != m_old_model_object
if (! mo->instances.front()->get_scaling_factor().isApprox(m_first_instance_scale) || mo->volumes.size() != m_volumes_matrices.size())
|| ! mo->instances.front()->get_mirror().isApprox(m_first_instance_mirror)) return true;
return true;
// We want to recalculate when the scale changes - some planes could (dis)appear.
for (unsigned int i=0; i < mo->volumes.size(); ++i) if (! mo->instances.front()->get_scaling_factor().isApprox(m_first_instance_scale)
if (! mo->volumes[i]->get_matrix().isApprox(m_volumes_matrices[i]) || ! mo->instances.front()->get_mirror().isApprox(m_first_instance_mirror))
|| mo->volumes[i]->type() != m_volumes_types[i]) return true;
return true;
for (unsigned int i=0; i < mo->volumes.size(); ++i)
return false; if (! mo->volumes[i]->get_matrix().isApprox(m_volumes_matrices[i])
} || mo->volumes[i]->type() != m_volumes_types[i])
return true;
} // namespace GUI
} // namespace Slic3r return false;
}
} // namespace GUI
} // namespace Slic3r

File diff suppressed because it is too large Load diff

View file

@ -90,32 +90,32 @@ bool GLGizmoMove3D::on_is_activable() const
void GLGizmoMove3D::on_start_dragging() void GLGizmoMove3D::on_start_dragging()
{ {
if (m_hover_id != -1) { assert(m_hover_id != -1);
m_displacement = Vec3d::Zero();
m_displacement = Vec3d::Zero();
#if ENABLE_WORLD_COORDINATE #if ENABLE_WORLD_COORDINATE
const Selection& selection = m_parent.get_selection(); const Selection& selection = m_parent.get_selection();
const ECoordinatesType coordinates_type = wxGetApp().obj_manipul()->get_coordinates_type(); const ECoordinatesType coordinates_type = wxGetApp().obj_manipul()->get_coordinates_type();
if (coordinates_type == ECoordinatesType::World) if (coordinates_type == ECoordinatesType::World)
m_starting_drag_position = m_center + m_grabbers[m_hover_id].center; m_starting_drag_position = m_center + m_grabbers[m_hover_id].center;
else if (coordinates_type == ECoordinatesType::Local && selection.is_single_volume_or_modifier()) { else if (coordinates_type == ECoordinatesType::Local && selection.is_single_volume_or_modifier()) {
const GLVolume& v = *selection.get_volume(*selection.get_volume_idxs().begin()); const GLVolume& v = *selection.get_volume(*selection.get_volume_idxs().begin());
m_starting_drag_position = m_center + Geometry::assemble_transform(Vec3d::Zero(), v.get_instance_rotation()) * Geometry::assemble_transform(Vec3d::Zero(), v.get_volume_rotation()) * m_grabbers[m_hover_id].center; m_starting_drag_position = m_center + Geometry::assemble_transform(Vec3d::Zero(), v.get_instance_rotation()) * Geometry::assemble_transform(Vec3d::Zero(), v.get_volume_rotation()) * m_grabbers[m_hover_id].center;
}
else {
const GLVolume& v = *selection.get_volume(*selection.get_volume_idxs().begin());
m_starting_drag_position = m_center + Geometry::assemble_transform(Vec3d::Zero(), v.get_instance_rotation()) * m_grabbers[m_hover_id].center;
}
m_starting_box_center = m_center;
m_starting_box_bottom_center = m_center;
m_starting_box_bottom_center.z() = m_bounding_box.min.z();
#else
const BoundingBoxf3& box = m_parent.get_selection().get_bounding_box();
m_starting_drag_position = m_grabbers[m_hover_id].center;
m_starting_box_center = box.center();
m_starting_box_bottom_center = box.center();
m_starting_box_bottom_center.z() = box.min.z();
#endif // ENABLE_WORLD_COORDINATE
} }
else {
const GLVolume& v = *selection.get_volume(*selection.get_volume_idxs().begin());
m_starting_drag_position = m_center + Geometry::assemble_transform(Vec3d::Zero(), v.get_instance_rotation()) * m_grabbers[m_hover_id].center;
}
m_starting_box_center = m_center;
m_starting_box_bottom_center = m_center;
m_starting_box_bottom_center.z() = m_bounding_box.min.z();
#else
const BoundingBoxf3& box = m_parent.get_selection().get_bounding_box();
m_starting_drag_position = m_grabbers[m_hover_id].center;
m_starting_box_center = box.center();
m_starting_box_bottom_center = box.center();
m_starting_box_bottom_center.z() = box.min.z();
#endif // ENABLE_WORLD_COORDINATE
} }
void GLGizmoMove3D::on_stop_dragging() void GLGizmoMove3D::on_stop_dragging()
@ -134,7 +134,11 @@ void GLGizmoMove3D::on_dragging(const UpdateData& data)
m_displacement.z() = calc_projection(data); m_displacement.z() = calc_projection(data);
Selection &selection = m_parent.get_selection(); Selection &selection = m_parent.get_selection();
#if ENABLE_WORLD_COORDINATE
selection.translate(m_displacement, wxGetApp().obj_manipul()->get_coordinates_type());
#else
selection.translate(m_displacement); selection.translate(m_displacement);
#endif // ENABLE_WORLD_COORDINATE
} }
void GLGizmoMove3D::on_render() void GLGizmoMove3D::on_render()
@ -148,9 +152,18 @@ void GLGizmoMove3D::on_render()
glsafe(::glEnable(GL_DEPTH_TEST)); glsafe(::glEnable(GL_DEPTH_TEST));
#if ENABLE_WORLD_COORDINATE #if ENABLE_WORLD_COORDINATE
#if !ENABLE_GL_SHADERS_ATTRIBUTES
glsafe(::glPushMatrix()); glsafe(::glPushMatrix());
#endif // !ENABLE_GL_SHADERS_ATTRIBUTES
calc_selection_box_and_center(); calc_selection_box_and_center();
#if ENABLE_GL_SHADERS_ATTRIBUTES
const Transform3d base_matrix = local_transform(m_parent.get_selection());
for (int i = 0; i < 3; ++i) {
m_grabbers[i].matrix = base_matrix;
}
#else
transform_to_local(m_parent.get_selection()); transform_to_local(m_parent.get_selection());
#endif // ENABLE_GL_SHADERS_ATTRIBUTES
const Vec3d zero = Vec3d::Zero(); const Vec3d zero = Vec3d::Zero();
const Vec3d half_box_size = 0.5 * m_bounding_box.size(); const Vec3d half_box_size = 0.5 * m_bounding_box.size();
@ -236,7 +249,7 @@ void GLGizmoMove3D::on_render()
#if ENABLE_GL_SHADERS_ATTRIBUTES #if ENABLE_GL_SHADERS_ATTRIBUTES
const Camera& camera = wxGetApp().plater()->get_camera(); const Camera& camera = wxGetApp().plater()->get_camera();
shader->set_uniform("view_model_matrix", camera.get_view_matrix()); shader->set_uniform("view_model_matrix", camera.get_view_matrix() * base_matrix);
shader->set_uniform("projection_matrix", camera.get_projection_matrix()); shader->set_uniform("projection_matrix", camera.get_projection_matrix());
#endif // ENABLE_GL_SHADERS_ATTRIBUTES #endif // ENABLE_GL_SHADERS_ATTRIBUTES
@ -270,8 +283,12 @@ void GLGizmoMove3D::on_render()
#if !ENABLE_GIZMO_GRABBER_REFACTOR #if !ENABLE_GIZMO_GRABBER_REFACTOR
for (unsigned int i = 0; i < 3; ++i) { for (unsigned int i = 0; i < 3; ++i) {
if (m_grabbers[i].enabled) if (m_grabbers[i].enabled)
#if ENABLE_GL_SHADERS_ATTRIBUTES
render_grabber_extension((Axis)i, base_matrix, m_bounding_box, false);
#else
render_grabber_extension((Axis)i, m_bounding_box, false); render_grabber_extension((Axis)i, m_bounding_box, false);
} #endif // ENABLE_GL_SHADERS_ATTRIBUTES
}
#endif // !ENABLE_GIZMO_GRABBER_REFACTOR #endif // !ENABLE_GIZMO_GRABBER_REFACTOR
#else #else
render_grabbers(box); render_grabbers(box);
@ -292,7 +309,7 @@ void GLGizmoMove3D::on_render()
#if ENABLE_GL_SHADERS_ATTRIBUTES #if ENABLE_GL_SHADERS_ATTRIBUTES
const Camera& camera = wxGetApp().plater()->get_camera(); const Camera& camera = wxGetApp().plater()->get_camera();
shader->set_uniform("view_model_matrix", camera.get_view_matrix()); shader->set_uniform("view_model_matrix", camera.get_view_matrix()* base_matrix);
shader->set_uniform("projection_matrix", camera.get_projection_matrix()); shader->set_uniform("projection_matrix", camera.get_projection_matrix());
#endif // ENABLE_GL_SHADERS_ATTRIBUTES #endif // ENABLE_GL_SHADERS_ATTRIBUTES
@ -329,7 +346,11 @@ void GLGizmoMove3D::on_render()
} }
#if !ENABLE_GIZMO_GRABBER_REFACTOR #if !ENABLE_GIZMO_GRABBER_REFACTOR
#if ENABLE_WORLD_COORDINATE #if ENABLE_WORLD_COORDINATE
#if ENABLE_GL_SHADERS_ATTRIBUTES
render_grabber_extension((Axis)m_hover_id, base_matrix, m_bounding_box, false);
#else
render_grabber_extension((Axis)m_hover_id, m_bounding_box, false); render_grabber_extension((Axis)m_hover_id, m_bounding_box, false);
#endif // ENABLE_GL_SHADERS_ATTRIBUTES
#else #else
render_grabber_extension((Axis)m_hover_id, box, false); render_grabber_extension((Axis)m_hover_id, box, false);
#endif // ENABLE_WORLD_COORDINATE #endif // ENABLE_WORLD_COORDINATE
@ -337,7 +358,9 @@ void GLGizmoMove3D::on_render()
} }
#if ENABLE_WORLD_COORDINATE #if ENABLE_WORLD_COORDINATE
#if !ENABLE_GL_SHADERS_ATTRIBUTES
glsafe(::glPopMatrix()); glsafe(::glPopMatrix());
#endif // !ENABLE_GL_SHADERS_ATTRIBUTES
#endif // ENABLE_WORLD_COORDINATE #endif // ENABLE_WORLD_COORDINATE
} }
@ -346,15 +369,30 @@ void GLGizmoMove3D::on_render_for_picking()
glsafe(::glDisable(GL_DEPTH_TEST)); glsafe(::glDisable(GL_DEPTH_TEST));
#if ENABLE_WORLD_COORDINATE #if ENABLE_WORLD_COORDINATE
#if ENABLE_GL_SHADERS_ATTRIBUTES
const Transform3d base_matrix = local_transform(m_parent.get_selection());
for (int i = 0; i < 3; ++i) {
m_grabbers[i].matrix = base_matrix;
}
#else
glsafe(::glPushMatrix()); glsafe(::glPushMatrix());
transform_to_local(m_parent.get_selection()); transform_to_local(m_parent.get_selection());
#endif // ENABLE_GL_SHADERS_ATTRIBUTES
render_grabbers_for_picking(m_bounding_box); render_grabbers_for_picking(m_bounding_box);
#if ENABLE_GL_SHADERS_ATTRIBUTES
#if !ENABLE_GIZMO_GRABBER_REFACTOR
render_grabber_extension(X, base_matrix, m_bounding_box, true);
render_grabber_extension(Y, base_matrix, m_bounding_box, true);
render_grabber_extension(Z, base_matrix, m_bounding_box, true);
#endif // !ENABLE_GIZMO_GRABBER_REFACTOR
#else
#if !ENABLE_GIZMO_GRABBER_REFACTOR #if !ENABLE_GIZMO_GRABBER_REFACTOR
render_grabber_extension(X, m_bounding_box, true); render_grabber_extension(X, m_bounding_box, true);
render_grabber_extension(Y, m_bounding_box, true); render_grabber_extension(Y, m_bounding_box, true);
render_grabber_extension(Z, m_bounding_box, true); render_grabber_extension(Z, m_bounding_box, true);
#endif // !ENABLE_GIZMO_GRABBER_REFACTOR #endif // !ENABLE_GIZMO_GRABBER_REFACTOR
glsafe(::glPopMatrix()); glsafe(::glPopMatrix());
#endif // ENABLE_GL_SHADERS_ATTRIBUTES
#else #else
const BoundingBoxf3& box = m_parent.get_selection().get_bounding_box(); const BoundingBoxf3& box = m_parent.get_selection().get_bounding_box();
render_grabbers_for_picking(box); render_grabbers_for_picking(box);
@ -393,9 +431,14 @@ double GLGizmoMove3D::calc_projection(const UpdateData& data) const
} }
#if !ENABLE_GIZMO_GRABBER_REFACTOR #if !ENABLE_GIZMO_GRABBER_REFACTOR
#if ENABLE_WORLD_COORDINATE && ENABLE_GL_SHADERS_ATTRIBUTES
void GLGizmoMove3D::render_grabber_extension(Axis axis, const Transform3d& base_matrix, const BoundingBoxf3& box, bool picking)
#else
void GLGizmoMove3D::render_grabber_extension(Axis axis, const BoundingBoxf3& box, bool picking) void GLGizmoMove3D::render_grabber_extension(Axis axis, const BoundingBoxf3& box, bool picking)
#endif // ENABLE_WORLD_COORDINATE && ENABLE_GL_SHADERS_ATTRIBUTES
{ {
const float mean_size = float((box.size().x() + box.size().y() + box.size().z()) / 3.0); const Vec3d box_size = box.size();
const float mean_size = float((box_size.x() + box_size.y() + box_size.z()) / 3.0);
const double size = m_dragging ? double(m_grabbers[axis].get_dragging_half_size(mean_size)) : double(m_grabbers[axis].get_half_size(mean_size)); const double size = m_dragging ? double(m_grabbers[axis].get_dragging_half_size(mean_size)) : double(m_grabbers[axis].get_half_size(mean_size));
#if ENABLE_LEGACY_OPENGL_REMOVAL #if ENABLE_LEGACY_OPENGL_REMOVAL
@ -420,7 +463,7 @@ void GLGizmoMove3D::render_grabber_extension(Axis axis, const BoundingBoxf3& box
#if ENABLE_GL_SHADERS_ATTRIBUTES #if ENABLE_GL_SHADERS_ATTRIBUTES
const Camera& camera = wxGetApp().plater()->get_camera(); const Camera& camera = wxGetApp().plater()->get_camera();
Transform3d view_model_matrix = camera.get_view_matrix() * Geometry::assemble_transform(m_grabbers[axis].center); Transform3d view_model_matrix = camera.get_view_matrix() * base_matrix * Geometry::assemble_transform(m_grabbers[axis].center);
if (axis == X) if (axis == X)
view_model_matrix = view_model_matrix * Geometry::assemble_transform(Vec3d::Zero(), 0.5 * PI * Vec3d::UnitY()); view_model_matrix = view_model_matrix * Geometry::assemble_transform(Vec3d::Zero(), 0.5 * PI * Vec3d::UnitY());
else if (axis == Y) else if (axis == Y)
@ -454,6 +497,28 @@ void GLGizmoMove3D::render_grabber_extension(Axis axis, const BoundingBoxf3& box
#endif // !ENABLE_GIZMO_GRABBER_REFACTOR #endif // !ENABLE_GIZMO_GRABBER_REFACTOR
#if ENABLE_WORLD_COORDINATE #if ENABLE_WORLD_COORDINATE
#if ENABLE_GL_SHADERS_ATTRIBUTES
Transform3d GLGizmoMove3D::local_transform(const Selection& selection) const
{
Transform3d ret = Geometry::assemble_transform(m_center);
if (!wxGetApp().obj_manipul()->is_world_coordinates()) {
const GLVolume& v = *selection.get_volume(*selection.get_volume_idxs().begin());
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
Transform3d orient_matrix = v.get_instance_transformation().get_rotation_matrix();
#else
Transform3d orient_matrix = v.get_instance_transformation().get_matrix(true, false, true, true);
#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES
if (selection.is_single_volume_or_modifier() && wxGetApp().obj_manipul()->is_local_coordinates())
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
orient_matrix = orient_matrix * v.get_volume_transformation().get_rotation_matrix();
#else
orient_matrix = orient_matrix * v.get_volume_transformation().get_matrix(true, false, true, true);
#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES
ret = ret * orient_matrix;
}
return ret;
}
#else
void GLGizmoMove3D::transform_to_local(const Selection& selection) const void GLGizmoMove3D::transform_to_local(const Selection& selection) const
{ {
glsafe(::glTranslated(m_center.x(), m_center.y(), m_center.z())); glsafe(::glTranslated(m_center.x(), m_center.y(), m_center.z()));
@ -466,6 +531,7 @@ void GLGizmoMove3D::transform_to_local(const Selection& selection) const
glsafe(::glMultMatrixd(orient_matrix.data())); glsafe(::glMultMatrixd(orient_matrix.data()));
} }
} }
#endif // ENABLE_GL_SHADERS_ATTRIBUTES
void GLGizmoMove3D::calc_selection_box_and_center() void GLGizmoMove3D::calc_selection_box_and_center()
{ {
@ -477,7 +543,12 @@ void GLGizmoMove3D::calc_selection_box_and_center()
} }
else if (coordinates_type == ECoordinatesType::Local && selection.is_single_volume_or_modifier()) { else if (coordinates_type == ECoordinatesType::Local && selection.is_single_volume_or_modifier()) {
const GLVolume& v = *selection.get_volume(*selection.get_volume_idxs().begin()); const GLVolume& v = *selection.get_volume(*selection.get_volume_idxs().begin());
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
m_bounding_box = v.transformed_convex_hull_bounding_box(
v.get_instance_transformation().get_scaling_factor_matrix() * v.get_volume_transformation().get_scaling_factor_matrix());
#else
m_bounding_box = v.transformed_convex_hull_bounding_box(v.get_instance_transformation().get_matrix(true, true, false, true) * v.get_volume_transformation().get_matrix(true, true, false, true)); m_bounding_box = v.transformed_convex_hull_bounding_box(v.get_instance_transformation().get_matrix(true, true, false, true) * v.get_volume_transformation().get_matrix(true, true, false, true));
#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES
m_center = v.world_matrix() * m_bounding_box.center(); m_center = v.world_matrix() * m_bounding_box.center();
} }
else { else {
@ -487,8 +558,13 @@ void GLGizmoMove3D::calc_selection_box_and_center()
const GLVolume& v = *selection.get_volume(id); const GLVolume& v = *selection.get_volume(id);
m_bounding_box.merge(v.transformed_convex_hull_bounding_box(v.get_volume_transformation().get_matrix())); m_bounding_box.merge(v.transformed_convex_hull_bounding_box(v.get_volume_transformation().get_matrix()));
} }
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
m_bounding_box = m_bounding_box.transformed(selection.get_volume(*ids.begin())->get_instance_transformation().get_scaling_factor_matrix());
m_center = selection.get_volume(*ids.begin())->get_instance_transformation().get_matrix_no_scaling_factor() * m_bounding_box.center();
#else
m_bounding_box = m_bounding_box.transformed(selection.get_volume(*ids.begin())->get_instance_transformation().get_matrix(true, true, false, true)); m_bounding_box = m_bounding_box.transformed(selection.get_volume(*ids.begin())->get_instance_transformation().get_matrix(true, true, false, true));
m_center = selection.get_volume(*ids.begin())->get_instance_transformation().get_matrix(false, false, true, false) * m_bounding_box.center(); m_center = selection.get_volume(*ids.begin())->get_instance_transformation().get_matrix(false, false, true, false) * m_bounding_box.center();
#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES
} }
} }
#endif // ENABLE_WORLD_COORDINATE #endif // ENABLE_WORLD_COORDINATE

View file

@ -71,7 +71,11 @@ protected:
private: private:
double calc_projection(const UpdateData& data) const; double calc_projection(const UpdateData& data) const;
#if ENABLE_WORLD_COORDINATE #if ENABLE_WORLD_COORDINATE
#if ENABLE_GL_SHADERS_ATTRIBUTES
Transform3d local_transform(const Selection& selection) const;
#else
void transform_to_local(const Selection& selection) const; void transform_to_local(const Selection& selection) const;
#endif // ENABLE_GL_SHADERS_ATTRIBUTES
void calc_selection_box_and_center(); void calc_selection_box_and_center();
#endif // ENABLE_WORLD_COORDINATE #endif // ENABLE_WORLD_COORDINATE
#if !ENABLE_GIZMO_GRABBER_REFACTOR #if !ENABLE_GIZMO_GRABBER_REFACTOR

File diff suppressed because it is too large Load diff

View file

@ -190,11 +190,7 @@ void GLGizmoRotate::on_render()
glsafe(::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f)); glsafe(::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f));
#if ENABLE_LEGACY_OPENGL_REMOVAL #if ENABLE_LEGACY_OPENGL_REMOVAL
#if ENABLE_GL_SHADERS_ATTRIBUTES
GLShaderProgram* shader = wxGetApp().get_shader("flat_attr");
#else
GLShaderProgram* shader = wxGetApp().get_shader("flat"); GLShaderProgram* shader = wxGetApp().get_shader("flat");
#endif // ENABLE_GL_SHADERS_ATTRIBUTES
if (shader != nullptr) { if (shader != nullptr) {
shader->start_using(); shader->start_using();
@ -298,7 +294,12 @@ void GLGizmoRotate::init_data_from_selection(const Selection& selection)
} }
else if (coordinates_type == ECoordinatesType::Local && selection.is_single_volume_or_modifier()) { else if (coordinates_type == ECoordinatesType::Local && selection.is_single_volume_or_modifier()) {
const GLVolume& v = *selection.get_volume(*selection.get_volume_idxs().begin()); const GLVolume& v = *selection.get_volume(*selection.get_volume_idxs().begin());
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
m_bounding_box = v.transformed_convex_hull_bounding_box(
v.get_instance_transformation().get_scaling_factor_matrix() * v.get_volume_transformation().get_scaling_factor_matrix());
#else
m_bounding_box = v.transformed_convex_hull_bounding_box(v.get_instance_transformation().get_matrix(true, true, false, true) * v.get_volume_transformation().get_matrix(true, true, false, true)); m_bounding_box = v.transformed_convex_hull_bounding_box(v.get_instance_transformation().get_matrix(true, true, false, true) * v.get_volume_transformation().get_matrix(true, true, false, true));
#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES
m_center = v.world_matrix() * m_bounding_box.center(); m_center = v.world_matrix() * m_bounding_box.center();
} }
else { else {
@ -308,8 +309,13 @@ void GLGizmoRotate::init_data_from_selection(const Selection& selection)
const GLVolume& v = *selection.get_volume(id); const GLVolume& v = *selection.get_volume(id);
m_bounding_box.merge(v.transformed_convex_hull_bounding_box(v.get_volume_transformation().get_matrix())); m_bounding_box.merge(v.transformed_convex_hull_bounding_box(v.get_volume_transformation().get_matrix()));
} }
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
m_bounding_box = m_bounding_box.transformed(selection.get_volume(*ids.begin())->get_instance_transformation().get_scaling_factor_matrix());
m_center = selection.get_volume(*ids.begin())->get_instance_transformation().get_matrix_no_scaling_factor() * m_bounding_box.center();
#else
m_bounding_box = m_bounding_box.transformed(selection.get_volume(*ids.begin())->get_instance_transformation().get_matrix(true, true, false, true)); m_bounding_box = m_bounding_box.transformed(selection.get_volume(*ids.begin())->get_instance_transformation().get_matrix(true, true, false, true));
m_center = selection.get_volume(*ids.begin())->get_instance_transformation().get_matrix(false, false, true, false) * m_bounding_box.center(); m_center = selection.get_volume(*ids.begin())->get_instance_transformation().get_matrix(false, false, true, false) * m_bounding_box.center();
#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES
} }
m_radius = Offset + m_bounding_box.radius(); m_radius = Offset + m_bounding_box.radius();
@ -322,11 +328,19 @@ void GLGizmoRotate::init_data_from_selection(const Selection& selection)
m_orient_matrix = Transform3d::Identity(); m_orient_matrix = Transform3d::Identity();
else if (coordinates_type == ECoordinatesType::Local && selection.is_single_volume_or_modifier()) { else if (coordinates_type == ECoordinatesType::Local && selection.is_single_volume_or_modifier()) {
const GLVolume& v = *selection.get_volume(*selection.get_volume_idxs().begin()); const GLVolume& v = *selection.get_volume(*selection.get_volume_idxs().begin());
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
m_orient_matrix = v.get_instance_transformation().get_rotation_matrix() * v.get_volume_transformation().get_rotation_matrix();
#else
m_orient_matrix = v.get_instance_transformation().get_matrix(true, false, true, true) * v.get_volume_transformation().get_matrix(true, false, true, true); m_orient_matrix = v.get_instance_transformation().get_matrix(true, false, true, true) * v.get_volume_transformation().get_matrix(true, false, true, true);
#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES
} }
else { else {
const GLVolume& v = *selection.get_volume(*selection.get_volume_idxs().begin()); const GLVolume& v = *selection.get_volume(*selection.get_volume_idxs().begin());
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
m_orient_matrix = v.get_instance_transformation().get_rotation_matrix();
#else
m_orient_matrix = v.get_instance_transformation().get_matrix(true, false, true, true); m_orient_matrix = v.get_instance_transformation().get_matrix(true, false, true, true);
#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES
} }
} }
#endif // ENABLE_WORLD_COORDINATE #endif // ENABLE_WORLD_COORDINATE
@ -656,11 +670,7 @@ void GLGizmoRotate::render_grabber_extension(const BoundingBoxf3& box, bool pick
const double size = m_dragging ? double(m_grabbers.front().get_dragging_half_size(mean_size)) : double(m_grabbers.front().get_half_size(mean_size)); const double size = m_dragging ? double(m_grabbers.front().get_dragging_half_size(mean_size)) : double(m_grabbers.front().get_half_size(mean_size));
#if ENABLE_LEGACY_OPENGL_REMOVAL #if ENABLE_LEGACY_OPENGL_REMOVAL
#if ENABLE_GL_SHADERS_ATTRIBUTES
GLShaderProgram* shader = wxGetApp().get_shader(picking ? "flat_attr" : "gouraud_light_attr");
#else
GLShaderProgram* shader = wxGetApp().get_shader(picking ? "flat" : "gouraud_light"); GLShaderProgram* shader = wxGetApp().get_shader(picking ? "flat" : "gouraud_light");
#endif // ENABLE_GL_SHADERS_ATTRIBUTES
if (shader == nullptr) if (shader == nullptr)
return; return;
@ -739,12 +749,12 @@ Transform3d GLGizmoRotate::local_transform(const Selection& selection) const
{ {
case X: case X:
{ {
ret = Geometry::assemble_transform(Vec3d::Zero(), Vec3d(0.0, 0.5 * PI, 0.0)) * Geometry::assemble_transform(Vec3d::Zero(), Vec3d(0.0, 0.0, -0.5 * PI)); ret = Geometry::assemble_transform(Vec3d::Zero(), 0.5 * PI * Vec3d::UnitY()) * Geometry::assemble_transform(Vec3d::Zero(), -0.5 * PI * Vec3d::UnitZ());
break; break;
} }
case Y: case Y:
{ {
ret = Geometry::assemble_transform(Vec3d::Zero(), Vec3d(0.0, 0.0, -0.5 * PI)) * Geometry::assemble_transform(Vec3d::Zero(), Vec3d(0.0, -0.5 * PI, 0.0)); ret = Geometry::assemble_transform(Vec3d::Zero(), -0.5 * PI * Vec3d::UnitZ()) * Geometry::assemble_transform(Vec3d::Zero(), -0.5 * PI * Vec3d::UnitY());
break; break;
} }
default: default:

View file

@ -219,14 +219,24 @@ void GLGizmoScale3D::on_render()
} }
#if ENABLE_WORLD_COORDINATE #if ENABLE_WORLD_COORDINATE
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
m_bounding_box = m_bounding_box.transformed(selection.get_volume(*idxs.begin())->get_instance_transformation().get_scaling_factor_matrix());
#else
m_bounding_box = m_bounding_box.transformed(selection.get_volume(*idxs.begin())->get_instance_transformation().get_matrix(true, true, false, true)); m_bounding_box = m_bounding_box.transformed(selection.get_volume(*idxs.begin())->get_instance_transformation().get_matrix(true, true, false, true));
#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES
#endif // ENABLE_WORLD_COORDINATE #endif // ENABLE_WORLD_COORDINATE
// gets transform from first selected volume // gets transform from first selected volume
const GLVolume& v = *selection.get_volume(*idxs.begin()); const GLVolume& v = *selection.get_volume(*idxs.begin());
#if ENABLE_WORLD_COORDINATE #if ENABLE_WORLD_COORDINATE
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
const Transform3d inst_trafo = v.get_instance_transformation().get_matrix_no_scaling_factor();
m_grabbers_transform = inst_trafo * Geometry::assemble_transform(m_bounding_box.center());
m_center = inst_trafo * m_bounding_box.center();
#else
m_grabbers_transform = v.get_instance_transformation().get_matrix(false, false, true) * Geometry::assemble_transform(m_bounding_box.center()); m_grabbers_transform = v.get_instance_transformation().get_matrix(false, false, true) * Geometry::assemble_transform(m_bounding_box.center());
m_center = selection.get_volume(*idxs.begin())->get_instance_transformation().get_matrix(false, false, true, false) * m_bounding_box.center(); m_center = selection.get_volume(*idxs.begin())->get_instance_transformation().get_matrix(false, false, true, false) * m_bounding_box.center();
#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES
m_instance_center = v.get_instance_offset(); m_instance_center = v.get_instance_offset();
} }
else if (selection.is_single_volume_or_modifier() && wxGetApp().obj_manipul()->is_instance_coordinates()) { else if (selection.is_single_volume_or_modifier() && wxGetApp().obj_manipul()->is_instance_coordinates()) {
@ -243,8 +253,14 @@ void GLGizmoScale3D::on_render()
#endif // ENABLE_WORLD_COORDINATE #endif // ENABLE_WORLD_COORDINATE
const GLVolume& v = *selection.get_volume(*selection.get_volume_idxs().begin()); const GLVolume& v = *selection.get_volume(*selection.get_volume_idxs().begin());
#if ENABLE_WORLD_COORDINATE #if ENABLE_WORLD_COORDINATE
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
m_bounding_box.merge(v.transformed_convex_hull_bounding_box(
v.get_instance_transformation().get_scaling_factor_matrix() * v.get_volume_transformation().get_matrix_no_offset()));
Geometry::Transformation trafo(v.get_instance_transformation().get_rotation_matrix());
#else
m_bounding_box.merge(v.transformed_convex_hull_bounding_box(v.get_instance_transformation().get_matrix(true, true, false, true) * v.get_volume_transformation().get_matrix(true, false, false, true))); m_bounding_box.merge(v.transformed_convex_hull_bounding_box(v.get_instance_transformation().get_matrix(true, true, false, true) * v.get_volume_transformation().get_matrix(true, false, false, true)));
Geometry::Transformation trafo(v.get_instance_transformation().get_matrix(true, false, true, true)); Geometry::Transformation trafo(v.get_instance_transformation().get_matrix(true, false, true, true));
#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES
trafo.set_offset(v.world_matrix().translation()); trafo.set_offset(v.world_matrix().translation());
m_grabbers_transform = trafo.get_matrix(); m_grabbers_transform = trafo.get_matrix();
m_center = v.world_matrix() * m_bounding_box.center(); m_center = v.world_matrix() * m_bounding_box.center();
@ -252,8 +268,14 @@ void GLGizmoScale3D::on_render()
} }
else if (selection.is_single_volume_or_modifier() && wxGetApp().obj_manipul()->is_local_coordinates()) { else if (selection.is_single_volume_or_modifier() && wxGetApp().obj_manipul()->is_local_coordinates()) {
const GLVolume& v = *selection.get_volume(*selection.get_volume_idxs().begin()); const GLVolume& v = *selection.get_volume(*selection.get_volume_idxs().begin());
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
m_bounding_box.merge(v.transformed_convex_hull_bounding_box(
v.get_instance_transformation().get_scaling_factor_matrix() * v.get_volume_transformation().get_scaling_factor_matrix()));
Geometry::Transformation trafo(v.get_instance_transformation().get_rotation_matrix() * v.get_volume_transformation().get_rotation_matrix());
#else
m_bounding_box.merge(v.transformed_convex_hull_bounding_box(v.get_instance_transformation().get_matrix(true, true, false, true) * v.get_volume_transformation().get_matrix(true, true, false, true))); m_bounding_box.merge(v.transformed_convex_hull_bounding_box(v.get_instance_transformation().get_matrix(true, true, false, true) * v.get_volume_transformation().get_matrix(true, true, false, true)));
Geometry::Transformation trafo(v.get_instance_transformation().get_matrix(true, false, true, true) * v.get_volume_transformation().get_matrix(true, false, true, true)); Geometry::Transformation trafo(v.get_instance_transformation().get_matrix(true, false, true, true) * v.get_volume_transformation().get_matrix(true, false, true, true));
#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES
trafo.set_offset(v.world_matrix().translation()); trafo.set_offset(v.world_matrix().translation());
m_grabbers_transform = trafo.get_matrix(); m_grabbers_transform = trafo.get_matrix();
m_center = v.world_matrix() * m_bounding_box.center(); m_center = v.world_matrix() * m_bounding_box.center();
@ -352,8 +374,15 @@ void GLGizmoScale3D::on_render()
glsafe(::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f)); glsafe(::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f));
#if ENABLE_WORLD_COORDINATE #if ENABLE_WORLD_COORDINATE
#if ENABLE_GL_SHADERS_ATTRIBUTES
const Transform3d base_matrix = local_transform(selection);
for (int i = 0; i < 10; ++i) {
m_grabbers[i].matrix = base_matrix;
}
#else
glsafe(::glPushMatrix()); glsafe(::glPushMatrix());
transform_to_local(selection); transform_to_local(selection);
#endif // ENABLE_GL_SHADERS_ATTRIBUTES
float grabber_mean_size = (float)((m_bounding_box.size().x() + m_bounding_box.size().y() + m_bounding_box.size().z()) / 3.0); float grabber_mean_size = (float)((m_bounding_box.size().x() + m_bounding_box.size().y() + m_bounding_box.size().z()) / 3.0);
#else #else
@ -557,14 +586,23 @@ void GLGizmoScale3D::on_render_for_picking()
{ {
glsafe(::glDisable(GL_DEPTH_TEST)); glsafe(::glDisable(GL_DEPTH_TEST));
#if ENABLE_WORLD_COORDINATE #if ENABLE_WORLD_COORDINATE
#if ENABLE_GL_SHADERS_ATTRIBUTES
const Transform3d base_matrix = local_transform(m_parent.get_selection());
for (int i = 0; i < 10; ++i) {
m_grabbers[i].matrix = base_matrix;
}
#else
glsafe(::glPushMatrix()); glsafe(::glPushMatrix());
transform_to_local(m_parent.get_selection()); transform_to_local(m_parent.get_selection());
#endif // ENABLE_GL_SHADERS_ATTRIBUTES
render_grabbers_for_picking(m_bounding_box); render_grabbers_for_picking(m_bounding_box);
#if !ENABLE_GL_SHADERS_ATTRIBUTES
glsafe(::glPopMatrix()); glsafe(::glPopMatrix());
#endif // !ENABLE_GL_SHADERS_ATTRIBUTES
#else #else
render_grabbers_for_picking(m_parent.get_selection().get_bounding_box()); render_grabbers_for_picking(m_parent.get_selection().get_bounding_box());
#endif // ENABLE_WORLD_COORDINATE #endif // ENABLE_WORLD_COORDINATE
} }
#if ENABLE_LEGACY_OPENGL_REMOVAL #if ENABLE_LEGACY_OPENGL_REMOVAL
void GLGizmoScale3D::render_grabbers_connection(unsigned int id_1, unsigned int id_2, const ColorRGBA& color) void GLGizmoScale3D::render_grabbers_connection(unsigned int id_1, unsigned int id_2, const ColorRGBA& color)
@ -773,6 +811,28 @@ double GLGizmoScale3D::calc_ratio(const UpdateData& data) const
} }
#if ENABLE_WORLD_COORDINATE #if ENABLE_WORLD_COORDINATE
#if ENABLE_GL_SHADERS_ATTRIBUTES
Transform3d GLGizmoScale3D::local_transform(const Selection& selection) const
{
Transform3d ret = Geometry::assemble_transform(m_center);
if (!wxGetApp().obj_manipul()->is_world_coordinates()) {
const GLVolume& v = *selection.get_volume(*selection.get_volume_idxs().begin());
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
Transform3d orient_matrix = v.get_instance_transformation().get_rotation_matrix();
#else
Transform3d orient_matrix = v.get_instance_transformation().get_matrix(true, false, true, true);
#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES
if (selection.is_single_volume_or_modifier() && wxGetApp().obj_manipul()->is_local_coordinates())
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
orient_matrix = orient_matrix * v.get_volume_transformation().get_rotation_matrix();
#else
orient_matrix = orient_matrix * v.get_volume_transformation().get_matrix(true, false, true, true);
#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES
ret = ret * orient_matrix;
}
return ret;
}
#else
void GLGizmoScale3D::transform_to_local(const Selection& selection) const void GLGizmoScale3D::transform_to_local(const Selection& selection) const
{ {
glsafe(::glTranslated(m_center.x(), m_center.y(), m_center.z())); glsafe(::glTranslated(m_center.x(), m_center.y(), m_center.z()));
@ -784,6 +844,7 @@ void GLGizmoScale3D::transform_to_local(const Selection& selection) const
glsafe(::glMultMatrixd(orient_matrix.data())); glsafe(::glMultMatrixd(orient_matrix.data()));
} }
} }
#endif // ENABLE_GL_SHADERS_ATTRIBUTES
#endif // ENABLE_WORLD_COORDINATE #endif // ENABLE_WORLD_COORDINATE
} // namespace GUI } // namespace GUI

View file

@ -107,7 +107,11 @@ private:
double calc_ratio(const UpdateData& data) const; double calc_ratio(const UpdateData& data) const;
#if ENABLE_WORLD_COORDINATE #if ENABLE_WORLD_COORDINATE
#if ENABLE_GL_SHADERS_ATTRIBUTES
Transform3d local_transform(const Selection& selection) const;
#else
void transform_to_local(const Selection& selection) const; void transform_to_local(const Selection& selection) const;
#endif // ENABLE_GL_SHADERS_ATTRIBUTES
#endif // ENABLE_WORLD_COORDINATE #endif // ENABLE_WORLD_COORDINATE
}; };

File diff suppressed because it is too large Load diff

View file

@ -1,370 +1,378 @@
#include "MeshUtils.hpp" #include "MeshUtils.hpp"
#include "libslic3r/Tesselate.hpp" #include "libslic3r/Tesselate.hpp"
#include "libslic3r/TriangleMesh.hpp" #include "libslic3r/TriangleMesh.hpp"
#include "libslic3r/TriangleMeshSlicer.hpp" #include "libslic3r/TriangleMeshSlicer.hpp"
#include "libslic3r/ClipperUtils.hpp" #include "libslic3r/ClipperUtils.hpp"
#include "libslic3r/Model.hpp" #include "libslic3r/Model.hpp"
#if ENABLE_LEGACY_OPENGL_REMOVAL #if ENABLE_LEGACY_OPENGL_REMOVAL
#include "slic3r/GUI/GUI_App.hpp" #include "slic3r/GUI/GUI_App.hpp"
#endif // ENABLE_LEGACY_OPENGL_REMOVAL #endif // ENABLE_LEGACY_OPENGL_REMOVAL
#include "slic3r/GUI/Camera.hpp" #include "slic3r/GUI/Camera.hpp"
#if ENABLE_GL_SHADERS_ATTRIBUTES #if ENABLE_GL_SHADERS_ATTRIBUTES
#include "slic3r/GUI/Plater.hpp" #include "slic3r/GUI/Plater.hpp"
#endif // ENABLE_GL_SHADERS_ATTRIBUTES #endif // ENABLE_GL_SHADERS_ATTRIBUTES
#include <GL/glew.h> #include <GL/glew.h>
#include <igl/unproject.h> #include <igl/unproject.h>
namespace Slic3r { namespace Slic3r {
namespace GUI { namespace GUI {
void MeshClipper::set_plane(const ClippingPlane& plane) void MeshClipper::set_plane(const ClippingPlane& plane)
{ {
if (m_plane != plane) { if (m_plane != plane) {
m_plane = plane; m_plane = plane;
m_triangles_valid = false; m_triangles_valid = false;
} }
} }
void MeshClipper::set_limiting_plane(const ClippingPlane& plane) void MeshClipper::set_limiting_plane(const ClippingPlane& plane)
{ {
if (m_limiting_plane != plane) { if (m_limiting_plane != plane) {
m_limiting_plane = plane; m_limiting_plane = plane;
m_triangles_valid = false; m_triangles_valid = false;
} }
} }
void MeshClipper::set_mesh(const TriangleMesh& mesh) void MeshClipper::set_mesh(const TriangleMesh& mesh)
{ {
if (m_mesh != &mesh) { if (m_mesh != &mesh) {
m_mesh = &mesh; m_mesh = &mesh;
m_triangles_valid = false; m_triangles_valid = false;
m_triangles2d.resize(0); m_triangles2d.resize(0);
} }
} }
void MeshClipper::set_negative_mesh(const TriangleMesh& mesh) void MeshClipper::set_negative_mesh(const TriangleMesh& mesh)
{ {
if (m_negative_mesh != &mesh) { if (m_negative_mesh != &mesh) {
m_negative_mesh = &mesh; m_negative_mesh = &mesh;
m_triangles_valid = false; m_triangles_valid = false;
m_triangles2d.resize(0); m_triangles2d.resize(0);
} }
} }
void MeshClipper::set_transformation(const Geometry::Transformation& trafo) void MeshClipper::set_transformation(const Geometry::Transformation& trafo)
{ {
if (! m_trafo.get_matrix().isApprox(trafo.get_matrix())) { if (! m_trafo.get_matrix().isApprox(trafo.get_matrix())) {
m_trafo = trafo; m_trafo = trafo;
m_triangles_valid = false; m_triangles_valid = false;
m_triangles2d.resize(0); m_triangles2d.resize(0);
} }
} }
#if ENABLE_LEGACY_OPENGL_REMOVAL #if ENABLE_LEGACY_OPENGL_REMOVAL
void MeshClipper::render_cut(const ColorRGBA& color) void MeshClipper::render_cut(const ColorRGBA& color)
#else #else
void MeshClipper::render_cut() void MeshClipper::render_cut()
#endif // ENABLE_LEGACY_OPENGL_REMOVAL #endif // ENABLE_LEGACY_OPENGL_REMOVAL
{ {
if (! m_triangles_valid) if (! m_triangles_valid)
recalculate_triangles(); recalculate_triangles();
#if ENABLE_LEGACY_OPENGL_REMOVAL #if ENABLE_LEGACY_OPENGL_REMOVAL
if (m_model.vertices_count() == 0 || m_model.indices_count() == 0) if (m_model.vertices_count() == 0 || m_model.indices_count() == 0)
return; return;
GLShaderProgram* curr_shader = wxGetApp().get_current_shader(); GLShaderProgram* curr_shader = wxGetApp().get_current_shader();
if (curr_shader != nullptr) if (curr_shader != nullptr)
curr_shader->stop_using(); curr_shader->stop_using();
GLShaderProgram* shader = wxGetApp().get_shader("flat"); GLShaderProgram* shader = wxGetApp().get_shader("flat");
if (shader != nullptr) { if (shader != nullptr) {
shader->start_using(); shader->start_using();
#if ENABLE_GL_SHADERS_ATTRIBUTES #if ENABLE_GL_SHADERS_ATTRIBUTES
const Camera& camera = wxGetApp().plater()->get_camera(); const Camera& camera = wxGetApp().plater()->get_camera();
shader->set_uniform("view_model_matrix", camera.get_view_matrix()); shader->set_uniform("view_model_matrix", camera.get_view_matrix());
shader->set_uniform("projection_matrix", camera.get_projection_matrix()); shader->set_uniform("projection_matrix", camera.get_projection_matrix());
#endif // ENABLE_GL_SHADERS_ATTRIBUTES #endif // ENABLE_GL_SHADERS_ATTRIBUTES
m_model.set_color(color); m_model.set_color(color);
m_model.render(); m_model.render();
shader->stop_using(); shader->stop_using();
} }
if (curr_shader != nullptr) if (curr_shader != nullptr)
curr_shader->start_using(); curr_shader->start_using();
#else #else
if (m_vertex_array.has_VBOs()) if (m_vertex_array.has_VBOs())
m_vertex_array.render(); m_vertex_array.render();
#endif // ENABLE_LEGACY_OPENGL_REMOVAL #endif // ENABLE_LEGACY_OPENGL_REMOVAL
} }
void MeshClipper::recalculate_triangles() void MeshClipper::recalculate_triangles()
{ {
const Transform3f& instance_matrix_no_translation_no_scaling = m_trafo.get_matrix(true,false,true).cast<float>(); #if ENABLE_TRANSFORMATIONS_BY_MATRICES
// Calculate clipping plane normal in mesh coordinates. const Transform3f instance_matrix_no_translation_no_scaling = m_trafo.get_rotation_matrix().cast<float>();
const Vec3f up_noscale = instance_matrix_no_translation_no_scaling.inverse() * m_plane.get_normal().cast<float>(); #else
const Vec3d up = up_noscale.cast<double>().cwiseProduct(m_trafo.get_scaling_factor()); const Transform3f& instance_matrix_no_translation_no_scaling = m_trafo.get_matrix(true,false,true).cast<float>();
// Calculate distance from mesh origin to the clipping plane (in mesh coordinates). #endif // ENABLE_TRANSFORMATIONS_BY_MATRICES
const float height_mesh = m_plane.distance(m_trafo.get_offset()) * (up_noscale.norm()/up.norm()); // Calculate clipping plane normal in mesh coordinates.
const Vec3f up_noscale = instance_matrix_no_translation_no_scaling.inverse() * m_plane.get_normal().cast<float>();
// Now do the cutting const Vec3d up = up_noscale.cast<double>().cwiseProduct(m_trafo.get_scaling_factor());
MeshSlicingParams slicing_params; // Calculate distance from mesh origin to the clipping plane (in mesh coordinates).
slicing_params.trafo.rotate(Eigen::Quaternion<double, Eigen::DontAlign>::FromTwoVectors(up, Vec3d::UnitZ())); const float height_mesh = m_plane.distance(m_trafo.get_offset()) * (up_noscale.norm()/up.norm());
ExPolygons expolys = union_ex(slice_mesh(m_mesh->its, height_mesh, slicing_params)); // Now do the cutting
MeshSlicingParams slicing_params;
if (m_negative_mesh && !m_negative_mesh->empty()) { slicing_params.trafo.rotate(Eigen::Quaternion<double, Eigen::DontAlign>::FromTwoVectors(up, Vec3d::UnitZ()));
const ExPolygons neg_expolys = union_ex(slice_mesh(m_negative_mesh->its, height_mesh, slicing_params));
expolys = diff_ex(expolys, neg_expolys); ExPolygons expolys = union_ex(slice_mesh(m_mesh->its, height_mesh, slicing_params));
}
if (m_negative_mesh && !m_negative_mesh->empty()) {
// Triangulate and rotate the cut into world coords: const ExPolygons neg_expolys = union_ex(slice_mesh(m_negative_mesh->its, height_mesh, slicing_params));
Eigen::Quaterniond q; expolys = diff_ex(expolys, neg_expolys);
q.setFromTwoVectors(Vec3d::UnitZ(), up); }
Transform3d tr = Transform3d::Identity();
tr.rotate(q); // Triangulate and rotate the cut into world coords:
tr = m_trafo.get_matrix() * tr; Eigen::Quaterniond q;
q.setFromTwoVectors(Vec3d::UnitZ(), up);
if (m_limiting_plane != ClippingPlane::ClipsNothing()) Transform3d tr = Transform3d::Identity();
{ tr.rotate(q);
// Now remove whatever ended up below the limiting plane (e.g. sinking objects). tr = m_trafo.get_matrix() * tr;
// First transform the limiting plane from world to mesh coords.
// Note that inverse of tr transforms the plane from world to horizontal. if (m_limiting_plane != ClippingPlane::ClipsNothing())
const Vec3d normal_old = m_limiting_plane.get_normal().normalized(); {
const Vec3d normal_new = (tr.matrix().block<3,3>(0,0).transpose() * normal_old).normalized(); // Now remove whatever ended up below the limiting plane (e.g. sinking objects).
// First transform the limiting plane from world to mesh coords.
// normal_new should now be the plane normal in mesh coords. To find the offset, // Note that inverse of tr transforms the plane from world to horizontal.
// transform a point and set offset so it belongs to the transformed plane. const Vec3d normal_old = m_limiting_plane.get_normal().normalized();
Vec3d pt = Vec3d::Zero(); const Vec3d normal_new = (tr.matrix().block<3,3>(0,0).transpose() * normal_old).normalized();
const double plane_offset = m_limiting_plane.get_data()[3];
if (std::abs(normal_old.z()) > 0.5) // normal is normalized, at least one of the coords if larger than sqrt(3)/3 = 0.57 // normal_new should now be the plane normal in mesh coords. To find the offset,
pt.z() = - plane_offset / normal_old.z(); // transform a point and set offset so it belongs to the transformed plane.
else if (std::abs(normal_old.y()) > 0.5) Vec3d pt = Vec3d::Zero();
pt.y() = - plane_offset / normal_old.y(); const double plane_offset = m_limiting_plane.get_data()[3];
else if (std::abs(normal_old.z()) > 0.5) // normal is normalized, at least one of the coords if larger than sqrt(3)/3 = 0.57
pt.x() = - plane_offset / normal_old.x(); pt.z() = - plane_offset / normal_old.z();
pt = tr.inverse() * pt; else if (std::abs(normal_old.y()) > 0.5)
const double offset = -(normal_new.dot(pt)); pt.y() = - plane_offset / normal_old.y();
else
if (std::abs(normal_old.dot(m_plane.get_normal().normalized())) > 0.99) { pt.x() = - plane_offset / normal_old.x();
// The cuts are parallel, show all or nothing. pt = tr.inverse() * pt;
if (normal_old.dot(m_plane.get_normal().normalized()) < 0.0 && offset < height_mesh) const double offset = -(normal_new.dot(pt));
expolys.clear();
} else { if (std::abs(normal_old.dot(m_plane.get_normal().normalized())) > 0.99) {
// The cut is a horizontal plane defined by z=height_mesh. // The cuts are parallel, show all or nothing.
// ax+by+e=0 is the line of intersection with the limiting plane. if (normal_old.dot(m_plane.get_normal().normalized()) < 0.0 && offset < height_mesh)
// Normalized so a^2 + b^2 = 1. expolys.clear();
const double len = std::hypot(normal_new.x(), normal_new.y()); } else {
if (len == 0.) // The cut is a horizontal plane defined by z=height_mesh.
return; // ax+by+e=0 is the line of intersection with the limiting plane.
const double a = normal_new.x() / len; // Normalized so a^2 + b^2 = 1.
const double b = normal_new.y() / len; const double len = std::hypot(normal_new.x(), normal_new.y());
const double e = (normal_new.z() * height_mesh + offset) / len; if (len == 0.)
return;
// We need a half-plane to limit the cut. Get angle of the intersecting line. const double a = normal_new.x() / len;
double angle = (b != 0.0) ? std::atan(-a / b) : ((a < 0.0) ? -0.5 * M_PI : 0.5 * M_PI); const double b = normal_new.y() / len;
if (b > 0) // select correct half-plane const double e = (normal_new.z() * height_mesh + offset) / len;
angle += M_PI;
// We need a half-plane to limit the cut. Get angle of the intersecting line.
// We'll take a big rectangle above x-axis and rotate and translate double angle = (b != 0.0) ? std::atan(-a / b) : ((a < 0.0) ? -0.5 * M_PI : 0.5 * M_PI);
// it so it lies on our line. This will be the figure to subtract if (b > 0) // select correct half-plane
// from the cut. The coordinates must not overflow after the transform, angle += M_PI;
// make the rectangle a bit smaller.
const coord_t size = (std::numeric_limits<coord_t>::max() - scale_(std::max(std::abs(e*a), std::abs(e*b)))) / 4; // We'll take a big rectangle above x-axis and rotate and translate
Polygons ep {Polygon({Point(-size, 0), Point(size, 0), Point(size, 2*size), Point(-size, 2*size)})}; // it so it lies on our line. This will be the figure to subtract
ep.front().rotate(angle); // from the cut. The coordinates must not overflow after the transform,
ep.front().translate(scale_(-e * a), scale_(-e * b)); // make the rectangle a bit smaller.
expolys = diff_ex(expolys, ep); const coord_t size = (std::numeric_limits<coord_t>::max() - scale_(std::max(std::abs(e*a), std::abs(e*b)))) / 4;
} Polygons ep {Polygon({Point(-size, 0), Point(size, 0), Point(size, 2*size), Point(-size, 2*size)})};
} ep.front().rotate(angle);
ep.front().translate(scale_(-e * a), scale_(-e * b));
m_triangles2d = triangulate_expolygons_2f(expolys, m_trafo.get_matrix().matrix().determinant() < 0.); expolys = diff_ex(expolys, ep);
}
tr.pretranslate(0.001 * m_plane.get_normal().normalized()); // to avoid z-fighting }
#if ENABLE_LEGACY_OPENGL_REMOVAL m_triangles2d = triangulate_expolygons_2f(expolys, m_trafo.get_matrix().matrix().determinant() < 0.);
m_model.reset();
tr.pretranslate(0.001 * m_plane.get_normal().normalized()); // to avoid z-fighting
GLModel::Geometry init_data;
init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 }; #if ENABLE_LEGACY_OPENGL_REMOVAL
init_data.reserve_vertices(m_triangles2d.size()); m_model.reset();
init_data.reserve_indices(m_triangles2d.size());
GLModel::Geometry init_data;
// vertices + indices init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 };
for (auto it = m_triangles2d.cbegin(); it != m_triangles2d.cend(); it = it + 3) { init_data.reserve_vertices(m_triangles2d.size());
init_data.add_vertex((Vec3f)(tr * Vec3d((*(it + 0)).x(), (*(it + 0)).y(), height_mesh)).cast<float>(), (Vec3f)up.cast<float>()); init_data.reserve_indices(m_triangles2d.size());
init_data.add_vertex((Vec3f)(tr * Vec3d((*(it + 1)).x(), (*(it + 1)).y(), height_mesh)).cast<float>(), (Vec3f)up.cast<float>());
init_data.add_vertex((Vec3f)(tr * Vec3d((*(it + 2)).x(), (*(it + 2)).y(), height_mesh)).cast<float>(), (Vec3f)up.cast<float>()); // vertices + indices
const size_t idx = it - m_triangles2d.cbegin(); for (auto it = m_triangles2d.cbegin(); it != m_triangles2d.cend(); it = it + 3) {
init_data.add_triangle((unsigned int)idx, (unsigned int)idx + 1, (unsigned int)idx + 2); init_data.add_vertex((Vec3f)(tr * Vec3d((*(it + 0)).x(), (*(it + 0)).y(), height_mesh)).cast<float>(), (Vec3f)up.cast<float>());
} init_data.add_vertex((Vec3f)(tr * Vec3d((*(it + 1)).x(), (*(it + 1)).y(), height_mesh)).cast<float>(), (Vec3f)up.cast<float>());
init_data.add_vertex((Vec3f)(tr * Vec3d((*(it + 2)).x(), (*(it + 2)).y(), height_mesh)).cast<float>(), (Vec3f)up.cast<float>());
if (!init_data.is_empty()) const size_t idx = it - m_triangles2d.cbegin();
m_model.init_from(std::move(init_data)); init_data.add_triangle((unsigned int)idx, (unsigned int)idx + 1, (unsigned int)idx + 2);
#else }
m_vertex_array.release_geometry();
for (auto it=m_triangles2d.cbegin(); it != m_triangles2d.cend(); it=it+3) { if (!init_data.is_empty())
m_vertex_array.push_geometry(tr * Vec3d((*(it+0))(0), (*(it+0))(1), height_mesh), up); m_model.init_from(std::move(init_data));
m_vertex_array.push_geometry(tr * Vec3d((*(it+1))(0), (*(it+1))(1), height_mesh), up); #else
m_vertex_array.push_geometry(tr * Vec3d((*(it+2))(0), (*(it+2))(1), height_mesh), up); m_vertex_array.release_geometry();
const size_t idx = it - m_triangles2d.cbegin(); for (auto it=m_triangles2d.cbegin(); it != m_triangles2d.cend(); it=it+3) {
m_vertex_array.push_triangle(idx, idx+1, idx+2); m_vertex_array.push_geometry(tr * Vec3d((*(it+0))(0), (*(it+0))(1), height_mesh), up);
} m_vertex_array.push_geometry(tr * Vec3d((*(it+1))(0), (*(it+1))(1), height_mesh), up);
m_vertex_array.finalize_geometry(true); m_vertex_array.push_geometry(tr * Vec3d((*(it+2))(0), (*(it+2))(1), height_mesh), up);
#endif // ENABLE_LEGACY_OPENGL_REMOVAL const size_t idx = it - m_triangles2d.cbegin();
m_vertex_array.push_triangle(idx, idx+1, idx+2);
m_triangles_valid = true; }
} m_vertex_array.finalize_geometry(true);
#endif // ENABLE_LEGACY_OPENGL_REMOVAL
Vec3f MeshRaycaster::get_triangle_normal(size_t facet_idx) const m_triangles_valid = true;
{ }
return m_normals[facet_idx];
}
Vec3f MeshRaycaster::get_triangle_normal(size_t facet_idx) const
void MeshRaycaster::line_from_mouse_pos(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera, {
Vec3d& point, Vec3d& direction) const return m_normals[facet_idx];
{ }
Matrix4d modelview = camera.get_view_matrix().matrix();
Matrix4d projection= camera.get_projection_matrix().matrix(); void MeshRaycaster::line_from_mouse_pos(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera,
Vec4i viewport(camera.get_viewport().data()); Vec3d& point, Vec3d& direction) const
{
Vec3d pt1; Matrix4d modelview = camera.get_view_matrix().matrix();
Vec3d pt2; Matrix4d projection= camera.get_projection_matrix().matrix();
igl::unproject(Vec3d(mouse_pos(0), viewport[3] - mouse_pos(1), 0.), Vec4i viewport(camera.get_viewport().data());
modelview, projection, viewport, pt1);
igl::unproject(Vec3d(mouse_pos(0), viewport[3] - mouse_pos(1), 1.), Vec3d pt1;
modelview, projection, viewport, pt2); Vec3d pt2;
igl::unproject(Vec3d(mouse_pos(0), viewport[3] - mouse_pos(1), 0.),
Transform3d inv = trafo.inverse(); modelview, projection, viewport, pt1);
pt1 = inv * pt1; igl::unproject(Vec3d(mouse_pos(0), viewport[3] - mouse_pos(1), 1.),
pt2 = inv * pt2; modelview, projection, viewport, pt2);
point = pt1; Transform3d inv = trafo.inverse();
direction = pt2-pt1; pt1 = inv * pt1;
} pt2 = inv * pt2;
point = pt1;
bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera, direction = pt2-pt1;
Vec3f& position, Vec3f& normal, const ClippingPlane* clipping_plane, }
size_t* facet_idx) const
{
Vec3d point; bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera,
Vec3d direction; Vec3f& position, Vec3f& normal, const ClippingPlane* clipping_plane,
line_from_mouse_pos(mouse_pos, trafo, camera, point, direction); size_t* facet_idx) const
{
std::vector<sla::IndexedMesh::hit_result> hits = m_emesh.query_ray_hits(point, direction); Vec3d point;
Vec3d direction;
if (hits.empty()) line_from_mouse_pos(mouse_pos, trafo, camera, point, direction);
return false; // no intersection found
std::vector<sla::IndexedMesh::hit_result> hits = m_emesh.query_ray_hits(point, direction);
unsigned i = 0;
if (hits.empty())
// Remove points that are obscured or cut by the clipping plane. return false; // no intersection found
// Also, remove anything below the bed (sinking objects).
for (i=0; i<hits.size(); ++i) { unsigned i = 0;
Vec3d transformed_hit = trafo * hits[i].position();
if (transformed_hit.z() >= SINKING_Z_THRESHOLD && // Remove points that are obscured or cut by the clipping plane.
(! clipping_plane || ! clipping_plane->is_point_clipped(transformed_hit))) // Also, remove anything below the bed (sinking objects).
break; for (i=0; i<hits.size(); ++i) {
} Vec3d transformed_hit = trafo * hits[i].position();
if (transformed_hit.z() >= SINKING_Z_THRESHOLD &&
if (i==hits.size() || (hits.size()-i) % 2 != 0) { (! clipping_plane || ! clipping_plane->is_point_clipped(transformed_hit)))
// All hits are either clipped, or there is an odd number of unclipped break;
// hits - meaning the nearest must be from inside the mesh. }
return false;
} if (i==hits.size() || (hits.size()-i) % 2 != 0) {
// All hits are either clipped, or there is an odd number of unclipped
// Now stuff the points in the provided vector and calculate normals if asked about them: // hits - meaning the nearest must be from inside the mesh.
position = hits[i].position().cast<float>(); return false;
normal = hits[i].normal().cast<float>(); }
if (facet_idx) // Now stuff the points in the provided vector and calculate normals if asked about them:
*facet_idx = hits[i].face(); position = hits[i].position().cast<float>();
normal = hits[i].normal().cast<float>();
return true;
} if (facet_idx)
*facet_idx = hits[i].face();
std::vector<unsigned> MeshRaycaster::get_unobscured_idxs(const Geometry::Transformation& trafo, const Camera& camera, const std::vector<Vec3f>& points, return true;
const ClippingPlane* clipping_plane) const }
{
std::vector<unsigned> out;
std::vector<unsigned> MeshRaycaster::get_unobscured_idxs(const Geometry::Transformation& trafo, const Camera& camera, const std::vector<Vec3f>& points,
const Transform3d& instance_matrix_no_translation_no_scaling = trafo.get_matrix(true,false,true); const ClippingPlane* clipping_plane) const
Vec3d direction_to_camera = -camera.get_dir_forward(); {
Vec3d direction_to_camera_mesh = (instance_matrix_no_translation_no_scaling.inverse() * direction_to_camera).normalized().eval(); std::vector<unsigned> out;
direction_to_camera_mesh = direction_to_camera_mesh.cwiseProduct(trafo.get_scaling_factor());
const Transform3d inverse_trafo = trafo.get_matrix().inverse(); #if ENABLE_TRANSFORMATIONS_BY_MATRICES
const Transform3d instance_matrix_no_translation_no_scaling = trafo.get_rotation_matrix();
for (size_t i=0; i<points.size(); ++i) { #else
const Vec3f& pt = points[i]; const Transform3d& instance_matrix_no_translation_no_scaling = trafo.get_matrix(true,false,true);
if (clipping_plane && clipping_plane->is_point_clipped(pt.cast<double>())) #endif // ENABLE_TRANSFORMATIONS_BY_MATRICES
continue; Vec3d direction_to_camera = -camera.get_dir_forward();
Vec3d direction_to_camera_mesh = (instance_matrix_no_translation_no_scaling.inverse() * direction_to_camera).normalized().eval();
bool is_obscured = false; direction_to_camera_mesh = direction_to_camera_mesh.cwiseProduct(trafo.get_scaling_factor());
// Cast a ray in the direction of the camera and look for intersection with the mesh: const Transform3d inverse_trafo = trafo.get_matrix().inverse();
std::vector<sla::IndexedMesh::hit_result> hits;
// Offset the start of the ray by EPSILON to account for numerical inaccuracies. for (size_t i=0; i<points.size(); ++i) {
hits = m_emesh.query_ray_hits((inverse_trafo * pt.cast<double>() + direction_to_camera_mesh * EPSILON), const Vec3f& pt = points[i];
direction_to_camera_mesh); if (clipping_plane && clipping_plane->is_point_clipped(pt.cast<double>()))
continue;
if (! hits.empty()) {
// If the closest hit facet normal points in the same direction as the ray, bool is_obscured = false;
// we are looking through the mesh and should therefore discard the point: // Cast a ray in the direction of the camera and look for intersection with the mesh:
if (hits.front().normal().dot(direction_to_camera_mesh.cast<double>()) > 0) std::vector<sla::IndexedMesh::hit_result> hits;
is_obscured = true; // Offset the start of the ray by EPSILON to account for numerical inaccuracies.
hits = m_emesh.query_ray_hits((inverse_trafo * pt.cast<double>() + direction_to_camera_mesh * EPSILON),
// Eradicate all hits that the caller wants to ignore direction_to_camera_mesh);
for (unsigned j=0; j<hits.size(); ++j) {
if (clipping_plane && clipping_plane->is_point_clipped(trafo.get_matrix() * hits[j].position())) { if (! hits.empty()) {
hits.erase(hits.begin()+j); // If the closest hit facet normal points in the same direction as the ray,
--j; // we are looking through the mesh and should therefore discard the point:
} if (hits.front().normal().dot(direction_to_camera_mesh.cast<double>()) > 0)
} is_obscured = true;
// FIXME: the intersection could in theory be behind the camera, but as of now we only have camera direction. // Eradicate all hits that the caller wants to ignore
// Also, the threshold is in mesh coordinates, not in actual dimensions. for (unsigned j=0; j<hits.size(); ++j) {
if (! hits.empty()) if (clipping_plane && clipping_plane->is_point_clipped(trafo.get_matrix() * hits[j].position())) {
is_obscured = true; hits.erase(hits.begin()+j);
} --j;
if (! is_obscured) }
out.push_back(i); }
}
return out; // FIXME: the intersection could in theory be behind the camera, but as of now we only have camera direction.
} // Also, the threshold is in mesh coordinates, not in actual dimensions.
if (! hits.empty())
is_obscured = true;
Vec3f MeshRaycaster::get_closest_point(const Vec3f& point, Vec3f* normal) const }
{ if (! is_obscured)
int idx = 0; out.push_back(i);
Vec3d closest_point; }
m_emesh.squared_distance(point.cast<double>(), idx, closest_point); return out;
if (normal) }
*normal = m_normals[idx];
return closest_point.cast<float>(); Vec3f MeshRaycaster::get_closest_point(const Vec3f& point, Vec3f* normal) const
} {
int idx = 0;
int MeshRaycaster::get_closest_facet(const Vec3f &point) const Vec3d closest_point;
{ m_emesh.squared_distance(point.cast<double>(), idx, closest_point);
int facet_idx = 0; if (normal)
Vec3d closest_point; *normal = m_normals[idx];
m_emesh.squared_distance(point.cast<double>(), facet_idx, closest_point);
return facet_idx; return closest_point.cast<float>();
} }
} // namespace GUI int MeshRaycaster::get_closest_facet(const Vec3f &point) const
} // namespace Slic3r {
int facet_idx = 0;
Vec3d closest_point;
m_emesh.squared_distance(point.cast<double>(), facet_idx, closest_point);
return facet_idx;
}
} // namespace GUI
} // namespace Slic3r

View file

@ -3492,7 +3492,11 @@ bool Plater::priv::replace_volume_with_stl(int object_idx, int volume_idx, const
new_volume->set_type(old_volume->type()); new_volume->set_type(old_volume->type());
new_volume->set_material_id(old_volume->material_id()); new_volume->set_material_id(old_volume->material_id());
new_volume->set_transformation(old_volume->get_transformation()); new_volume->set_transformation(old_volume->get_transformation());
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
new_volume->translate(new_volume->get_transformation().get_matrix_no_offset() * (new_volume->source.mesh_offset - old_volume->source.mesh_offset));
#else
new_volume->translate(new_volume->get_transformation().get_matrix(true) * (new_volume->source.mesh_offset - old_volume->source.mesh_offset)); new_volume->translate(new_volume->get_transformation().get_matrix(true) * (new_volume->source.mesh_offset - old_volume->source.mesh_offset));
#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES
assert(!old_volume->source.is_converted_from_inches || !old_volume->source.is_converted_from_meters); assert(!old_volume->source.is_converted_from_inches || !old_volume->source.is_converted_from_meters);
if (old_volume->source.is_converted_from_inches) if (old_volume->source.is_converted_from_inches)
new_volume->convert_from_imperial_units(); new_volume->convert_from_imperial_units();
@ -3847,10 +3851,16 @@ void Plater::priv::reload_from_disk()
new_volume->config.apply(old_volume->config); new_volume->config.apply(old_volume->config);
new_volume->set_type(old_volume->type()); new_volume->set_type(old_volume->type());
new_volume->set_material_id(old_volume->material_id()); new_volume->set_material_id(old_volume->material_id());
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
new_volume->set_transformation(Geometry::assemble_transform(old_volume->source.transform.get_offset()) *
old_volume->get_transformation().get_matrix_no_offset() * old_volume->source.transform.get_matrix_no_offset());
new_volume->translate(new_volume->get_transformation().get_matrix_no_offset() * (new_volume->source.mesh_offset - old_volume->source.mesh_offset));
#else
new_volume->set_transformation(Geometry::assemble_transform(old_volume->source.transform.get_offset()) * new_volume->set_transformation(Geometry::assemble_transform(old_volume->source.transform.get_offset()) *
old_volume->get_transformation().get_matrix(true) * old_volume->get_transformation().get_matrix(true) *
old_volume->source.transform.get_matrix(true)); old_volume->source.transform.get_matrix(true));
new_volume->translate(new_volume->get_transformation().get_matrix(true) * (new_volume->source.mesh_offset - old_volume->source.mesh_offset)); new_volume->translate(new_volume->get_transformation().get_matrix(true) * (new_volume->source.mesh_offset - old_volume->source.mesh_offset));
#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES
new_volume->source.object_idx = old_volume->source.object_idx; new_volume->source.object_idx = old_volume->source.object_idx;
new_volume->source.volume_idx = old_volume->source.volume_idx; new_volume->source.volume_idx = old_volume->source.volume_idx;
assert(!old_volume->source.is_converted_from_inches || !old_volume->source.is_converted_from_meters); assert(!old_volume->source.is_converted_from_inches || !old_volume->source.is_converted_from_meters);

View file

@ -723,7 +723,11 @@ const BoundingBoxf3& Selection::get_unscaled_instance_bounding_box() const
const GLVolume& volume = *(*m_volumes)[i]; const GLVolume& volume = *(*m_volumes)[i];
if (volume.is_modifier) if (volume.is_modifier)
continue; continue;
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
Transform3d trafo = volume.get_instance_transformation().get_matrix_no_scaling_factor() * volume.get_volume_transformation().get_matrix();
#else
Transform3d trafo = volume.get_instance_transformation().get_matrix(false, false, true, false) * volume.get_volume_transformation().get_matrix(); Transform3d trafo = volume.get_instance_transformation().get_matrix(false, false, true, false) * volume.get_volume_transformation().get_matrix();
#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES
trafo.translation().z() += volume.get_sla_shift_z(); trafo.translation().z() += volume.get_sla_shift_z();
(*bbox)->merge(volume.transformed_convex_hull_bounding_box(trafo)); (*bbox)->merge(volume.transformed_convex_hull_bounding_box(trafo));
} }
@ -1486,8 +1490,14 @@ void Selection::render(float scale_factor)
} }
else if (coordinates_type == ECoordinatesType::Local && is_single_volume_or_modifier()) { else if (coordinates_type == ECoordinatesType::Local && is_single_volume_or_modifier()) {
const GLVolume& v = *get_volume(*get_volume_idxs().begin()); const GLVolume& v = *get_volume(*get_volume_idxs().begin());
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
box = v.transformed_convex_hull_bounding_box(
v.get_instance_transformation().get_scaling_factor_matrix() * v.get_volume_transformation().get_scaling_factor_matrix());
trafo = v.get_instance_transformation().get_matrix_no_scaling_factor() * v.get_volume_transformation().get_matrix_no_scaling_factor();
#else
box = v.transformed_convex_hull_bounding_box(v.get_instance_transformation().get_matrix(true, true, false, true) * v.get_volume_transformation().get_matrix(true, true, false, true)); box = v.transformed_convex_hull_bounding_box(v.get_instance_transformation().get_matrix(true, true, false, true) * v.get_volume_transformation().get_matrix(true, true, false, true));
trafo = v.get_instance_transformation().get_matrix(false, false, true, false) * v.get_volume_transformation().get_matrix(false, false, true, false); trafo = v.get_instance_transformation().get_matrix(false, false, true, false) * v.get_volume_transformation().get_matrix(false, false, true, false);
#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES
} }
else { else {
const Selection::IndicesList& ids = get_volume_idxs(); const Selection::IndicesList& ids = get_volume_idxs();
@ -1495,8 +1505,13 @@ void Selection::render(float scale_factor)
const GLVolume& v = *get_volume(id); const GLVolume& v = *get_volume(id);
box.merge(v.transformed_convex_hull_bounding_box(v.get_volume_transformation().get_matrix())); box.merge(v.transformed_convex_hull_bounding_box(v.get_volume_transformation().get_matrix()));
} }
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
box = box.transformed(get_volume(*ids.begin())->get_instance_transformation().get_scaling_factor_matrix());
trafo = get_volume(*ids.begin())->get_instance_transformation().get_matrix_no_scaling_factor();
#else
box = box.transformed(get_volume(*ids.begin())->get_instance_transformation().get_matrix(true, true, false, true)); box = box.transformed(get_volume(*ids.begin())->get_instance_transformation().get_matrix(true, true, false, true));
trafo = get_volume(*ids.begin())->get_instance_transformation().get_matrix(false, false, true, false); trafo = get_volume(*ids.begin())->get_instance_transformation().get_matrix(false, false, true, false);
#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES
} }
render_bounding_box(box, trafo, ColorRGB::WHITE()); render_bounding_box(box, trafo, ColorRGB::WHITE());
@ -1516,11 +1531,7 @@ void Selection::render_center(bool gizmo_is_dragging)
return; return;
#if ENABLE_LEGACY_OPENGL_REMOVAL #if ENABLE_LEGACY_OPENGL_REMOVAL
#if ENABLE_GL_SHADERS_ATTRIBUTES
GLShaderProgram* shader = wxGetApp().get_shader("flat_attr");
#else
GLShaderProgram* shader = wxGetApp().get_shader("flat"); GLShaderProgram* shader = wxGetApp().get_shader("flat");
#endif // ENABLE_GL_SHADERS_ATTRIBUTES
if (shader == nullptr) if (shader == nullptr)
return; return;
@ -1565,11 +1576,7 @@ void Selection::render_sidebar_hints(const std::string& sidebar_field)
return; return;
#if ENABLE_LEGACY_OPENGL_REMOVAL #if ENABLE_LEGACY_OPENGL_REMOVAL
#if ENABLE_GL_SHADERS_ATTRIBUTES
GLShaderProgram* shader = wxGetApp().get_shader(boost::starts_with(sidebar_field, "layer") ? "flat_attr" : "gouraud_light_attr");
#else
GLShaderProgram* shader = wxGetApp().get_shader(boost::starts_with(sidebar_field, "layer") ? "flat" : "gouraud_light"); GLShaderProgram* shader = wxGetApp().get_shader(boost::starts_with(sidebar_field, "layer") ? "flat" : "gouraud_light");
#endif // ENABLE_GL_SHADERS_ATTRIBUTES
if (shader == nullptr) if (shader == nullptr)
return; return;
@ -1622,7 +1629,11 @@ void Selection::render_sidebar_hints(const std::string& sidebar_field)
#if !ENABLE_GL_SHADERS_ATTRIBUTES && !ENABLE_WORLD_COORDINATE_SHOW_AXES #if !ENABLE_GL_SHADERS_ATTRIBUTES && !ENABLE_WORLD_COORDINATE_SHOW_AXES
Transform3d orient_matrix = Transform3d::Identity(); Transform3d orient_matrix = Transform3d::Identity();
#endif // !ENABLE_GL_SHADERS_ATTRIBUTES && !ENABLE_WORLD_COORDINATE_SHOW_AXES #endif // !ENABLE_GL_SHADERS_ATTRIBUTES && !ENABLE_WORLD_COORDINATE_SHOW_AXES
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_rotation_matrix();
#else
orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true); orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true);
#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES
#if ENABLE_WORLD_COORDINATE_SHOW_AXES #if ENABLE_WORLD_COORDINATE_SHOW_AXES
axes_center = (*m_volumes)[*m_list.begin()]->get_instance_offset(); axes_center = (*m_volumes)[*m_list.begin()]->get_instance_offset();
#else #else
@ -1667,13 +1678,21 @@ void Selection::render_sidebar_hints(const std::string& sidebar_field)
#endif // !ENABLE_GL_SHADERS_ATTRIBUTES && !ENABLE_WORLD_COORDINATE_SHOW_AXES #endif // !ENABLE_GL_SHADERS_ATTRIBUTES && !ENABLE_WORLD_COORDINATE_SHOW_AXES
if (wxGetApp().obj_manipul()->is_local_coordinates()) { if (wxGetApp().obj_manipul()->is_local_coordinates()) {
const GLVolume* v = (*m_volumes)[*m_list.begin()]; const GLVolume* v = (*m_volumes)[*m_list.begin()];
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
orient_matrix = v->get_instance_transformation().get_rotation_matrix() * v->get_volume_transformation().get_rotation_matrix();
#else
orient_matrix = v->get_instance_transformation().get_matrix(true, false, true, true) * v->get_volume_transformation().get_matrix(true, false, true, true); orient_matrix = v->get_instance_transformation().get_matrix(true, false, true, true) * v->get_volume_transformation().get_matrix(true, false, true, true);
#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES
#if ENABLE_WORLD_COORDINATE_SHOW_AXES #if ENABLE_WORLD_COORDINATE_SHOW_AXES
axes_center = (*m_volumes)[*m_list.begin()]->world_matrix().translation(); axes_center = (*m_volumes)[*m_list.begin()]->world_matrix().translation();
#endif // ENABLE_WORLD_COORDINATE_SHOW_AXES #endif // ENABLE_WORLD_COORDINATE_SHOW_AXES
} }
else { else {
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_rotation_matrix();
#else
orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true); orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true);
#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES
#if ENABLE_WORLD_COORDINATE_SHOW_AXES #if ENABLE_WORLD_COORDINATE_SHOW_AXES
axes_center = (*m_volumes)[*m_list.begin()]->get_instance_offset(); axes_center = (*m_volumes)[*m_list.begin()]->get_instance_offset();
} }
@ -1700,7 +1719,11 @@ void Selection::render_sidebar_hints(const std::string& sidebar_field)
else { else {
#if ENABLE_GL_SHADERS_ATTRIBUTES || ENABLE_WORLD_COORDINATE_SHOW_AXES #if ENABLE_GL_SHADERS_ATTRIBUTES || ENABLE_WORLD_COORDINATE_SHOW_AXES
if (requires_local_axes()) if (requires_local_axes())
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_rotation_matrix();
#else
orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true); orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true);
#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES
#else #else
glsafe(::glTranslated(center.x(), center.y(), center.z())); glsafe(::glTranslated(center.x(), center.y(), center.z()));
if (requires_local_axes()) { if (requires_local_axes()) {
@ -2357,11 +2380,7 @@ void Selection::render_bounding_box(const BoundingBoxf3 & box, float* color) con
glsafe(::glLineWidth(2.0f * m_scale_factor)); glsafe(::glLineWidth(2.0f * m_scale_factor));
#if ENABLE_GL_SHADERS_ATTRIBUTES
GLShaderProgram* shader = wxGetApp().get_shader("flat_attr");
#else
GLShaderProgram* shader = wxGetApp().get_shader("flat"); GLShaderProgram* shader = wxGetApp().get_shader("flat");
#endif // ENABLE_GL_SHADERS_ATTRIBUTES
if (shader == nullptr) if (shader == nullptr)
return; return;
@ -3061,8 +3080,13 @@ void Selection::paste_volumes_from_clipboard()
{ {
ModelInstance* dst_instance = dst_object->instances[dst_inst_idx]; ModelInstance* dst_instance = dst_object->instances[dst_inst_idx];
BoundingBoxf3 dst_instance_bb = dst_object->instance_bounding_box(dst_inst_idx); BoundingBoxf3 dst_instance_bb = dst_object->instance_bounding_box(dst_inst_idx);
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
Transform3d src_matrix = src_object->instances[0]->get_transformation().get_matrix_no_offset();
Transform3d dst_matrix = dst_instance->get_transformation().get_matrix_no_offset();
#else
Transform3d src_matrix = src_object->instances[0]->get_transformation().get_matrix(true); Transform3d src_matrix = src_object->instances[0]->get_transformation().get_matrix(true);
Transform3d dst_matrix = dst_instance->get_transformation().get_matrix(true); Transform3d dst_matrix = dst_instance->get_transformation().get_matrix(true);
#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES
bool from_same_object = (src_object->input_file == dst_object->input_file) && src_matrix.isApprox(dst_matrix); 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 // used to keep relative position of multivolume selections when pasting from another object