ENH: Rotate around the center of the bounding box
jira:none code is from PrusaSlicer,thanks for enricoturri1966 and PrusaSlicer commit dcec7a8ad40eaad72789f6dba15cafc94664119f Author: enricoturri1966 <enricoturri@seznam.cz> Date: Tue Feb 28 08:08:56 2023 +0100 Fixed Rotate Gizmo orientation for mirrored objects + ensure that instances and volumes always rotate as rigid body Change-Id: I359d15814a6411bbd6bcb753661388bb5e6fb513
This commit is contained in:
parent
82775a1a59
commit
818c7a345a
|
@ -500,6 +500,15 @@ void Transformation::set_rotation(Axis axis, double rotation)
|
|||
}
|
||||
}
|
||||
|
||||
Transform3d Transformation::get_scaling_factor_matrix() const
|
||||
{
|
||||
Transform3d scale = extract_scale(m_matrix);
|
||||
scale(0, 0) = std::abs(scale(0, 0));
|
||||
scale(1, 1) = std::abs(scale(1, 1));
|
||||
scale(2, 2) = std::abs(scale(2, 2));
|
||||
return scale;
|
||||
}
|
||||
|
||||
void Transformation::set_scaling_factor(const Vec3d& scaling_factor)
|
||||
{
|
||||
set_scaling_factor(X, scaling_factor(0));
|
||||
|
|
|
@ -406,6 +406,7 @@ public:
|
|||
void set_rotation(const Vec3d& rotation);
|
||||
void set_rotation(Axis axis, double rotation);
|
||||
|
||||
Transform3d get_scaling_factor_matrix() const;
|
||||
const Vec3d& get_scaling_factor() const { return m_scaling_factor; }
|
||||
double get_scaling_factor(Axis axis) const { return m_scaling_factor(axis); }
|
||||
|
||||
|
@ -421,6 +422,7 @@ public:
|
|||
void set_mirror(Axis axis, double mirror);
|
||||
|
||||
void set_from_transform(const Transform3d& transform);
|
||||
void set_matrix(const Transform3d &transform) { set_from_transform(transform); }
|
||||
|
||||
void reset();
|
||||
void reset_offset() { set_offset(Vec3d::Zero()); }
|
||||
|
|
|
@ -437,7 +437,7 @@ public:
|
|||
|
||||
const Geometry::Transformation& get_instance_transformation() const { return m_instance_transformation; }
|
||||
void set_instance_transformation(const Geometry::Transformation& transformation) { m_instance_transformation = transformation; set_bounding_boxes_as_dirty(); }
|
||||
|
||||
void set_instance_transformation(const Transform3d &transform){ m_instance_transformation.set_matrix(transform); set_bounding_boxes_as_dirty(); }
|
||||
const Vec3d& get_instance_offset() const { return m_instance_transformation.get_offset(); }
|
||||
double get_instance_offset(Axis axis) const { return m_instance_transformation.get_offset(axis); }
|
||||
|
||||
|
@ -464,6 +464,7 @@ public:
|
|||
|
||||
const Geometry::Transformation& get_volume_transformation() const { return m_volume_transformation; }
|
||||
void set_volume_transformation(const Geometry::Transformation& transformation) { m_volume_transformation = transformation; set_bounding_boxes_as_dirty(); }
|
||||
void set_volume_transformation(const Transform3d &transform) { m_volume_transformation.set_matrix(transform); set_bounding_boxes_as_dirty(); }
|
||||
|
||||
const Vec3d& get_volume_offset() const { return m_volume_transformation.get_offset(); }
|
||||
double get_volume_offset(Axis axis) const { return m_volume_transformation.get_offset(axis); }
|
||||
|
|
|
@ -973,7 +973,26 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt)
|
|||
case Rotate:
|
||||
{
|
||||
// Apply new temporary rotations
|
||||
TransformationType transformation_type(TransformationType::World_Relative_Joint);
|
||||
TransformationType transformation_type;
|
||||
if (m_parent.get_selection().is_wipe_tower())
|
||||
transformation_type = TransformationType::World_Relative_Joint;
|
||||
else {
|
||||
switch (wxGetApp().obj_manipul()->get_coordinates_type()) {
|
||||
default:
|
||||
case ECoordinatesType::World: {
|
||||
transformation_type = TransformationType::World_Relative_Joint;
|
||||
break;
|
||||
}
|
||||
case ECoordinatesType::Instance: {
|
||||
transformation_type = TransformationType::Instance_Relative_Joint;
|
||||
break;
|
||||
}
|
||||
case ECoordinatesType::Local: {
|
||||
transformation_type = TransformationType::Local_Relative_Joint;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (evt.AltDown())
|
||||
transformation_type.set_independent();
|
||||
selection.rotate(get_rotation(), transformation_type);
|
||||
|
|
|
@ -23,6 +23,9 @@
|
|||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <boost/log/trivial.hpp>
|
||||
|
||||
#include <CGAL/Simple_cartesian.h>
|
||||
#include <CGAL/Min_sphere_of_spheres_d.h>
|
||||
#include <CGAL/Min_sphere_of_points_d_traits_3.h>
|
||||
static const std::array<float, 4> UNIFORM_SCALE_COLOR = { 0.923f, 0.504f, 0.264f, 1.0f };
|
||||
|
||||
namespace Slic3r {
|
||||
|
@ -36,7 +39,7 @@ Selection::VolumeCache::TransformCache::TransformCache()
|
|||
, rotation_matrix(Transform3d::Identity())
|
||||
, scale_matrix(Transform3d::Identity())
|
||||
, mirror_matrix(Transform3d::Identity())
|
||||
, full_matrix(Transform3d::Identity())
|
||||
, full_tran(Transform3d::Identity())
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -45,7 +48,7 @@ Selection::VolumeCache::TransformCache::TransformCache(const Geometry::Transform
|
|||
, rotation(transform.get_rotation())
|
||||
, scaling_factor(transform.get_scaling_factor())
|
||||
, mirror(transform.get_mirror())
|
||||
, full_matrix(transform.get_matrix())
|
||||
, full_tran(transform)
|
||||
{
|
||||
rotation_matrix = Geometry::assemble_transform(Vec3d::Zero(), rotation);
|
||||
scale_matrix = Geometry::assemble_transform(Vec3d::Zero(), Vec3d::Zero(), scaling_factor);
|
||||
|
@ -1002,6 +1005,40 @@ void Selection::move_to_center(const Vec3d& displacement, bool local)
|
|||
this->set_bounding_boxes_dirty();
|
||||
}
|
||||
|
||||
const std::pair<Vec3d, double> Selection::get_bounding_sphere() const
|
||||
{
|
||||
if (!m_bounding_sphere.has_value()) {
|
||||
std::optional<std::pair<Vec3d, double>> *sphere = const_cast<std::optional<std::pair<Vec3d, double>> *>(&m_bounding_sphere);
|
||||
*sphere = {Vec3d::Zero(), 0.0};
|
||||
|
||||
using K = CGAL::Simple_cartesian<float>;
|
||||
using Traits = CGAL::Min_sphere_of_points_d_traits_3<K, float>;
|
||||
using Min_sphere = CGAL::Min_sphere_of_spheres_d<Traits>;
|
||||
using Point = K::Point_3;
|
||||
|
||||
std::vector<Point> points;
|
||||
if (m_valid) {
|
||||
for (unsigned int i : m_list) {
|
||||
const GLVolume & volume = *(*m_volumes)[i];
|
||||
const TriangleMesh * hull = volume.convex_hull();
|
||||
const indexed_triangle_set &its = (hull != nullptr) ? hull->its : m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh().its;
|
||||
const Transform3d & matrix = volume.world_matrix();
|
||||
for (const Vec3f &v : its.vertices) {
|
||||
const Vec3d vv = matrix * v.cast<double>();
|
||||
points.push_back(Point(vv.x(), vv.y(), vv.z()));
|
||||
}
|
||||
}
|
||||
|
||||
Min_sphere ms(points.begin(), points.end());
|
||||
const float *center_x = ms.center_cartesian_begin();
|
||||
(*sphere)->first = {*center_x, *(center_x + 1), *(center_x + 2)};
|
||||
(*sphere)->second = ms.radius();
|
||||
}
|
||||
}
|
||||
|
||||
return *m_bounding_sphere;
|
||||
}
|
||||
|
||||
void Selection::setup_cache()
|
||||
{
|
||||
if (!m_valid)
|
||||
|
@ -1141,33 +1178,60 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_
|
|||
};
|
||||
|
||||
for (unsigned int i : m_list) {
|
||||
Transform3d rotation_matrix = Geometry::rotation_transform(rotation);
|
||||
GLVolume &v = *(*m_volumes)[i];
|
||||
if (is_single_full_instance())
|
||||
rotate_instance(v, i);
|
||||
else if (is_single_volume() || is_single_modifier()) {
|
||||
if (transformation_type.independent())
|
||||
v.set_volume_rotation(m_cache.volumes_data[i].get_volume_rotation() + rotation);
|
||||
else {
|
||||
const Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), rotation);
|
||||
const Vec3d new_rotation = Geometry::extract_euler_angles(m * m_cache.volumes_data[i].get_volume_rotation_matrix());
|
||||
v.set_volume_rotation(new_rotation);
|
||||
const VolumeCache &volume_data = m_cache.volumes_data[i];
|
||||
const Geometry::Transformation &inst_trafo = volume_data.get_instance_transform();
|
||||
if (m_mode == Instance ||is_single_full_instance()) {
|
||||
assert(is_from_fully_selected_instance(i));
|
||||
if (transformation_type.instance()) {
|
||||
// ensure that the instance rotates as a rigid body
|
||||
Transform3d inst_rotation_matrix = inst_trafo.get_rotation_matrix();
|
||||
if (inst_trafo.is_left_handed()) {
|
||||
Geometry::TransformationSVD inst_svd(inst_trafo);
|
||||
inst_rotation_matrix = inst_svd.u * inst_svd.v.transpose();
|
||||
// ensure the rotation has the proper direction
|
||||
if (!rotation.normalized().cwiseAbs().isApprox(Vec3d::UnitX())) rotation_matrix = rotation_matrix.inverse();
|
||||
}
|
||||
|
||||
const Transform3d inst_matrix_no_offset = inst_trafo.get_matrix_no_offset();
|
||||
rotation_matrix = inst_matrix_no_offset.inverse() * inst_rotation_matrix * rotation_matrix * inst_rotation_matrix.inverse() * inst_matrix_no_offset;
|
||||
|
||||
// rotate around selection center
|
||||
const Vec3d inst_pivot = inst_trafo.get_matrix_no_offset().inverse() * (m_cache.rotation_pivot - inst_trafo.get_offset());
|
||||
rotation_matrix = Geometry::translation_transform(inst_pivot) * rotation_matrix * Geometry::translation_transform(-inst_pivot);
|
||||
}
|
||||
transform_instance_relative(v, volume_data, transformation_type, rotation_matrix, m_cache.rotation_pivot);
|
||||
}
|
||||
else if (!is_single_volume_or_modifier()) {
|
||||
assert(transformation_type.world());
|
||||
transform_volume_relative(v, volume_data, transformation_type, rotation_matrix, m_cache.rotation_pivot);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
if (m_mode == Instance)
|
||||
rotate_instance(v, i);
|
||||
else if (m_mode == Volume) {
|
||||
// extracts rotations from the composed transformation
|
||||
Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), rotation);
|
||||
Vec3d new_rotation = Geometry::extract_euler_angles(m * m_cache.volumes_data[i].get_volume_rotation_matrix());
|
||||
if (transformation_type.joint()) {
|
||||
const Vec3d local_pivot = m_cache.volumes_data[i].get_instance_full_matrix().inverse() * m_cache.dragging_center;
|
||||
const Vec3d offset = m * (m_cache.volumes_data[i].get_volume_position() - local_pivot);
|
||||
v.set_volume_offset(local_pivot + offset);
|
||||
if (transformation_type.instance()) {//in object Coordinate System
|
||||
// ensure that the volume rotates as a rigid body
|
||||
const Transform3d inst_scale_matrix = inst_trafo.get_scaling_factor_matrix();
|
||||
rotation_matrix = inst_scale_matrix.inverse() * rotation_matrix * inst_scale_matrix;
|
||||
} else {
|
||||
if (transformation_type.local()) {
|
||||
// ensure that the volume rotates as a rigid body
|
||||
const Geometry::Transformation &vol_trafo = volume_data.get_volume_transform();
|
||||
const Transform3d vol_matrix_no_offset = vol_trafo.get_matrix_no_offset();
|
||||
const Transform3d inst_scale_matrix = inst_trafo.get_scaling_factor_matrix();
|
||||
Transform3d vol_rotation_matrix = vol_trafo.get_rotation_matrix();
|
||||
if (vol_trafo.is_left_handed()) {
|
||||
Geometry::TransformationSVD vol_svd(vol_trafo);
|
||||
vol_rotation_matrix = vol_svd.u * vol_svd.v.transpose();
|
||||
// ensure the rotation has the proper direction
|
||||
if (!rotation.normalized().cwiseAbs().isApprox(Vec3d::UnitX())) rotation_matrix = rotation_matrix.inverse();
|
||||
}
|
||||
rotation_matrix = vol_matrix_no_offset.inverse() * inst_scale_matrix.inverse() * vol_rotation_matrix * rotation_matrix *
|
||||
vol_rotation_matrix.inverse() * inst_scale_matrix * vol_matrix_no_offset;
|
||||
}
|
||||
v.set_volume_rotation(new_rotation);
|
||||
}
|
||||
transform_volume_relative(v, volume_data, transformation_type, rotation_matrix, m_cache.rotation_pivot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2264,6 +2328,7 @@ void Selection::set_caches()
|
|||
m_cache.sinking_volumes.push_back(i);
|
||||
}
|
||||
m_cache.dragging_center = get_bounding_box().center();
|
||||
m_cache.rotation_pivot = get_bounding_sphere().first;
|
||||
}
|
||||
|
||||
void Selection::do_add_volume(unsigned int volume_idx)
|
||||
|
@ -2915,5 +2980,45 @@ void Selection::paste_objects_from_clipboard()
|
|||
#endif /* _DEBUG */
|
||||
}
|
||||
|
||||
void Selection::transform_instance_relative(
|
||||
GLVolume &volume, const VolumeCache &volume_data, TransformationType transformation_type, const Transform3d &transform, const Vec3d &world_pivot)
|
||||
{
|
||||
assert(transformation_type.relative());
|
||||
|
||||
const Geometry::Transformation &inst_trafo = volume_data.get_instance_transform();
|
||||
if (transformation_type.world()) {
|
||||
const Vec3d inst_pivot = transformation_type.independent() && !is_from_single_instance() ? inst_trafo.get_offset() : world_pivot;
|
||||
const Transform3d trafo = Geometry::translation_transform(inst_pivot) * transform * Geometry::translation_transform(-inst_pivot);
|
||||
volume.set_instance_transformation(trafo * inst_trafo.get_matrix());
|
||||
} else if (transformation_type.instance())
|
||||
volume.set_instance_transformation(inst_trafo.get_matrix() * transform);
|
||||
else
|
||||
assert(false);
|
||||
}
|
||||
|
||||
void Selection::transform_volume_relative(
|
||||
GLVolume &volume, const VolumeCache &volume_data, TransformationType transformation_type, const Transform3d &transform, const Vec3d &world_pivot)
|
||||
{
|
||||
assert(transformation_type.relative());
|
||||
|
||||
const Geometry::Transformation &vol_trafo = volume_data.get_volume_transform();
|
||||
const Geometry::Transformation &inst_trafo = volume_data.get_instance_transform();
|
||||
|
||||
if (transformation_type.world()) {
|
||||
const Vec3d inst_pivot = transformation_type.independent() ? vol_trafo.get_offset() : (Vec3d) (inst_trafo.get_matrix().inverse() * world_pivot);
|
||||
const Transform3d inst_matrix_no_offset = inst_trafo.get_matrix_no_offset();
|
||||
const Transform3d trafo = Geometry::translation_transform(inst_pivot) * inst_matrix_no_offset.inverse() * transform * inst_matrix_no_offset *
|
||||
Geometry::translation_transform(-inst_pivot);
|
||||
volume.set_volume_transformation(trafo * vol_trafo.get_matrix());
|
||||
} else if (transformation_type.instance()) {
|
||||
const Vec3d inst_pivot = transformation_type.independent() ? vol_trafo.get_offset() : (Vec3d) (inst_trafo.get_matrix().inverse() * world_pivot);
|
||||
const Transform3d trafo = Geometry::translation_transform(inst_pivot) * transform * Geometry::translation_transform(-inst_pivot);
|
||||
volume.set_volume_transformation(trafo * vol_trafo.get_matrix());
|
||||
} else if (transformation_type.local())
|
||||
volume.set_volume_transformation(vol_trafo.get_matrix() * transform);
|
||||
else
|
||||
assert(false);
|
||||
}
|
||||
|
||||
} // namespace GUI
|
||||
} // namespace Slic3r
|
||||
|
|
|
@ -38,45 +38,69 @@ public:
|
|||
enum Enum {
|
||||
// Transforming in a world coordinate system
|
||||
World = 0,
|
||||
// Transforming in a instance coordinate system
|
||||
Instance = 1,
|
||||
// Transforming in a local coordinate system
|
||||
Local = 1,
|
||||
Local = 2,
|
||||
// Absolute transformations, allowed in local coordinate system only.
|
||||
Absolute = 0,
|
||||
// Relative transformations, allowed in both local and world coordinate system.
|
||||
Relative = 2,
|
||||
Relative = 4,
|
||||
// For group selection, the transformation is performed as if the group made a single solid body.
|
||||
Joint = 0,
|
||||
// For group selection, the transformation is performed on each object independently.
|
||||
Independent = 4,
|
||||
Independent = 8,
|
||||
|
||||
World_Relative_Joint = World | Relative | Joint,
|
||||
World_Relative_Independent = World | Relative | Independent,
|
||||
Local_Absolute_Joint = Local | Absolute | Joint,
|
||||
Local_Absolute_Independent = Local | Absolute | Independent,
|
||||
Local_Relative_Joint = Local | Relative | Joint,
|
||||
Local_Relative_Independent = Local | Relative | Independent,
|
||||
World_Relative_Joint = World | Relative | Joint,
|
||||
World_Relative_Independent = World | Relative | Independent,
|
||||
Instance_Absolute_Joint = Instance | Absolute | Joint,
|
||||
Instance_Absolute_Independent = Instance | Absolute | Independent,
|
||||
Instance_Relative_Joint = Instance | Relative | Joint,
|
||||
Instance_Relative_Independent = Instance | Relative | Independent,
|
||||
Local_Absolute_Joint = Local | Absolute | Joint,
|
||||
Local_Absolute_Independent = Local | Absolute | Independent,
|
||||
Local_Relative_Joint = Local | Relative | Joint,
|
||||
Local_Relative_Independent = Local | Relative | Independent,
|
||||
};
|
||||
|
||||
TransformationType() : m_value(World) {}
|
||||
TransformationType(Enum value) : m_value(value) {}
|
||||
TransformationType& operator=(Enum value) { m_value = value; return *this; }
|
||||
TransformationType &operator=(Enum value)
|
||||
{
|
||||
m_value = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Enum operator()() const { return m_value; }
|
||||
bool has(Enum v) const { return ((unsigned int)m_value & (unsigned int)v) != 0; }
|
||||
bool has(Enum v) const { return ((unsigned int) m_value & (unsigned int) v) != 0; }
|
||||
|
||||
void set_world() { this->remove(Local); }
|
||||
void set_local() { this->add(Local); }
|
||||
void set_absolute() { this->remove(Relative); }
|
||||
void set_relative() { this->add(Relative); }
|
||||
void set_joint() { this->remove(Independent); }
|
||||
void set_independent() { this->add(Independent); }
|
||||
void set_world()
|
||||
{
|
||||
this->remove(Instance);
|
||||
this->remove(Local);
|
||||
}
|
||||
void set_instance()
|
||||
{
|
||||
this->remove(Local);
|
||||
this->add(Instance);
|
||||
}
|
||||
void set_local()
|
||||
{
|
||||
this->remove(Instance);
|
||||
this->add(Local);
|
||||
}
|
||||
void set_absolute() { this->remove(Relative); }
|
||||
void set_relative() { this->add(Relative); }
|
||||
void set_joint() { this->remove(Independent); }
|
||||
void set_independent() { this->add(Independent); }
|
||||
|
||||
bool world() const { return !this->has(Local); }
|
||||
bool local() const { return this->has(Local); }
|
||||
bool absolute() const { return !this->has(Relative); }
|
||||
bool relative() const { return this->has(Relative); }
|
||||
bool joint() const { return !this->has(Independent); }
|
||||
bool independent() const { return this->has(Independent); }
|
||||
bool world() const { return !this->has(Instance) && !this->has(Local); }
|
||||
bool instance() const { return this->has(Instance); }
|
||||
bool local() const { return this->has(Local); }
|
||||
bool absolute() const { return !this->has(Relative); }
|
||||
bool relative() const { return this->has(Relative); }
|
||||
bool joint() const { return !this->has(Independent); }
|
||||
bool independent() const { return this->has(Independent); }
|
||||
|
||||
private:
|
||||
void add(Enum v) { m_value = Enum((unsigned int)m_value | (unsigned int)v); }
|
||||
|
@ -125,7 +149,7 @@ private:
|
|||
Transform3d rotation_matrix;
|
||||
Transform3d scale_matrix;
|
||||
Transform3d mirror_matrix;
|
||||
Transform3d full_matrix;
|
||||
Geometry::Transformation full_tran;
|
||||
|
||||
TransformCache();
|
||||
explicit TransformCache(const Geometry::Transformation& transform);
|
||||
|
@ -145,7 +169,7 @@ private:
|
|||
const Transform3d& get_volume_rotation_matrix() const { return m_volume.rotation_matrix; }
|
||||
const Transform3d& get_volume_scale_matrix() const { return m_volume.scale_matrix; }
|
||||
const Transform3d& get_volume_mirror_matrix() const { return m_volume.mirror_matrix; }
|
||||
const Transform3d& get_volume_full_matrix() const { return m_volume.full_matrix; }
|
||||
const Transform3d &get_volume_full_matrix() const { return m_volume.full_tran.get_matrix(); }
|
||||
|
||||
const Vec3d& get_instance_position() const { return m_instance.position; }
|
||||
const Vec3d& get_instance_rotation() const { return m_instance.rotation; }
|
||||
|
@ -154,7 +178,10 @@ private:
|
|||
const Transform3d& get_instance_rotation_matrix() const { return m_instance.rotation_matrix; }
|
||||
const Transform3d& get_instance_scale_matrix() const { return m_instance.scale_matrix; }
|
||||
const Transform3d& get_instance_mirror_matrix() const { return m_instance.mirror_matrix; }
|
||||
const Transform3d& get_instance_full_matrix() const { return m_instance.full_matrix; }
|
||||
const Transform3d &get_instance_full_matrix() const { return m_instance.full_tran.get_matrix(); }
|
||||
|
||||
const Geometry::Transformation &get_volume_transform() const { return m_volume.full_tran; }
|
||||
const Geometry::Transformation &get_instance_transform() const { return m_instance.full_tran; }
|
||||
};
|
||||
|
||||
public:
|
||||
|
@ -199,6 +226,7 @@ private:
|
|||
ObjectIdxsToInstanceIdxsMap content;
|
||||
// List of ids of the volumes which are sinking when starting dragging
|
||||
std::vector<unsigned int> sinking_volumes;
|
||||
Vec3d rotation_pivot;
|
||||
};
|
||||
|
||||
// Volumes owned by GLCanvas3D.
|
||||
|
@ -223,6 +251,8 @@ private:
|
|||
// Bounding box aligned to the axis of the currently selected reference system (World/Object/Part)
|
||||
// and transform to place and orient it in world coordinates
|
||||
std::optional<std::pair<BoundingBoxf3, Transform3d>> m_bounding_box_in_current_reference_system;
|
||||
|
||||
std::optional<std::pair<Vec3d, double>> m_bounding_sphere;
|
||||
#if ENABLE_RENDER_SELECTION_CENTER
|
||||
GLModel m_vbo_sphere;
|
||||
#endif // ENABLE_RENDER_SELECTION_CENTER
|
||||
|
@ -350,6 +380,8 @@ public:
|
|||
void start_dragging();
|
||||
void stop_dragging() { m_dragging = false; }
|
||||
bool is_dragging() const { return m_dragging; }
|
||||
// Returns the bounding sphere: first = center, second = radius
|
||||
const std::pair<Vec3d, double> get_bounding_sphere() const;
|
||||
|
||||
void setup_cache();
|
||||
void translate(const Vec3d& displacement, bool local = false);
|
||||
|
@ -425,6 +457,7 @@ private:
|
|||
m_bounding_box.reset();
|
||||
m_unscaled_instance_bounding_box.reset(); m_scaled_instance_bounding_box.reset();
|
||||
m_bounding_box_in_current_reference_system.reset();
|
||||
m_bounding_sphere.reset();
|
||||
}
|
||||
void render_selected_volumes() const;
|
||||
void render_synchronized_volumes() const;
|
||||
|
@ -452,6 +485,11 @@ private:
|
|||
|
||||
void paste_volumes_from_clipboard();
|
||||
void paste_objects_from_clipboard();
|
||||
|
||||
void transform_instance_relative(
|
||||
GLVolume &volume, const VolumeCache &volume_data, TransformationType transformation_type, const Transform3d &transform, const Vec3d &world_pivot);
|
||||
void transform_volume_relative(
|
||||
GLVolume &volume, const VolumeCache &volume_data, TransformationType transformation_type, const Transform3d &transform, const Vec3d &world_pivot);
|
||||
};
|
||||
|
||||
} // namespace GUI
|
||||
|
|
Loading…
Reference in New Issue