Merge branch 'dev' into lm_sla_supports_ui

This commit is contained in:
Lukas Matena 2018-09-12 10:04:57 +02:00
commit ccf27ae1f3
17 changed files with 638 additions and 261 deletions

View File

@ -154,16 +154,15 @@ sub new {
}; };
# callback to react to gizmo rotate # callback to react to gizmo rotate
# omitting last three parameters means rotation around Z
# otherwise they are the components of the rotation axis vector
my $on_gizmo_rotate = sub { my $on_gizmo_rotate = sub {
my ($angle) = @_;
$self->rotate(rad2deg($angle), Z, 'absolute');
};
# callback to react to gizmo flatten
my $on_gizmo_flatten = sub {
my ($angle, $axis_x, $axis_y, $axis_z) = @_; my ($angle, $axis_x, $axis_y, $axis_z) = @_;
if (!defined $axis_x) { $self->rotate(rad2deg($angle), undef, 'absolute', $axis_x, $axis_y, $axis_z) if $angle != 0;
$self->rotate(rad2deg($angle), Z, 'absolute');
}
else {
$self->rotate(rad2deg($angle), undef, 'absolute', $axis_x, $axis_y, $axis_z) if $angle != 0;
}
}; };
# callback to update object's geometry info while using gizmos # callback to update object's geometry info while using gizmos
@ -264,6 +263,7 @@ sub new {
Slic3r::GUI::_3DScene::register_on_enable_action_buttons_callback($self->{canvas3D}, $enable_action_buttons); Slic3r::GUI::_3DScene::register_on_enable_action_buttons_callback($self->{canvas3D}, $enable_action_buttons);
Slic3r::GUI::_3DScene::register_on_gizmo_scale_uniformly_callback($self->{canvas3D}, $on_gizmo_scale_uniformly); Slic3r::GUI::_3DScene::register_on_gizmo_scale_uniformly_callback($self->{canvas3D}, $on_gizmo_scale_uniformly);
Slic3r::GUI::_3DScene::register_on_gizmo_rotate_callback($self->{canvas3D}, $on_gizmo_rotate); Slic3r::GUI::_3DScene::register_on_gizmo_rotate_callback($self->{canvas3D}, $on_gizmo_rotate);
Slic3r::GUI::_3DScene::register_on_gizmo_flatten_callback($self->{canvas3D}, $on_gizmo_flatten);
Slic3r::GUI::_3DScene::register_on_update_geometry_info_callback($self->{canvas3D}, $on_update_geometry_info); Slic3r::GUI::_3DScene::register_on_update_geometry_info_callback($self->{canvas3D}, $on_update_geometry_info);
Slic3r::GUI::_3DScene::register_action_add_callback($self->{canvas3D}, $on_action_add); Slic3r::GUI::_3DScene::register_action_add_callback($self->{canvas3D}, $on_action_add);
Slic3r::GUI::_3DScene::register_action_delete_callback($self->{canvas3D}, $on_action_delete); Slic3r::GUI::_3DScene::register_action_delete_callback($self->{canvas3D}, $on_action_delete);
@ -880,6 +880,15 @@ sub load_files {
$model->convert_multipart_object(scalar(@$nozzle_dmrs)) if $dialog->ShowModal() == wxID_YES; $model->convert_multipart_object(scalar(@$nozzle_dmrs)) if $dialog->ShowModal() == wxID_YES;
} }
# objects imported from 3mf require a call to center_around_origin to have gizmos working properly and this call
# need to be done after looks_like_multipart_object detection
if ($input_file =~ /.3[mM][fF]$/)
{
foreach my $model_object (@{$model->objects}) {
$model_object->center_around_origin; # also aligns object to Z = 0
}
}
if ($one_by_one) { if ($one_by_one) {
push @obj_idx, $self->load_model_objects(@{$model->objects}); push @obj_idx, $self->load_model_objects(@{$model->objects});
} else { } else {

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -601,8 +601,6 @@ namespace Slic3r {
if (!_generate_volumes(*object.second, obj_geometry->second, *volumes_ptr)) if (!_generate_volumes(*object.second, obj_geometry->second, *volumes_ptr))
return false; return false;
object.second->center_around_origin();
} }
// fixes the min z of the model if negative // fixes the min z of the model if negative

View File

@ -665,6 +665,14 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
_write_format(file, "\n"); _write_format(file, "\n");
} }
// adds tags for time estimators
if (print.config.remaining_times.value)
{
_writeln(file, GCodeTimeEstimator::Normal_First_M73_Output_Placeholder_Tag);
if (m_silent_time_estimator_enabled)
_writeln(file, GCodeTimeEstimator::Silent_First_M73_Output_Placeholder_Tag);
}
// Prepare the helper object for replacing placeholders in custom G-code and output filename. // Prepare the helper object for replacing placeholders in custom G-code and output filename.
m_placeholder_parser = print.placeholder_parser; m_placeholder_parser = print.placeholder_parser;
m_placeholder_parser.update_timestamp(); m_placeholder_parser.update_timestamp();
@ -724,7 +732,6 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
m_placeholder_parser.set("has_wipe_tower", has_wipe_tower); m_placeholder_parser.set("has_wipe_tower", has_wipe_tower);
m_placeholder_parser.set("has_single_extruder_multi_material_priming", has_wipe_tower && print.config.single_extruder_multi_material_priming); m_placeholder_parser.set("has_single_extruder_multi_material_priming", has_wipe_tower && print.config.single_extruder_multi_material_priming);
std::string start_gcode = this->placeholder_parser_process("start_gcode", print.config.start_gcode.value, initial_extruder_id); std::string start_gcode = this->placeholder_parser_process("start_gcode", print.config.start_gcode.value, initial_extruder_id);
// Set bed temperature if the start G-code does not contain any bed temp control G-codes. // Set bed temperature if the start G-code does not contain any bed temp control G-codes.
this->_print_first_layer_bed_temperature(file, print, start_gcode, initial_extruder_id, true); this->_print_first_layer_bed_temperature(file, print, start_gcode, initial_extruder_id, true);
// Set extruder(s) temperature before and after start G-code. // Set extruder(s) temperature before and after start G-code.

View File

@ -168,6 +168,9 @@ namespace Slic3r {
} }
#endif // ENABLE_MOVE_STATS #endif // ENABLE_MOVE_STATS
const std::string GCodeTimeEstimator::Normal_First_M73_Output_Placeholder_Tag = "; NORMAL_FIRST_M73_OUTPUT_PLACEHOLDER";
const std::string GCodeTimeEstimator::Silent_First_M73_Output_Placeholder_Tag = "; SILENT_FIRST_M73_OUTPUT_PLACEHOLDER";
GCodeTimeEstimator::GCodeTimeEstimator(EMode mode) GCodeTimeEstimator::GCodeTimeEstimator(EMode mode)
: _mode(mode) : _mode(mode)
{ {
@ -294,7 +297,15 @@ namespace Slic3r {
throw std::runtime_error(std::string("Remaining times export failed.\nError while reading from file.\n")); throw std::runtime_error(std::string("Remaining times export failed.\nError while reading from file.\n"));
} }
gcode_line += "\n"; // replaces placeholders for initial line M73 with the real lines
if (((_mode == Normal) && (gcode_line == Normal_First_M73_Output_Placeholder_Tag)) ||
((_mode == Silent) && (gcode_line == Silent_First_M73_Output_Placeholder_Tag)))
{
sprintf(time_line, time_mask.c_str(), "0", _get_time_minutes(_time).c_str());
gcode_line = time_line;
}
else
gcode_line += "\n";
// add remaining time lines where needed // add remaining time lines where needed
_parser.parse_line(gcode_line, _parser.parse_line(gcode_line,

View File

@ -17,6 +17,9 @@ namespace Slic3r {
class GCodeTimeEstimator class GCodeTimeEstimator
{ {
public: public:
static const std::string Normal_First_M73_Output_Placeholder_Tag;
static const std::string Silent_First_M73_Output_Placeholder_Tag;
enum EMode : unsigned char enum EMode : unsigned char
{ {
Normal, Normal,

View File

@ -313,6 +313,14 @@ void GLVolume::set_select_group_id(const std::string& select_by)
select_group_id = composite_id; select_group_id = composite_id;
} }
void GLVolume::set_drag_group_id(const std::string& drag_by)
{
if (drag_by == "object")
drag_group_id = object_idx() * 1000;
else if (drag_by == "instance")
drag_group_id = object_idx() * 1000 + instance_idx();
}
const Transform3f& GLVolume::world_matrix() const const Transform3f& GLVolume::world_matrix() const
{ {
if (m_world_matrix_dirty) if (m_world_matrix_dirty)
@ -666,11 +674,7 @@ std::vector<int> GLVolumeCollection::load_object(
v.indexed_vertex_array.finalize_geometry(use_VBOs); v.indexed_vertex_array.finalize_geometry(use_VBOs);
v.composite_id = obj_idx * 1000000 + volume_idx * 1000 + instance_idx; v.composite_id = obj_idx * 1000000 + volume_idx * 1000 + instance_idx;
v.set_select_group_id(select_by); v.set_select_group_id(select_by);
if (drag_by == "object") v.set_drag_group_id(drag_by);
v.drag_group_id = obj_idx * 1000;
else if (drag_by == "instance")
v.drag_group_id = obj_idx * 1000 + instance_idx;
if (!model_volume->modifier) if (!model_volume->modifier)
{ {
v.set_convex_hull(model_volume->get_convex_hull()); v.set_convex_hull(model_volume->get_convex_hull());
@ -963,6 +967,15 @@ void GLVolumeCollection::set_select_by(const std::string& select_by)
} }
} }
void GLVolumeCollection::set_drag_by(const std::string& drag_by)
{
for (GLVolume *vol : this->volumes)
{
if (vol != nullptr)
vol->set_drag_group_id(drag_by);
}
}
std::vector<double> GLVolumeCollection::get_current_print_zs(bool active_only) const std::vector<double> GLVolumeCollection::get_current_print_zs(bool active_only) const
{ {
// Collect layer top positions of all volumes. // Collect layer top positions of all volumes.
@ -2044,6 +2057,11 @@ void _3DScene::register_on_gizmo_rotate_callback(wxGLCanvas* canvas, void* callb
s_canvas_mgr.register_on_gizmo_rotate_callback(canvas, callback); s_canvas_mgr.register_on_gizmo_rotate_callback(canvas, callback);
} }
void _3DScene::register_on_gizmo_flatten_callback(wxGLCanvas* canvas, void* callback)
{
s_canvas_mgr.register_on_gizmo_flatten_callback(canvas, callback);
}
void _3DScene::register_on_update_geometry_info_callback(wxGLCanvas* canvas, void* callback) void _3DScene::register_on_update_geometry_info_callback(wxGLCanvas* canvas, void* callback)
{ {
s_canvas_mgr.register_on_update_geometry_info_callback(canvas, callback); s_canvas_mgr.register_on_update_geometry_info_callback(canvas, callback);

View File

@ -338,6 +338,7 @@ public:
void set_convex_hull(const TriangleMesh& convex_hull); void set_convex_hull(const TriangleMesh& convex_hull);
void set_select_group_id(const std::string& select_by); void set_select_group_id(const std::string& select_by);
void set_drag_group_id(const std::string& drag_by);
int object_idx() const { return this->composite_id / 1000000; } int object_idx() const { return this->composite_id / 1000000; }
int volume_idx() const { return (this->composite_id / 1000) % 1000; } int volume_idx() const { return (this->composite_id / 1000) % 1000; }
@ -449,6 +450,7 @@ public:
void update_colors_by_extruder(const DynamicPrintConfig* config); void update_colors_by_extruder(const DynamicPrintConfig* config);
void set_select_by(const std::string& select_by); void set_select_by(const std::string& select_by);
void set_drag_by(const std::string& drag_by);
// Returns a vector containing the sorted list of all the print_zs of the volumes contained in this collection // Returns a vector containing the sorted list of all the print_zs of the volumes contained in this collection
std::vector<double> get_current_print_zs(bool active_only) const; std::vector<double> get_current_print_zs(bool active_only) const;
@ -556,6 +558,7 @@ public:
static void register_on_enable_action_buttons_callback(wxGLCanvas* canvas, void* callback); static void register_on_enable_action_buttons_callback(wxGLCanvas* canvas, void* callback);
static void register_on_gizmo_scale_uniformly_callback(wxGLCanvas* canvas, void* callback); static void register_on_gizmo_scale_uniformly_callback(wxGLCanvas* canvas, void* callback);
static void register_on_gizmo_rotate_callback(wxGLCanvas* canvas, void* callback); static void register_on_gizmo_rotate_callback(wxGLCanvas* canvas, void* callback);
static void register_on_gizmo_flatten_callback(wxGLCanvas* canvas, void* callback);
static void register_on_update_geometry_info_callback(wxGLCanvas* canvas, void* callback); static void register_on_update_geometry_info_callback(wxGLCanvas* canvas, void* callback);
static void register_action_add_callback(wxGLCanvas* canvas, void* callback); static void register_action_add_callback(wxGLCanvas* canvas, void* callback);

View File

@ -1125,7 +1125,6 @@ const float GLCanvas3D::Gizmos::OverlayGapY = 5.0f * OverlayTexturesScale;
GLCanvas3D::Gizmos::Gizmos() GLCanvas3D::Gizmos::Gizmos()
: m_enabled(false) : m_enabled(false)
, m_current(Undefined) , m_current(Undefined)
, m_dragging(false)
{ {
} }
@ -1136,13 +1135,35 @@ GLCanvas3D::Gizmos::~Gizmos()
bool GLCanvas3D::Gizmos::init(GLCanvas3D& parent) bool GLCanvas3D::Gizmos::init(GLCanvas3D& parent)
{ {
GLGizmoBase* gizmo = new GLGizmoScale3D(parent); GLGizmoBase* gizmo = new GLGizmoMove3D(parent);
if (gizmo == nullptr) if (gizmo == nullptr)
return false; return false;
if (!gizmo->init()) if (!gizmo->init())
return false; return false;
// temporary disable z grabber
gizmo->disable_grabber(2);
m_gizmos.insert(GizmosMap::value_type(Move, gizmo));
gizmo = new GLGizmoScale3D(parent);
if (gizmo == nullptr)
return false;
if (!gizmo->init())
return false;
// temporary disable x grabbers
gizmo->disable_grabber(0);
gizmo->disable_grabber(1);
// temporary disable y grabbers
gizmo->disable_grabber(2);
gizmo->disable_grabber(3);
// temporary disable z grabbers
gizmo->disable_grabber(4);
gizmo->disable_grabber(5);
m_gizmos.insert(GizmosMap::value_type(Scale, gizmo)); m_gizmos.insert(GizmosMap::value_type(Scale, gizmo));
gizmo = new GLGizmoRotate3D(parent); gizmo = new GLGizmoRotate3D(parent);
@ -1158,6 +1179,10 @@ bool GLCanvas3D::Gizmos::init(GLCanvas3D& parent)
return false; return false;
} }
// temporary disable x and y grabbers
gizmo->disable_grabber(0);
gizmo->disable_grabber(1);
m_gizmos.insert(GizmosMap::value_type(Rotate, gizmo)); m_gizmos.insert(GizmosMap::value_type(Rotate, gizmo));
gizmo = new GLGizmoFlatten(parent); gizmo = new GLGizmoFlatten(parent);
@ -1322,16 +1347,6 @@ void GLCanvas3D::Gizmos::update(const Linef3& mouse_ray)
curr->update(mouse_ray); curr->update(mouse_ray);
} }
void GLCanvas3D::Gizmos::refresh()
{
if (!m_enabled)
return;
GLGizmoBase* curr = _get_current();
if (curr != nullptr)
curr->refresh();
}
GLCanvas3D::Gizmos::EType GLCanvas3D::Gizmos::get_current_type() const GLCanvas3D::Gizmos::EType GLCanvas3D::Gizmos::get_current_type() const
{ {
return m_current; return m_current;
@ -1348,25 +1363,43 @@ bool GLCanvas3D::Gizmos::is_running() const
bool GLCanvas3D::Gizmos::is_dragging() const bool GLCanvas3D::Gizmos::is_dragging() const
{ {
return m_dragging; GLGizmoBase* curr = _get_current();
return (curr != nullptr) ? curr->is_dragging() : false;
} }
void GLCanvas3D::Gizmos::start_dragging() void GLCanvas3D::Gizmos::start_dragging(const BoundingBoxf3& box)
{ {
m_dragging = true;
GLGizmoBase* curr = _get_current(); GLGizmoBase* curr = _get_current();
if (curr != nullptr) if (curr != nullptr)
curr->start_dragging(); curr->start_dragging(box);
} }
void GLCanvas3D::Gizmos::stop_dragging() void GLCanvas3D::Gizmos::stop_dragging()
{ {
m_dragging = false;
GLGizmoBase* curr = _get_current(); GLGizmoBase* curr = _get_current();
if (curr != nullptr) if (curr != nullptr)
curr->stop_dragging(); curr->stop_dragging();
} }
Vec3d GLCanvas3D::Gizmos::get_position() const
{
if (!m_enabled)
return Vec3d::Zero();
GizmosMap::const_iterator it = m_gizmos.find(Move);
return (it != m_gizmos.end()) ? reinterpret_cast<GLGizmoMove3D*>(it->second)->get_position() : Vec3d::Zero();
}
void GLCanvas3D::Gizmos::set_position(const Vec3d& position)
{
if (!m_enabled)
return;
GizmosMap::const_iterator it = m_gizmos.find(Move);
if (it != m_gizmos.end())
reinterpret_cast<GLGizmoMove3D*>(it->second)->set_position(position);
}
float GLCanvas3D::Gizmos::get_scale() const float GLCanvas3D::Gizmos::get_scale() const
{ {
if (!m_enabled) if (!m_enabled)
@ -2155,6 +2188,7 @@ void GLCanvas3D::set_select_by(const std::string& value)
void GLCanvas3D::set_drag_by(const std::string& value) void GLCanvas3D::set_drag_by(const std::string& value)
{ {
m_drag_by = value; m_drag_by = value;
m_volumes.set_drag_by(value);
} }
const std::string& GLCanvas3D::get_select_by() const const std::string& GLCanvas3D::get_select_by() const
@ -2162,6 +2196,11 @@ const std::string& GLCanvas3D::get_select_by() const
return m_select_by; return m_select_by;
} }
const std::string& GLCanvas3D::get_drag_by() const
{
return m_drag_by;
}
float GLCanvas3D::get_camera_zoom() const float GLCanvas3D::get_camera_zoom() const
{ {
return m_camera.zoom; return m_camera.zoom;
@ -2338,6 +2377,7 @@ void GLCanvas3D::update_gizmos_data()
ModelInstance* model_instance = model_object->instances[0]; ModelInstance* model_instance = model_object->instances[0];
if (model_instance != nullptr) if (model_instance != nullptr)
{ {
m_gizmos.set_position(Vec3d(model_instance->offset(0), model_instance->offset(1), 0.0));
m_gizmos.set_scale(model_instance->scaling_factor); m_gizmos.set_scale(model_instance->scaling_factor);
m_gizmos.set_angle_z(model_instance->rotation); m_gizmos.set_angle_z(model_instance->rotation);
m_gizmos.set_flattening_data(model_object); m_gizmos.set_flattening_data(model_object);
@ -2346,6 +2386,7 @@ void GLCanvas3D::update_gizmos_data()
} }
else else
{ {
m_gizmos.set_position(Vec3d::Zero());
m_gizmos.set_scale(1.0f); m_gizmos.set_scale(1.0f);
m_gizmos.set_angle_z(0.0f); m_gizmos.set_angle_z(0.0f);
m_gizmos.set_flattening_data(nullptr); m_gizmos.set_flattening_data(nullptr);
@ -2492,8 +2533,6 @@ void GLCanvas3D::reload_scene(bool force)
if (!m_objects_selections.empty()) if (!m_objects_selections.empty())
update_gizmos_data(); update_gizmos_data();
m_gizmos.refresh();
if (m_config->has("nozzle_diameter")) if (m_config->has("nozzle_diameter"))
{ {
// Should the wipe tower be visualized ? // Should the wipe tower be visualized ?
@ -2716,6 +2755,12 @@ void GLCanvas3D::register_on_gizmo_rotate_callback(void* callback)
m_on_gizmo_rotate_callback.register_callback(callback); m_on_gizmo_rotate_callback.register_callback(callback);
} }
void GLCanvas3D::register_on_gizmo_flatten_callback(void* callback)
{
if (callback != nullptr)
m_on_gizmo_flatten_callback.register_callback(callback);
}
void GLCanvas3D::register_on_update_geometry_info_callback(void* callback) void GLCanvas3D::register_on_update_geometry_info_callback(void* callback)
{ {
if (callback != nullptr) if (callback != nullptr)
@ -3024,7 +3069,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
else if ((selected_object_idx != -1) && m_gizmos.grabber_contains_mouse()) else if ((selected_object_idx != -1) && m_gizmos.grabber_contains_mouse())
{ {
update_gizmos_data(); update_gizmos_data();
m_gizmos.start_dragging(); m_gizmos.start_dragging(_selected_volumes_bounding_box());
m_mouse.drag.gizmo_volume_idx = _get_first_selected_volume_id(selected_object_idx); m_mouse.drag.gizmo_volume_idx = _get_first_selected_volume_id(selected_object_idx);
if (m_gizmos.get_current_type() == Gizmos::Flatten) { if (m_gizmos.get_current_type() == Gizmos::Flatten) {
@ -3033,7 +3078,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
if (normal(0) != 0.0 || normal(1) != 0.0 || normal(2) != 0.0) { if (normal(0) != 0.0 || normal(1) != 0.0 || normal(2) != 0.0) {
Vec3d axis = normal(2) > 0.999 ? Vec3d::UnitX() : normal.cross(-Vec3d::UnitZ()).normalized(); Vec3d axis = normal(2) > 0.999 ? Vec3d::UnitX() : normal.cross(-Vec3d::UnitZ()).normalized();
float angle = acos(clamp(-1.0, 1.0, -normal(2))); float angle = acos(clamp(-1.0, 1.0, -normal(2)));
m_on_gizmo_rotate_callback.call(angle, (float)axis(0), (float)axis(1), (float)axis(2)); m_on_gizmo_flatten_callback.call(angle, (float)axis(0), (float)axis(1), (float)axis(2));
} }
} }
@ -3067,7 +3112,6 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
} }
update_gizmos_data(); update_gizmos_data();
m_gizmos.refresh();
m_dirty = true; m_dirty = true;
} }
} }
@ -3206,7 +3250,6 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
update_position_values(volume->get_offset()); update_position_values(volume->get_offset());
m_mouse.drag.start_position_3D = cur_pos; m_mouse.drag.start_position_3D = cur_pos;
m_gizmos.refresh();
m_dirty = true; m_dirty = true;
} }
@ -3237,6 +3280,18 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
switch (m_gizmos.get_current_type()) switch (m_gizmos.get_current_type())
{ {
case Gizmos::Move:
{
// Apply new temporary offset
GLVolume* volume = m_volumes.volumes[m_mouse.drag.gizmo_volume_idx];
Vec3d offset = m_gizmos.get_position() - volume->get_offset();
for (GLVolume* v : volumes)
{
v->set_offset(v->get_offset() + offset);
}
update_position_values(volume->get_offset());
break;
}
case Gizmos::Scale: case Gizmos::Scale:
{ {
// Apply new temporary scale factor // Apply new temporary scale factor
@ -3244,8 +3299,8 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
for (GLVolume* v : volumes) for (GLVolume* v : volumes)
{ {
v->set_scaling_factor((double)scale_factor); v->set_scaling_factor((double)scale_factor);
update_scale_values((double)scale_factor);
} }
update_scale_values((double)scale_factor);
break; break;
} }
case Gizmos::Rotate: case Gizmos::Rotate:
@ -3255,8 +3310,8 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
for (GLVolume* v : volumes) for (GLVolume* v : volumes)
{ {
v->set_rotation((double)angle_z); v->set_rotation((double)angle_z);
update_rotation_value((double)angle_z, Z);
} }
update_rotation_value((double)angle_z, Z);
break; break;
} }
default: default:
@ -3274,9 +3329,6 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
m_on_update_geometry_info_callback.call(size(0), size(1), size(2), m_gizmos.get_scale()); m_on_update_geometry_info_callback.call(size(0), size(1), size(2), m_gizmos.get_scale());
} }
if ((m_gizmos.get_current_type() != Gizmos::Rotate) && (volumes.size() > 1))
m_gizmos.refresh();
m_dirty = true; m_dirty = true;
} }
else if (evt.Dragging() && !gizmos_overlay_contains_mouse) else if (evt.Dragging() && !gizmos_overlay_contains_mouse)
@ -3369,6 +3421,27 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
{ {
switch (m_gizmos.get_current_type()) switch (m_gizmos.get_current_type())
{ {
case Gizmos::Move:
{
// get all volumes belonging to the same group, if any
std::vector<int> volume_idxs;
int vol_id = m_mouse.drag.gizmo_volume_idx;
int group_id = m_volumes.volumes[vol_id]->select_group_id;
if (group_id == -1)
volume_idxs.push_back(vol_id);
else
{
for (int i = 0; i < (int)m_volumes.volumes.size(); ++i)
{
if (m_volumes.volumes[i]->select_group_id == group_id)
volume_idxs.push_back(i);
}
}
_on_move(volume_idxs);
break;
}
case Gizmos::Scale: case Gizmos::Scale:
{ {
m_on_gizmo_scale_uniformly_callback.call((double)m_gizmos.get_scale()); m_on_gizmo_scale_uniformly_callback.call((double)m_gizmos.get_scale());
@ -3824,6 +3897,7 @@ void GLCanvas3D::_deregister_callbacks()
m_on_enable_action_buttons_callback.deregister_callback(); m_on_enable_action_buttons_callback.deregister_callback();
m_on_gizmo_scale_uniformly_callback.deregister_callback(); m_on_gizmo_scale_uniformly_callback.deregister_callback();
m_on_gizmo_rotate_callback.deregister_callback(); m_on_gizmo_rotate_callback.deregister_callback();
m_on_gizmo_flatten_callback.deregister_callback();
m_on_update_geometry_info_callback.deregister_callback(); m_on_update_geometry_info_callback.deregister_callback();
m_action_add_callback.deregister_callback(); m_action_add_callback.deregister_callback();

View File

@ -336,6 +336,7 @@ public:
enum EType : unsigned char enum EType : unsigned char
{ {
Undefined, Undefined,
Move,
Scale, Scale,
Rotate, Rotate,
Flatten, Flatten,
@ -347,7 +348,6 @@ public:
typedef std::map<EType, GLGizmoBase*> GizmosMap; typedef std::map<EType, GLGizmoBase*> GizmosMap;
GizmosMap m_gizmos; GizmosMap m_gizmos;
EType m_current; EType m_current;
bool m_dragging;
public: public:
Gizmos(); Gizmos();
@ -367,16 +367,18 @@ public:
bool overlay_contains_mouse(const GLCanvas3D& canvas, const Vec2d& mouse_pos) const; bool overlay_contains_mouse(const GLCanvas3D& canvas, const Vec2d& mouse_pos) const;
bool grabber_contains_mouse() const; bool grabber_contains_mouse() const;
void update(const Linef3& mouse_ray); void update(const Linef3& mouse_ray);
void refresh();
EType get_current_type() const; EType get_current_type() const;
bool is_running() const; bool is_running() const;
bool is_dragging() const; bool is_dragging() const;
void start_dragging(); void start_dragging(const BoundingBoxf3& box);
void stop_dragging(); void stop_dragging();
Vec3d get_position() const;
void set_position(const Vec3d& position);
float get_scale() const; float get_scale() const;
void set_scale(float scale); void set_scale(float scale);
@ -502,6 +504,7 @@ private:
PerlCallback m_on_enable_action_buttons_callback; PerlCallback m_on_enable_action_buttons_callback;
PerlCallback m_on_gizmo_scale_uniformly_callback; PerlCallback m_on_gizmo_scale_uniformly_callback;
PerlCallback m_on_gizmo_rotate_callback; PerlCallback m_on_gizmo_rotate_callback;
PerlCallback m_on_gizmo_flatten_callback;
PerlCallback m_on_update_geometry_info_callback; PerlCallback m_on_update_geometry_info_callback;
PerlCallback m_action_add_callback; PerlCallback m_action_add_callback;
@ -558,6 +561,7 @@ public:
void set_drag_by(const std::string& value); void set_drag_by(const std::string& value);
const std::string& get_select_by() const; const std::string& get_select_by() const;
const std::string& get_drag_by() const;
float get_camera_zoom() const; float get_camera_zoom() const;
@ -624,6 +628,7 @@ public:
void register_on_enable_action_buttons_callback(void* callback); void register_on_enable_action_buttons_callback(void* callback);
void register_on_gizmo_scale_uniformly_callback(void* callback); void register_on_gizmo_scale_uniformly_callback(void* callback);
void register_on_gizmo_rotate_callback(void* callback); void register_on_gizmo_rotate_callback(void* callback);
void register_on_gizmo_flatten_callback(void* callback);
void register_on_update_geometry_info_callback(void* callback); void register_on_update_geometry_info_callback(void* callback);
void register_action_add_callback(void* callback); void register_action_add_callback(void* callback);

View File

@ -700,6 +700,13 @@ void GLCanvas3DManager::register_on_gizmo_rotate_callback(wxGLCanvas* canvas, vo
it->second->register_on_gizmo_rotate_callback(callback); it->second->register_on_gizmo_rotate_callback(callback);
} }
void GLCanvas3DManager::register_on_gizmo_flatten_callback(wxGLCanvas* canvas, void* callback)
{
CanvasesMap::iterator it = _get_canvas(canvas);
if (it != m_canvases.end())
it->second->register_on_gizmo_flatten_callback(callback);
}
void GLCanvas3DManager::register_on_update_geometry_info_callback(wxGLCanvas* canvas, void* callback) void GLCanvas3DManager::register_on_update_geometry_info_callback(wxGLCanvas* canvas, void* callback)
{ {
CanvasesMap::iterator it = _get_canvas(canvas); CanvasesMap::iterator it = _get_canvas(canvas);

View File

@ -163,6 +163,7 @@ public:
void register_on_enable_action_buttons_callback(wxGLCanvas* canvas, void* callback); void register_on_enable_action_buttons_callback(wxGLCanvas* canvas, void* callback);
void register_on_gizmo_scale_uniformly_callback(wxGLCanvas* canvas, void* callback); void register_on_gizmo_scale_uniformly_callback(wxGLCanvas* canvas, void* callback);
void register_on_gizmo_rotate_callback(wxGLCanvas* canvas, void* callback); void register_on_gizmo_rotate_callback(wxGLCanvas* canvas, void* callback);
void register_on_gizmo_flatten_callback(wxGLCanvas* canvas, void* callback);
void register_on_update_geometry_info_callback(wxGLCanvas* canvas, void* callback); void register_on_update_geometry_info_callback(wxGLCanvas* canvas, void* callback);
void register_action_add_callback(wxGLCanvas* canvas, void* callback); void register_action_add_callback(wxGLCanvas* canvas, void* callback);

View File

@ -20,20 +20,105 @@ static const float AXES_COLOR[3][3] = { { 1.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f
namespace Slic3r { namespace Slic3r {
namespace GUI { namespace GUI {
const float GLGizmoBase::Grabber::HalfSize = 2.0f; // returns the intersection of the given ray with the plane parallel to plane XY and passing through the given center
// coordinates are local to the plane
Vec3d intersection_on_plane_xy(const Linef3& ray, const Vec3d& center)
{
Transform3d m = Transform3d::Identity();
m.translate(-center);
Vec2d mouse_pos_2d = to_2d(transform(ray, m).intersect_plane(0.0));
return Vec3d(mouse_pos_2d(0), mouse_pos_2d(1), 0.0);
}
// returns the intersection of the given ray with the plane parallel to plane XZ and passing through the given center
// coordinates are local to the plane
Vec3d intersection_on_plane_xz(const Linef3& ray, const Vec3d& center)
{
Transform3d m = Transform3d::Identity();
m.rotate(Eigen::AngleAxisd(-0.5 * (double)PI, Vec3d::UnitX()));
m.translate(-center);
Vec2d mouse_pos_2d = to_2d(transform(ray, m).intersect_plane(0.0));
return Vec3d(mouse_pos_2d(0), 0.0, mouse_pos_2d(1));
}
// returns the intersection of the given ray with the plane parallel to plane YZ and passing through the given center
// coordinates are local to the plane
Vec3d intersection_on_plane_yz(const Linef3& ray, const Vec3d& center)
{
Transform3d m = Transform3d::Identity();
m.rotate(Eigen::AngleAxisd(-0.5f * (double)PI, Vec3d::UnitY()));
m.translate(-center);
Vec2d mouse_pos_2d = to_2d(transform(ray, m).intersect_plane(0.0));
return Vec3d(0.0, mouse_pos_2d(1), -mouse_pos_2d(0));
}
// return an index:
// 0 for plane XY
// 1 for plane XZ
// 2 for plane YZ
// which indicates which plane is best suited for intersecting the given unit vector
// giving precedence to the plane with the given index
unsigned int select_best_plane(const Vec3d& unit_vector, unsigned int preferred_plane)
{
unsigned int ret = preferred_plane;
// 1st checks if the given vector is not parallel to the given preferred plane
double dot_to_normal = 0.0;
switch (ret)
{
case 0: // plane xy
{
dot_to_normal = std::abs(unit_vector.dot(Vec3d::UnitZ()));
break;
}
case 1: // plane xz
{
dot_to_normal = std::abs(unit_vector.dot(-Vec3d::UnitY()));
break;
}
case 2: // plane yz
{
dot_to_normal = std::abs(unit_vector.dot(Vec3d::UnitX()));
break;
}
default:
{
break;
}
}
// if almost parallel, select the plane whose normal direction is closest to the given vector direction,
// otherwise return the given preferred plane index
if (dot_to_normal < 0.1)
{
typedef std::map<double, unsigned int> ProjsMap;
ProjsMap projs_map;
projs_map.insert(ProjsMap::value_type(std::abs(unit_vector.dot(Vec3d::UnitZ())), 0)); // plane xy
projs_map.insert(ProjsMap::value_type(std::abs(unit_vector.dot(-Vec3d::UnitY())), 1)); // plane xz
projs_map.insert(ProjsMap::value_type(std::abs(unit_vector.dot(Vec3d::UnitX())), 2)); // plane yz
ret = projs_map.rbegin()->second;
}
return ret;
}
const float GLGizmoBase::Grabber::SizeFactor = 0.025f;
const float GLGizmoBase::Grabber::MinHalfSize = 1.5f;
const float GLGizmoBase::Grabber::DraggingScaleFactor = 1.25f; const float GLGizmoBase::Grabber::DraggingScaleFactor = 1.25f;
GLGizmoBase::Grabber::Grabber() GLGizmoBase::Grabber::Grabber()
: center(Vec3d::Zero()) : center(Vec3d::Zero())
, angles(Vec3d::Zero()) , angles(Vec3d::Zero())
, dragging(false) , dragging(false)
, enabled(true)
{ {
color[0] = 1.0f; color[0] = 1.0f;
color[1] = 1.0f; color[1] = 1.0f;
color[2] = 1.0f; color[2] = 1.0f;
} }
void GLGizmoBase::Grabber::render(bool hover) const void GLGizmoBase::Grabber::render(bool hover, const BoundingBoxf3& box) const
{ {
float render_color[3]; float render_color[3];
if (hover) if (hover)
@ -45,12 +130,15 @@ void GLGizmoBase::Grabber::render(bool hover) const
else else
::memcpy((void*)render_color, (const void*)color, 3 * sizeof(float)); ::memcpy((void*)render_color, (const void*)color, 3 * sizeof(float));
render(render_color, true); render(box, render_color, true);
} }
void GLGizmoBase::Grabber::render(const float* render_color, bool use_lighting) const void GLGizmoBase::Grabber::render(const BoundingBoxf3& box, const float* render_color, bool use_lighting) const
{ {
float half_size = dragging ? HalfSize * DraggingScaleFactor : HalfSize; float max_size = (float)box.max_size();
float half_size = dragging ? max_size * SizeFactor * DraggingScaleFactor : max_size * SizeFactor;
half_size = std::max(half_size, MinHalfSize);
if (use_lighting) if (use_lighting)
::glEnable(GL_LIGHTING); ::glEnable(GL_LIGHTING);
@ -129,6 +217,7 @@ GLGizmoBase::GLGizmoBase(GLCanvas3D& parent)
, m_group_id(-1) , m_group_id(-1)
, m_state(Off) , m_state(Off)
, m_hover_id(-1) , m_hover_id(-1)
, m_dragging(false)
{ {
::memcpy((void*)m_base_color, (const void*)DEFAULT_BASE_COLOR, 3 * sizeof(float)); ::memcpy((void*)m_base_color, (const void*)DEFAULT_BASE_COLOR, 3 * sizeof(float));
::memcpy((void*)m_drag_color, (const void*)DEFAULT_DRAG_COLOR, 3 * sizeof(float)); ::memcpy((void*)m_drag_color, (const void*)DEFAULT_DRAG_COLOR, 3 * sizeof(float));
@ -150,18 +239,37 @@ void GLGizmoBase::set_highlight_color(const float* color)
::memcpy((void*)m_highlight_color, (const void*)color, 3 * sizeof(float)); ::memcpy((void*)m_highlight_color, (const void*)color, 3 * sizeof(float));
} }
void GLGizmoBase::start_dragging() void GLGizmoBase::enable_grabber(unsigned int id)
{ {
if ((0 <= id) && (id < (unsigned int)m_grabbers.size()))
m_grabbers[id].enabled = true;
on_enable_grabber(id);
}
void GLGizmoBase::disable_grabber(unsigned int id)
{
if ((0 <= id) && (id < (unsigned int)m_grabbers.size()))
m_grabbers[id].enabled = false;
on_disable_grabber(id);
}
void GLGizmoBase::start_dragging(const BoundingBoxf3& box)
{
m_dragging = true;
for (int i = 0; i < (int)m_grabbers.size(); ++i) for (int i = 0; i < (int)m_grabbers.size(); ++i)
{ {
m_grabbers[i].dragging = (m_hover_id == i); m_grabbers[i].dragging = (m_hover_id == i);
} }
on_start_dragging(); on_start_dragging(box);
} }
void GLGizmoBase::stop_dragging() void GLGizmoBase::stop_dragging()
{ {
m_dragging = false;
set_tooltip(""); set_tooltip("");
for (int i = 0; i < (int)m_grabbers.size(); ++i) for (int i = 0; i < (int)m_grabbers.size(); ++i)
@ -187,22 +295,26 @@ float GLGizmoBase::picking_color_component(unsigned int id) const
return (float)color / 255.0f; return (float)color / 255.0f;
} }
void GLGizmoBase::render_grabbers() const void GLGizmoBase::render_grabbers(const BoundingBoxf3& box) const
{ {
for (int i = 0; i < (int)m_grabbers.size(); ++i) for (int i = 0; i < (int)m_grabbers.size(); ++i)
{ {
m_grabbers[i].render(m_hover_id == i); if (m_grabbers[i].enabled)
m_grabbers[i].render((m_hover_id == i), box);
} }
} }
void GLGizmoBase::render_grabbers_for_picking() const void GLGizmoBase::render_grabbers_for_picking(const BoundingBoxf3& box) const
{ {
for (unsigned int i = 0; i < (unsigned int)m_grabbers.size(); ++i) for (unsigned int i = 0; i < (unsigned int)m_grabbers.size(); ++i)
{ {
m_grabbers[i].color[0] = 1.0f; if (m_grabbers[i].enabled)
m_grabbers[i].color[1] = 1.0f; {
m_grabbers[i].color[2] = picking_color_component(i); m_grabbers[i].color[0] = 1.0f;
m_grabbers[i].render_for_picking(); m_grabbers[i].color[1] = 1.0f;
m_grabbers[i].color[2] = picking_color_component(i);
m_grabbers[i].render_for_picking(box);
}
} }
} }
@ -235,7 +347,6 @@ GLGizmoRotate::GLGizmoRotate(GLCanvas3D& parent, GLGizmoRotate::Axis axis)
, m_angle(0.0) , m_angle(0.0)
, m_center(0.0, 0.0, 0.0) , m_center(0.0, 0.0, 0.0)
, m_radius(0.0f) , m_radius(0.0f)
, m_keep_initial_values(false)
{ {
} }
@ -253,6 +364,12 @@ bool GLGizmoRotate::on_init()
return true; return true;
} }
void GLGizmoRotate::on_start_dragging(const BoundingBoxf3& box)
{
m_center = box.center();
m_radius = Offset + box.radius();
}
void GLGizmoRotate::on_update(const Linef3& mouse_ray) void GLGizmoRotate::on_update(const Linef3& mouse_ray)
{ {
Vec2d mouse_pos = to_2d(mouse_position_in_local_plane(mouse_ray)); Vec2d mouse_pos = to_2d(mouse_position_in_local_plane(mouse_ray));
@ -294,18 +411,19 @@ void GLGizmoRotate::on_update(const Linef3& mouse_ray)
void GLGizmoRotate::on_render(const BoundingBoxf3& box) const void GLGizmoRotate::on_render(const BoundingBoxf3& box) const
{ {
if (m_grabbers[0].dragging) if (!m_grabbers[0].enabled)
return;
if (m_dragging)
set_tooltip(format(m_angle * 180.0f / (float)PI, 4)); set_tooltip(format(m_angle * 180.0f / (float)PI, 4));
else
::glEnable(GL_DEPTH_TEST);
if (!m_keep_initial_values)
{ {
m_center = box.center(); m_center = box.center();
m_radius = Offset + box.radius(); m_radius = Offset + box.radius();
m_keep_initial_values = true;
} }
::glEnable(GL_DEPTH_TEST);
::glPushMatrix(); ::glPushMatrix();
transform_to_local(); transform_to_local();
@ -326,7 +444,7 @@ void GLGizmoRotate::on_render(const BoundingBoxf3& box) const
if (m_hover_id != -1) if (m_hover_id != -1)
render_angle(); render_angle();
render_grabber(); render_grabber(box);
::glPopMatrix(); ::glPopMatrix();
} }
@ -338,7 +456,7 @@ void GLGizmoRotate::on_render_for_picking(const BoundingBoxf3& box) const
::glPushMatrix(); ::glPushMatrix();
transform_to_local(); transform_to_local();
render_grabbers_for_picking(); render_grabbers_for_picking(box);
::glPopMatrix(); ::glPopMatrix();
} }
@ -430,7 +548,7 @@ void GLGizmoRotate::render_angle() const
::glEnd(); ::glEnd();
} }
void GLGizmoRotate::render_grabber() const void GLGizmoRotate::render_grabber(const BoundingBoxf3& box) const
{ {
double grabber_radius = (double)(m_radius + GrabberOffset); double grabber_radius = (double)(m_radius + GrabberOffset);
m_grabbers[0].center = Vec3d(::cos(m_angle) * grabber_radius, ::sin(m_angle) * grabber_radius, 0.0); m_grabbers[0].center = Vec3d(::cos(m_angle) * grabber_radius, ::sin(m_angle) * grabber_radius, 0.0);
@ -444,7 +562,7 @@ void GLGizmoRotate::render_grabber() const
::glEnd(); ::glEnd();
::memcpy((void*)m_grabbers[0].color, (const void*)m_highlight_color, 3 * sizeof(float)); ::memcpy((void*)m_grabbers[0].color, (const void*)m_highlight_color, 3 * sizeof(float));
render_grabbers(); render_grabbers(box);
} }
void GLGizmoRotate::transform_to_local() const void GLGizmoRotate::transform_to_local() const
@ -509,23 +627,29 @@ Vec3d GLGizmoRotate::mouse_position_in_local_plane(const Linef3& mouse_ray) cons
GLGizmoRotate3D::GLGizmoRotate3D(GLCanvas3D& parent) GLGizmoRotate3D::GLGizmoRotate3D(GLCanvas3D& parent)
: GLGizmoBase(parent) : GLGizmoBase(parent)
, m_x(parent, GLGizmoRotate::X)
, m_y(parent, GLGizmoRotate::Y)
, m_z(parent, GLGizmoRotate::Z)
{ {
m_x.set_group_id(0); m_gizmos.emplace_back(parent, GLGizmoRotate::X);
m_y.set_group_id(1); m_gizmos.emplace_back(parent, GLGizmoRotate::Y);
m_z.set_group_id(2); m_gizmos.emplace_back(parent, GLGizmoRotate::Z);
for (unsigned int i = 0; i < 3; ++i)
{
m_gizmos[i].set_group_id(i);
}
} }
bool GLGizmoRotate3D::on_init() bool GLGizmoRotate3D::on_init()
{ {
if (!m_x.init() || !m_y.init() || !m_z.init()) for (GLGizmoRotate& g : m_gizmos)
return false; {
if (!g.init())
return false;
}
m_x.set_highlight_color(AXES_COLOR[0]); for (unsigned int i = 0; i < 3; ++i)
m_y.set_highlight_color(AXES_COLOR[1]); {
m_z.set_highlight_color(AXES_COLOR[2]); m_gizmos[i].set_highlight_color(AXES_COLOR[i]);
}
std::string path = resources_dir() + "/icons/overlay/"; std::string path = resources_dir() + "/icons/overlay/";
@ -544,68 +668,28 @@ bool GLGizmoRotate3D::on_init()
return true; return true;
} }
void GLGizmoRotate3D::on_start_dragging() void GLGizmoRotate3D::on_start_dragging(const BoundingBoxf3& box)
{ {
switch (m_hover_id) if ((0 <= m_hover_id) && (m_hover_id < 3))
{ m_gizmos[m_hover_id].start_dragging(box);
case 0:
{
m_x.start_dragging();
break;
}
case 1:
{
m_y.start_dragging();
break;
}
case 2:
{
m_z.start_dragging();
break;
}
default:
{
break;
}
}
} }
void GLGizmoRotate3D::on_stop_dragging() void GLGizmoRotate3D::on_stop_dragging()
{ {
switch (m_hover_id) if ((0 <= m_hover_id) && (m_hover_id < 3))
{ m_gizmos[m_hover_id].stop_dragging();
case 0:
{
m_x.stop_dragging();
break;
}
case 1:
{
m_y.stop_dragging();
break;
}
case 2:
{
m_z.stop_dragging();
break;
}
default:
{
break;
}
}
} }
void GLGizmoRotate3D::on_render(const BoundingBoxf3& box) const void GLGizmoRotate3D::on_render(const BoundingBoxf3& box) const
{ {
if ((m_hover_id == -1) || (m_hover_id == 0)) if ((m_hover_id == -1) || (m_hover_id == 0))
m_x.render(box); m_gizmos[X].render(box);
if ((m_hover_id == -1) || (m_hover_id == 1)) if ((m_hover_id == -1) || (m_hover_id == 1))
m_y.render(box); m_gizmos[Y].render(box);
if ((m_hover_id == -1) || (m_hover_id == 2)) if ((m_hover_id == -1) || (m_hover_id == 2))
m_z.render(box); m_gizmos[Z].render(box);
} }
const float GLGizmoScale3D::Offset = 5.0f; const float GLGizmoScale3D::Offset = 5.0f;
@ -652,13 +736,13 @@ bool GLGizmoScale3D::on_init()
return true; return true;
} }
void GLGizmoScale3D::on_start_dragging() void GLGizmoScale3D::on_start_dragging(const BoundingBoxf3& box)
{ {
if (m_hover_id != -1) if (m_hover_id != -1)
{ {
m_starting_drag_position = m_grabbers[m_hover_id].center; m_starting_drag_position = m_grabbers[m_hover_id].center;
m_show_starting_box = true; m_show_starting_box = true;
m_starting_box = m_box; m_starting_box = box;
} }
} }
@ -733,14 +817,23 @@ void GLGizmoScale3D::on_render(const BoundingBoxf3& box) const
::glColor3fv(m_base_color); ::glColor3fv(m_base_color);
render_box(m_box); render_box(m_box);
// draw connections // draw connections
::glColor3fv(m_grabbers[0].color); if (m_grabbers[0].enabled && m_grabbers[1].enabled)
render_grabbers_connection(0, 1); {
::glColor3fv(m_grabbers[2].color); ::glColor3fv(m_grabbers[0].color);
render_grabbers_connection(2, 3); render_grabbers_connection(0, 1);
::glColor3fv(m_grabbers[4].color); }
render_grabbers_connection(4, 5); if (m_grabbers[2].enabled && m_grabbers[3].enabled)
{
::glColor3fv(m_grabbers[2].color);
render_grabbers_connection(2, 3);
}
if (m_grabbers[4].enabled && m_grabbers[5].enabled)
{
::glColor3fv(m_grabbers[4].color);
render_grabbers_connection(4, 5);
}
// draw grabbers // draw grabbers
render_grabbers(); render_grabbers(m_box);
} }
else if ((m_hover_id == 0) || (m_hover_id == 1)) else if ((m_hover_id == 0) || (m_hover_id == 1))
{ {
@ -757,8 +850,8 @@ void GLGizmoScale3D::on_render(const BoundingBoxf3& box) const
::glColor3fv(m_grabbers[0].color); ::glColor3fv(m_grabbers[0].color);
render_grabbers_connection(0, 1); render_grabbers_connection(0, 1);
// draw grabbers // draw grabbers
m_grabbers[0].render(true); m_grabbers[0].render(true, m_box);
m_grabbers[1].render(true); m_grabbers[1].render(true, m_box);
} }
else if ((m_hover_id == 2) || (m_hover_id == 3)) else if ((m_hover_id == 2) || (m_hover_id == 3))
{ {
@ -775,8 +868,8 @@ void GLGizmoScale3D::on_render(const BoundingBoxf3& box) const
::glColor3fv(m_grabbers[2].color); ::glColor3fv(m_grabbers[2].color);
render_grabbers_connection(2, 3); render_grabbers_connection(2, 3);
// draw grabbers // draw grabbers
m_grabbers[2].render(true); m_grabbers[2].render(true, m_box);
m_grabbers[3].render(true); m_grabbers[3].render(true, m_box);
} }
else if ((m_hover_id == 4) || (m_hover_id == 5)) else if ((m_hover_id == 4) || (m_hover_id == 5))
{ {
@ -793,8 +886,8 @@ void GLGizmoScale3D::on_render(const BoundingBoxf3& box) const
::glColor3fv(m_grabbers[4].color); ::glColor3fv(m_grabbers[4].color);
render_grabbers_connection(4, 5); render_grabbers_connection(4, 5);
// draw grabbers // draw grabbers
m_grabbers[4].render(true); m_grabbers[4].render(true, m_box);
m_grabbers[5].render(true); m_grabbers[5].render(true, m_box);
} }
else if (m_hover_id >= 6) else if (m_hover_id >= 6)
{ {
@ -810,7 +903,7 @@ void GLGizmoScale3D::on_render(const BoundingBoxf3& box) const
// draw grabbers // draw grabbers
for (int i = 6; i < 10; ++i) for (int i = 6; i < 10; ++i)
{ {
m_grabbers[i].render(true); m_grabbers[i].render(true, m_box);
} }
} }
} }
@ -819,7 +912,7 @@ void GLGizmoScale3D::on_render_for_picking(const BoundingBoxf3& box) const
{ {
::glDisable(GL_DEPTH_TEST); ::glDisable(GL_DEPTH_TEST);
render_grabbers_for_picking(); render_grabbers_for_picking(box);
} }
void GLGizmoScale3D::render_box(const BoundingBoxf3& box) const void GLGizmoScale3D::render_box(const BoundingBoxf3& box) const
@ -908,77 +1001,24 @@ double GLGizmoScale3D::calc_ratio(unsigned int preferred_plane_id, const Linef3&
Vec3d starting_vec_dir = starting_vec.normalized(); Vec3d starting_vec_dir = starting_vec.normalized();
Vec3d mouse_dir = mouse_ray.unit_vector(); Vec3d mouse_dir = mouse_ray.unit_vector();
unsigned int plane_id = preferred_plane_id;
// 1st try to see if the mouse direction is close enough to the preferred plane normal unsigned int plane_id = select_best_plane(mouse_dir, preferred_plane_id);
double dot_to_normal = 0.0; // ratio is given by the projection of the calculated intersection on the starting vector divided by the starting vector length
switch (plane_id) switch (plane_id)
{ {
case 0: case 0:
{ {
dot_to_normal = std::abs(mouse_dir.dot(Vec3d::UnitZ())); ratio = starting_vec_dir.dot(intersection_on_plane_xy(mouse_ray, center)) / len_starting_vec;
break; break;
} }
case 1: case 1:
{ {
dot_to_normal = std::abs(mouse_dir.dot(-Vec3d::UnitY())); ratio = starting_vec_dir.dot(intersection_on_plane_xz(mouse_ray, center)) / len_starting_vec;
break; break;
} }
case 2: case 2:
{ {
dot_to_normal = std::abs(mouse_dir.dot(Vec3d::UnitX())); ratio = starting_vec_dir.dot(intersection_on_plane_yz(mouse_ray, center)) / len_starting_vec;
break;
}
}
if (dot_to_normal < 0.1)
{
// if not, select the plane who's normal is closest to the mouse direction
typedef std::map<double, unsigned int> ProjsMap;
ProjsMap projs_map;
projs_map.insert(ProjsMap::value_type(std::abs(mouse_dir.dot(Vec3d::UnitZ())), 0)); // plane xy
projs_map.insert(ProjsMap::value_type(std::abs(mouse_dir.dot(-Vec3d::UnitY())), 1)); // plane xz
projs_map.insert(ProjsMap::value_type(std::abs(mouse_dir.dot(Vec3d::UnitX())), 2)); // plane yz
plane_id = projs_map.rbegin()->second;
}
switch (plane_id)
{
case 0:
{
// calculates the intersection of the mouse ray with the plane parallel to plane XY and passing through the given center
Transform3d m = Transform3d::Identity();
m.translate(-center);
Vec2d mouse_pos_2d = to_2d(transform(mouse_ray, m).intersect_plane(0.0));
// ratio is given by the projection of the calculated intersection on the starting vector divided by the starting vector length
ratio = starting_vec_dir.dot(Vec3d(mouse_pos_2d(0), mouse_pos_2d(1), 0.0)) / len_starting_vec;
break;
}
case 1:
{
// calculates the intersection of the mouse ray with the plane parallel to plane XZ and passing through the given center
Transform3d m = Transform3d::Identity();
m.rotate(Eigen::AngleAxisd(-0.5 * (double)PI, Vec3d::UnitX()));
m.translate(-center);
Vec2d mouse_pos_2d = to_2d(transform(mouse_ray, m).intersect_plane(0.0));
// ratio is given by the projection of the calculated intersection on the starting vector divided by the starting vector length
ratio = starting_vec_dir.dot(Vec3d(mouse_pos_2d(0), 0.0, mouse_pos_2d(1))) / len_starting_vec;
break;
}
case 2:
{
// calculates the intersection of the mouse ray with the plane parallel to plane YZ and passing through the given center
Transform3d m = Transform3d::Identity();
m.rotate(Eigen::AngleAxisd(-0.5f * (double)PI, Vec3d::UnitY()));
m.translate(-center);
Vec2d mouse_pos_2d = to_2d(transform(mouse_ray, m).intersect_plane(0.0));
// ratio is given by the projection of the calculated intersection on the starting vector divided by the starting vector length
ratio = starting_vec_dir.dot(Vec3d(0.0, mouse_pos_2d(1), -mouse_pos_2d(0))) / len_starting_vec;
break; break;
} }
} }
@ -986,10 +1026,165 @@ double GLGizmoScale3D::calc_ratio(unsigned int preferred_plane_id, const Linef3&
return ratio; return ratio;
} }
const double GLGizmoMove3D::Offset = 10.0;
GLGizmoMove3D::GLGizmoMove3D(GLCanvas3D& parent)
: GLGizmoBase(parent)
, m_position(Vec3d::Zero())
, m_starting_drag_position(Vec3d::Zero())
, m_starting_box_center(Vec3d::Zero())
{
}
bool GLGizmoMove3D::on_init()
{
std::string path = resources_dir() + "/icons/overlay/";
std::string filename = path + "move_off.png";
if (!m_textures[Off].load_from_file(filename, false))
return false;
filename = path + "move_hover.png";
if (!m_textures[Hover].load_from_file(filename, false))
return false;
filename = path + "move_on.png";
if (!m_textures[On].load_from_file(filename, false))
return false;
for (int i = 0; i < 3; ++i)
{
m_grabbers.push_back(Grabber());
}
return true;
}
void GLGizmoMove3D::on_start_dragging(const BoundingBoxf3& box)
{
if (m_hover_id != -1)
{
m_starting_drag_position = m_grabbers[m_hover_id].center;
m_starting_box_center = box.center();
}
}
void GLGizmoMove3D::on_update(const Linef3& mouse_ray)
{
if (m_hover_id == 0)
m_position(0) = 2.0 * m_starting_box_center(0) + calc_displacement(1, mouse_ray) - m_starting_drag_position(0);
else if (m_hover_id == 1)
m_position(1) = 2.0 * m_starting_box_center(1) + calc_displacement(2, mouse_ray) - m_starting_drag_position(1);
else if (m_hover_id == 2)
m_position(2) = 2.0 * m_starting_box_center(2) + calc_displacement(1, mouse_ray) - m_starting_drag_position(2);
}
void GLGizmoMove3D::on_render(const BoundingBoxf3& box) const
{
if (m_grabbers[0].dragging)
set_tooltip("X: " + format(m_position(0), 2));
else if (m_grabbers[1].dragging)
set_tooltip("Y: " + format(m_position(1), 2));
else if (m_grabbers[2].dragging)
set_tooltip("Z: " + format(m_position(2), 2));
::glEnable(GL_DEPTH_TEST);
const Vec3d& center = box.center();
// x axis
m_grabbers[0].center = Vec3d(box.max(0) + Offset, center(1), center(2));
::memcpy((void*)m_grabbers[0].color, (const void*)&AXES_COLOR[0], 3 * sizeof(float));
// y axis
m_grabbers[1].center = Vec3d(center(0), box.max(1) + Offset, center(2));
::memcpy((void*)m_grabbers[1].color, (const void*)&AXES_COLOR[1], 3 * sizeof(float));
// z axis
m_grabbers[2].center = Vec3d(center(0), center(1), box.max(2) + Offset);
::memcpy((void*)m_grabbers[2].color, (const void*)&AXES_COLOR[2], 3 * sizeof(float));
::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f);
if (m_hover_id == -1)
{
// draw axes
for (unsigned int i = 0; i < 3; ++i)
{
if (m_grabbers[i].enabled)
{
::glColor3fv(AXES_COLOR[i]);
::glBegin(GL_LINES);
::glVertex3f(center(0), center(1), center(2));
::glVertex3f((GLfloat)m_grabbers[i].center(0), (GLfloat)m_grabbers[i].center(1), (GLfloat)m_grabbers[i].center(2));
::glEnd();
}
}
// draw grabbers
render_grabbers(box);
}
else
{
// draw axis
::glColor3fv(AXES_COLOR[m_hover_id]);
::glBegin(GL_LINES);
::glVertex3f(center(0), center(1), center(2));
::glVertex3f((GLfloat)m_grabbers[m_hover_id].center(0), (GLfloat)m_grabbers[m_hover_id].center(1), (GLfloat)m_grabbers[m_hover_id].center(2));
::glEnd();
// draw grabber
m_grabbers[m_hover_id].render(true, box);
}
}
void GLGizmoMove3D::on_render_for_picking(const BoundingBoxf3& box) const
{
::glDisable(GL_DEPTH_TEST);
render_grabbers_for_picking(box);
}
double GLGizmoMove3D::calc_displacement(unsigned int preferred_plane_id, const Linef3& mouse_ray) const
{
double displacement = 0.0;
Vec3d starting_vec = m_starting_drag_position - m_starting_box_center;
double len_starting_vec = starting_vec.norm();
if (len_starting_vec == 0.0)
return displacement;
Vec3d starting_vec_dir = starting_vec.normalized();
Vec3d mouse_dir = mouse_ray.unit_vector();
unsigned int plane_id = select_best_plane(mouse_dir, preferred_plane_id);
switch (plane_id)
{
case 0:
{
displacement = starting_vec_dir.dot(intersection_on_plane_xy(mouse_ray, m_starting_box_center));
break;
}
case 1:
{
displacement = starting_vec_dir.dot(intersection_on_plane_xz(mouse_ray, m_starting_box_center));
break;
}
case 2:
{
displacement = starting_vec_dir.dot(intersection_on_plane_yz(mouse_ray, m_starting_box_center));
break;
}
}
return displacement;
}
GLGizmoFlatten::GLGizmoFlatten(GLCanvas3D& parent) GLGizmoFlatten::GLGizmoFlatten(GLCanvas3D& parent)
: GLGizmoBase(parent) : GLGizmoBase(parent)
, m_normal(0.0, 0.0, 0.0) , m_normal(Vec3d::Zero())
, m_starting_center(Vec3d::Zero())
{ {
} }
@ -1012,10 +1207,13 @@ bool GLGizmoFlatten::on_init()
return true; return true;
} }
void GLGizmoFlatten::on_start_dragging() void GLGizmoFlatten::on_start_dragging(const BoundingBoxf3& box)
{ {
if (m_hover_id != -1) if (m_hover_id != -1)
{
m_normal = m_planes[m_hover_id].normal; m_normal = m_planes[m_hover_id].normal;
m_starting_center = box.center();
}
} }
void GLGizmoFlatten::on_render(const BoundingBoxf3& box) const void GLGizmoFlatten::on_render(const BoundingBoxf3& box) const
@ -1023,10 +1221,9 @@ void GLGizmoFlatten::on_render(const BoundingBoxf3& box) const
// the dragged_offset is a vector measuring where was the object moved // the dragged_offset is a vector measuring where was the object moved
// with the gizmo being on. This is reset in set_flattening_data and // with the gizmo being on. This is reset in set_flattening_data and
// does not work correctly when there are multiple copies. // does not work correctly when there are multiple copies.
if (!m_center) // this is the first bounding box that we see Vec3d dragged_offset(Vec3d::Zero());
m_center.reset(new Vec3d(box.center())); if (m_dragging)
dragged_offset = box.center() - m_starting_center;
Vec3d dragged_offset = box.center() - *m_center;
::glEnable(GL_BLEND); ::glEnable(GL_BLEND);
::glEnable(GL_DEPTH_TEST); ::glEnable(GL_DEPTH_TEST);
@ -1073,7 +1270,6 @@ void GLGizmoFlatten::on_render_for_picking(const BoundingBoxf3& box) const
void GLGizmoFlatten::set_flattening_data(const ModelObject* model_object) void GLGizmoFlatten::set_flattening_data(const ModelObject* model_object)
{ {
m_center.release(); // object is not being dragged (this would not be called otherwise) - we must forget about the bounding box position...
m_model_object = model_object; m_model_object = model_object;
// ...and save the updated positions of the object instances: // ...and save the updated positions of the object instances:

View File

@ -22,21 +22,23 @@ class GLGizmoBase
protected: protected:
struct Grabber struct Grabber
{ {
static const float HalfSize; static const float SizeFactor;
static const float MinHalfSize;
static const float DraggingScaleFactor; static const float DraggingScaleFactor;
Vec3d center; Vec3d center;
Vec3d angles; Vec3d angles;
float color[3]; float color[3];
bool enabled;
bool dragging; bool dragging;
Grabber(); Grabber();
void render(bool hover) const; void render(bool hover, const BoundingBoxf3& box) const;
void render_for_picking() const { render(color, false); } void render_for_picking(const BoundingBoxf3& box) const { render(box, color, false); }
private: private:
void render(const float* render_color, bool use_lighting) const; void render(const BoundingBoxf3& box, const float* render_color, bool use_lighting) const;
void render_face(float half_size) const; void render_face(float half_size) const;
}; };
@ -57,6 +59,7 @@ protected:
// textures are assumed to be square and all with the same size in pixels, no internal check is done // textures are assumed to be square and all with the same size in pixels, no internal check is done
GLTexture m_textures[Num_States]; GLTexture m_textures[Num_States];
int m_hover_id; int m_hover_id;
bool m_dragging;
float m_base_color[3]; float m_base_color[3];
float m_drag_color[3]; float m_drag_color[3];
float m_highlight_color[3]; float m_highlight_color[3];
@ -79,13 +82,17 @@ public:
int get_hover_id() const { return m_hover_id; } int get_hover_id() const { return m_hover_id; }
void set_hover_id(int id); void set_hover_id(int id);
void set_highlight_color(const float* color); void set_highlight_color(const float* color);
void start_dragging(); void enable_grabber(unsigned int id);
void disable_grabber(unsigned int id);
void start_dragging(const BoundingBoxf3& box);
void stop_dragging(); void stop_dragging();
bool is_dragging() const { return m_dragging; }
void update(const Linef3& mouse_ray); void update(const Linef3& mouse_ray);
void refresh() { on_refresh(); }
void render(const BoundingBoxf3& box) const { on_render(box); } void render(const BoundingBoxf3& box) const { on_render(box); }
void render_for_picking(const BoundingBoxf3& box) const { on_render_for_picking(box); } void render_for_picking(const BoundingBoxf3& box) const { on_render_for_picking(box); }
@ -94,16 +101,17 @@ protected:
virtual bool on_init() = 0; virtual bool on_init() = 0;
virtual void on_set_state() {} virtual void on_set_state() {}
virtual void on_set_hover_id() {} virtual void on_set_hover_id() {}
virtual void on_start_dragging() {} virtual void on_enable_grabber(unsigned int id) {}
virtual void on_disable_grabber(unsigned int id) {}
virtual void on_start_dragging(const BoundingBoxf3& box) {}
virtual void on_stop_dragging() {} virtual void on_stop_dragging() {}
virtual void on_update(const Linef3& mouse_ray) = 0; virtual void on_update(const Linef3& mouse_ray) = 0;
virtual void on_refresh() {}
virtual void on_render(const BoundingBoxf3& box) const = 0; virtual void on_render(const BoundingBoxf3& box) const = 0;
virtual void on_render_for_picking(const BoundingBoxf3& box) const = 0; virtual void on_render_for_picking(const BoundingBoxf3& box) const = 0;
float picking_color_component(unsigned int id) const; float picking_color_component(unsigned int id) const;
void render_grabbers() const; void render_grabbers(const BoundingBoxf3& box) const;
void render_grabbers_for_picking() const; void render_grabbers_for_picking(const BoundingBoxf3& box) const;
void set_tooltip(const std::string& tooltip) const; void set_tooltip(const std::string& tooltip) const;
std::string format(float value, unsigned int decimals) const; std::string format(float value, unsigned int decimals) const;
@ -136,7 +144,6 @@ private:
mutable Vec3d m_center; mutable Vec3d m_center;
mutable float m_radius; mutable float m_radius;
mutable bool m_keep_initial_values;
public: public:
GLGizmoRotate(GLCanvas3D& parent, Axis axis); GLGizmoRotate(GLCanvas3D& parent, Axis axis);
@ -146,9 +153,8 @@ public:
protected: protected:
virtual bool on_init(); virtual bool on_init();
virtual void on_set_state() { m_keep_initial_values = (m_state == On) ? false : true; } virtual void on_start_dragging(const BoundingBoxf3& box);
virtual void on_update(const Linef3& mouse_ray); virtual void on_update(const Linef3& mouse_ray);
virtual void on_refresh() { m_keep_initial_values = false; }
virtual void on_render(const BoundingBoxf3& box) const; virtual void on_render(const BoundingBoxf3& box) const;
virtual void on_render_for_picking(const BoundingBoxf3& box) const; virtual void on_render_for_picking(const BoundingBoxf3& box) const;
@ -158,7 +164,7 @@ private:
void render_snap_radii() const; void render_snap_radii() const;
void render_reference_radius() const; void render_reference_radius() const;
void render_angle() const; void render_angle() const;
void render_grabber() const; void render_grabber(const BoundingBoxf3& box) const;
void transform_to_local() const; void transform_to_local() const;
// returns the intersection of the mouse ray with the plane perpendicular to the gizmo axis, in local coordinate // returns the intersection of the mouse ray with the plane perpendicular to the gizmo axis, in local coordinate
@ -167,56 +173,62 @@ private:
class GLGizmoRotate3D : public GLGizmoBase class GLGizmoRotate3D : public GLGizmoBase
{ {
GLGizmoRotate m_x; std::vector<GLGizmoRotate> m_gizmos;
GLGizmoRotate m_y;
GLGizmoRotate m_z;
public: public:
explicit GLGizmoRotate3D(GLCanvas3D& parent); explicit GLGizmoRotate3D(GLCanvas3D& parent);
double get_angle_x() const { return m_x.get_angle(); } double get_angle_x() const { return m_gizmos[X].get_angle(); }
void set_angle_x(double angle) { m_x.set_angle(angle); } void set_angle_x(double angle) { m_gizmos[X].set_angle(angle); }
double get_angle_y() const { return m_y.get_angle(); } double get_angle_y() const { return m_gizmos[Y].get_angle(); }
void set_angle_y(double angle) { m_y.set_angle(angle); } void set_angle_y(double angle) { m_gizmos[Y].set_angle(angle); }
double get_angle_z() const { return m_z.get_angle(); } double get_angle_z() const { return m_gizmos[Z].get_angle(); }
void set_angle_z(double angle) { m_z.set_angle(angle); } void set_angle_z(double angle) { m_gizmos[Z].set_angle(angle); }
protected: protected:
virtual bool on_init(); virtual bool on_init();
virtual void on_set_state() virtual void on_set_state()
{ {
m_x.set_state(m_state); for (GLGizmoRotate& g : m_gizmos)
m_y.set_state(m_state); {
m_z.set_state(m_state); g.set_state(m_state);
}
} }
virtual void on_set_hover_id() virtual void on_set_hover_id()
{ {
m_x.set_hover_id(m_hover_id == 0 ? 0 : -1); for (unsigned int i = 0; i < 3; ++i)
m_y.set_hover_id(m_hover_id == 1 ? 0 : -1); {
m_z.set_hover_id(m_hover_id == 2 ? 0 : -1); m_gizmos[i].set_hover_id((m_hover_id == i) ? 0 : -1);
}
} }
virtual void on_start_dragging(); virtual void on_enable_grabber(unsigned int id)
{
if ((0 <= id) && (id < 3))
m_gizmos[id].enable_grabber(0);
}
virtual void on_disable_grabber(unsigned int id)
{
if ((0 <= id) && (id < 3))
m_gizmos[id].disable_grabber(0);
}
virtual void on_start_dragging(const BoundingBoxf3& box);
virtual void on_stop_dragging(); virtual void on_stop_dragging();
virtual void on_update(const Linef3& mouse_ray) virtual void on_update(const Linef3& mouse_ray)
{ {
m_x.update(mouse_ray); for (GLGizmoRotate& g : m_gizmos)
m_y.update(mouse_ray); {
m_z.update(mouse_ray); g.update(mouse_ray);
} }
virtual void on_refresh()
{
m_x.refresh();
m_y.refresh();
m_z.refresh();
} }
virtual void on_render(const BoundingBoxf3& box) const; virtual void on_render(const BoundingBoxf3& box) const;
virtual void on_render_for_picking(const BoundingBoxf3& box) const virtual void on_render_for_picking(const BoundingBoxf3& box) const
{ {
m_x.render_for_picking(box); for (const GLGizmoRotate& g : m_gizmos)
m_y.render_for_picking(box); {
m_z.render_for_picking(box); g.render_for_picking(box);
}
} }
}; };
@ -249,7 +261,7 @@ public:
protected: protected:
virtual bool on_init(); virtual bool on_init();
virtual void on_start_dragging(); virtual void on_start_dragging(const BoundingBoxf3& box);
virtual void on_stop_dragging() { m_show_starting_box = false; } virtual void on_stop_dragging() { m_show_starting_box = false; }
virtual void on_update(const Linef3& mouse_ray); virtual void on_update(const Linef3& mouse_ray);
virtual void on_render(const BoundingBoxf3& box) const; virtual void on_render(const BoundingBoxf3& box) const;
@ -267,6 +279,31 @@ private:
double calc_ratio(unsigned int preferred_plane_id, const Linef3& mouse_ray, const Vec3d& center) const; double calc_ratio(unsigned int preferred_plane_id, const Linef3& mouse_ray, const Vec3d& center) const;
}; };
class GLGizmoMove3D : public GLGizmoBase
{
static const double Offset;
Vec3d m_position;
Vec3d m_starting_drag_position;
Vec3d m_starting_box_center;
public:
explicit GLGizmoMove3D(GLCanvas3D& parent);
const Vec3d& get_position() const { return m_position; }
void set_position(const Vec3d& position) { m_position = position; }
protected:
virtual bool on_init();
virtual void on_start_dragging(const BoundingBoxf3& box);
virtual void on_update(const Linef3& mouse_ray);
virtual void on_render(const BoundingBoxf3& box) const;
virtual void on_render_for_picking(const BoundingBoxf3& box) const;
private:
double calc_displacement(unsigned int preferred_plane_id, const Linef3& mouse_ray) const;
};
class GLGizmoFlatten : public GLGizmoBase class GLGizmoFlatten : public GLGizmoBase
{ {
// This gizmo does not use grabbers. The m_hover_id relates to polygon managed by the class itself. // This gizmo does not use grabbers. The m_hover_id relates to polygon managed by the class itself.
@ -291,7 +328,7 @@ private:
std::vector<PlaneData> m_planes; std::vector<PlaneData> m_planes;
std::vector<Vec2d> m_instances_positions; std::vector<Vec2d> m_instances_positions;
mutable std::unique_ptr<Vec3d> m_center = nullptr; Vec3d m_starting_center;
const ModelObject* m_model_object = nullptr; const ModelObject* m_model_object = nullptr;
void update_planes(); void update_planes();
@ -305,11 +342,12 @@ public:
protected: protected:
virtual bool on_init(); virtual bool on_init();
virtual void on_start_dragging(); virtual void on_start_dragging(const BoundingBoxf3& box);
virtual void on_update(const Linef3& mouse_ray) {} virtual void on_update(const Linef3& mouse_ray) {}
virtual void on_render(const BoundingBoxf3& box) const; virtual void on_render(const BoundingBoxf3& box) const;
virtual void on_render_for_picking(const BoundingBoxf3& box) const; virtual void on_render_for_picking(const BoundingBoxf3& box) const;
virtual void on_set_state() { virtual void on_set_state()
{
if (m_state == On && is_plane_update_necessary()) if (m_state == On && is_plane_update_necessary())
update_planes(); update_planes();
} }

View File

@ -651,6 +651,13 @@ register_on_gizmo_rotate_callback(canvas, callback)
CODE: CODE:
_3DScene::register_on_gizmo_rotate_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback); _3DScene::register_on_gizmo_rotate_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback);
void
register_on_gizmo_flatten_callback(canvas, callback)
SV *canvas;
SV *callback;
CODE:
_3DScene::register_on_gizmo_flatten_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback);
void void
register_on_update_geometry_info_callback(canvas, callback) register_on_update_geometry_info_callback(canvas, callback)
SV *canvas; SV *canvas;