From 62e60bcb43dcf147596b5ae466afb6c04e6bcb2a Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Wed, 15 Jan 2020 12:49:34 +0100 Subject: [PATCH 1/6] Six degrees of freedom camera - 1st installment --- src/libslic3r/Technologies.hpp | 2 + src/slic3r/GUI/3DBed.cpp | 14 +++ src/slic3r/GUI/3DBed.hpp | 4 + src/slic3r/GUI/Camera.cpp | 144 ++++++++++++++++++++++++++- src/slic3r/GUI/Camera.hpp | 37 ++++++- src/slic3r/GUI/GLCanvas3D.cpp | 31 ++++++ src/slic3r/GUI/Mouse3DController.cpp | 11 ++ src/slic3r/GUI/Selection.cpp | 4 + 8 files changed, 245 insertions(+), 2 deletions(-) diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index 23c516a34..401946b94 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -74,5 +74,7 @@ // Enable configurable paths export (fullpath or not) to 3mf and amf #define ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF (1 && ENABLE_2_2_0_BETA1) +// Enable 6 degrees of freedom camera +#define ENABLE_6DOF_CAMERA (1 && ENABLE_2_2_0_BETA1) #endif // _technologies_h_ diff --git a/src/slic3r/GUI/3DBed.cpp b/src/slic3r/GUI/3DBed.cpp index c66c8efdd..698dbbc05 100644 --- a/src/slic3r/GUI/3DBed.cpp +++ b/src/slic3r/GUI/3DBed.cpp @@ -262,7 +262,11 @@ Point Bed3D::point_projection(const Point& point) const return m_polygon.point_projection(point); } +#if ENABLE_6DOF_CAMERA +void Bed3D::render(GLCanvas3D& canvas, bool bottom, float scale_factor, bool show_axes) const +#else void Bed3D::render(GLCanvas3D& canvas, float theta, float scale_factor, bool show_axes) const +#endif // ENABLE_6DOF_CAMERA { m_scale_factor = scale_factor; @@ -273,6 +277,15 @@ void Bed3D::render(GLCanvas3D& canvas, float theta, float scale_factor, bool sho switch (m_type) { +#if ENABLE_6DOF_CAMERA + case MK2: { render_prusa(canvas, "mk2", bottom); break; } + case MK3: { render_prusa(canvas, "mk3", bottom); break; } + case SL1: { render_prusa(canvas, "sl1", bottom); break; } + case MINI: { render_prusa(canvas, "mini", bottom); break; } + case ENDER3: { render_prusa(canvas, "ender3", bottom); break; } + default: + case Custom: { render_custom(canvas, bottom); break; } +#else case MK2: { render_prusa(canvas, "mk2", theta > 90.0f); break; } case MK3: { render_prusa(canvas, "mk3", theta > 90.0f); break; } case SL1: { render_prusa(canvas, "sl1", theta > 90.0f); break; } @@ -280,6 +293,7 @@ void Bed3D::render(GLCanvas3D& canvas, float theta, float scale_factor, bool sho case ENDER3: { render_prusa(canvas, "ender3", theta > 90.0f); break; } default: case Custom: { render_custom(canvas, theta > 90.0f); break; } +#endif // ENABLE_6DOF_CAMERA } glsafe(::glDisable(GL_DEPTH_TEST)); diff --git a/src/slic3r/GUI/3DBed.hpp b/src/slic3r/GUI/3DBed.hpp index cd2de862e..c1d3fdce7 100644 --- a/src/slic3r/GUI/3DBed.hpp +++ b/src/slic3r/GUI/3DBed.hpp @@ -110,7 +110,11 @@ public: bool contains(const Point& point) const; Point point_projection(const Point& point) const; +#if ENABLE_6DOF_CAMERA + void render(GLCanvas3D& canvas, bool bottom, float scale_factor, bool show_axes) const; +#else void render(GLCanvas3D& canvas, float theta, float scale_factor, bool show_axes) const; +#endif // ENABLE_6DOF_CAMERA private: void calc_bounding_boxes() const; diff --git a/src/slic3r/GUI/Camera.cpp b/src/slic3r/GUI/Camera.cpp index fa7a3be21..b22d27326 100644 --- a/src/slic3r/GUI/Camera.cpp +++ b/src/slic3r/GUI/Camera.cpp @@ -34,18 +34,27 @@ double Camera::FrustrumZMargin = 10.0; double Camera::MaxFovDeg = 60.0; Camera::Camera() +#if ENABLE_6DOF_CAMERA + : requires_zoom_to_bed(false) +#else : phi(45.0f) , requires_zoom_to_bed(false) , inverted_phi(false) +#endif // ENABLE_6DOF_CAMERA , m_type(Perspective) , m_target(Vec3d::Zero()) +#if !ENABLE_6DOF_CAMERA , m_theta(45.0f) +#endif // !ENABLE_6DOF_CAMERA , m_zoom(1.0) , m_distance(DefaultDistance) , m_gui_scale(1.0) , m_view_matrix(Transform3d::Identity()) , m_projection_matrix(Transform3d::Identity()) { +#if ENABLE_6DOF_CAMERA + set_default_orientation(); +#endif // ENABLE_6DOF_CAMERA } std::string Camera::get_type_as_string() const @@ -91,6 +100,9 @@ void Camera::select_next_type() void Camera::set_target(const Vec3d& target) { +#if ENABLE_6DOF_CAMERA + translate_world(target - m_target); +#else BoundingBoxf3 test_box = m_scene_box; test_box.translate(-m_scene_box.center()); // We may let this factor be customizable @@ -101,8 +113,10 @@ void Camera::set_target(const Vec3d& target) m_target(0) = clamp(test_box.min(0), test_box.max(0), target(0)); m_target(1) = clamp(test_box.min(1), test_box.max(1), target(1)); m_target(2) = clamp(test_box.min(2), test_box.max(2), target(2)); +#endif // ENABLE_6DOF_CAMERA } +#if !ENABLE_6DOF_CAMERA void Camera::set_theta(float theta, bool apply_limit) { if (apply_limit) @@ -114,6 +128,7 @@ void Camera::set_theta(float theta, bool apply_limit) m_theta += 360.0f; } } +#endif // !ENABLE_6DOF_CAMERA void Camera::update_zoom(double delta_zoom) { @@ -130,7 +145,25 @@ void Camera::set_zoom(double zoom) // Don't allow to zoom too close to the scene. m_zoom = std::min(zoom, 100.0); } - +#if ENABLE_6DOF_CAMERA +void Camera::select_view(const std::string& direction) +{ + if (direction == "iso") + set_default_orientation(); + else if (direction == "left") + m_view_matrix = look_at(m_target - m_distance * Vec3d::UnitX(), m_target, Vec3d::UnitZ()); + else if (direction == "right") + m_view_matrix = look_at(m_target + m_distance * Vec3d::UnitX(), m_target, Vec3d::UnitZ()); + else if (direction == "top") + m_view_matrix = look_at(m_target + m_distance * Vec3d::UnitZ(), m_target, Vec3d::UnitY()); + else if (direction == "bottom") + m_view_matrix = look_at(m_target - m_distance * Vec3d::UnitZ(), m_target, -Vec3d::UnitY()); + else if (direction == "front") + m_view_matrix = look_at(m_target - m_distance * Vec3d::UnitY(), m_target, Vec3d::UnitZ()); + else if (direction == "rear") + m_view_matrix = look_at(m_target + m_distance * Vec3d::UnitY(), m_target, Vec3d::UnitZ()); +} +#else bool Camera::select_view(const std::string& direction) { const float* dir_vec = nullptr; @@ -159,6 +192,7 @@ bool Camera::select_view(const std::string& direction) else return false; } +#endif // ENABLE_6DOF_CAMERA double Camera::get_fov() const { @@ -180,20 +214,26 @@ void Camera::apply_viewport(int x, int y, unsigned int w, unsigned int h) const void Camera::apply_view_matrix() const { +#if !ENABLE_6DOF_CAMERA double theta_rad = Geometry::deg2rad(-(double)m_theta); double phi_rad = Geometry::deg2rad((double)phi); double sin_theta = ::sin(theta_rad); Vec3d camera_pos = m_target + m_distance * Vec3d(sin_theta * ::sin(phi_rad), sin_theta * ::cos(phi_rad), ::cos(theta_rad)); +#endif // !ENABLE_6DOF_CAMERA glsafe(::glMatrixMode(GL_MODELVIEW)); glsafe(::glLoadIdentity()); +#if ENABLE_6DOF_CAMERA + glsafe(::glMultMatrixd(m_view_matrix.data())); +#else glsafe(::glRotatef(-m_theta, 1.0f, 0.0f, 0.0f)); // pitch glsafe(::glRotatef(phi, 0.0f, 0.0f, 1.0f)); // yaw glsafe(::glTranslated(-camera_pos(0), -camera_pos(1), -camera_pos(2))); glsafe(::glGetDoublev(GL_MODELVIEW_MATRIX, m_view_matrix.data())); +#endif // ENABLE_6DOF_CAMERA } void Camera::apply_projection(const BoundingBoxf3& box, double near_z, double far_z) const @@ -300,7 +340,11 @@ void Camera::zoom_to_box(const BoundingBoxf3& box, int canvas_w, int canvas_h) { m_zoom = zoom; // center view around box center +#if ENABLE_6DOF_CAMERA + set_target(box.center()); +#else m_target = box.center(); +#endif // ENABLE_6DOF_CAMERA } } @@ -313,7 +357,11 @@ void Camera::zoom_to_volumes(const GLVolumePtrs& volumes, int canvas_w, int canv { m_zoom = zoom; // center view around the calculated center +#if ENABLE_6DOF_CAMERA + set_target(center); +#else m_target = center; +#endif // ENABLE_6DOF_CAMERA } } #endif // ENABLE_THUMBNAIL_GENERATOR @@ -360,6 +408,43 @@ void Camera::debug_render() const } #endif // ENABLE_CAMERA_STATISTICS +#if ENABLE_6DOF_CAMERA +void Camera::translate_world(const Vec3d& displacement) +{ + Vec3d new_target = validate_target(m_target + displacement); + Vec3d new_displacement = new_target - m_target; + if (!new_displacement.isApprox(Vec3d::Zero())) + { + m_target += new_displacement; + m_view_matrix.translate(-new_displacement); + } +} + +void Camera::rotate_on_sphere(double delta_azimut_rad, double delta_zenit_rad, bool apply_limit) +{ + Vec3d target = m_target; + translate_world(-target); + m_view_matrix.rotate(Eigen::AngleAxisd(delta_zenit_rad, get_dir_right())); + m_view_matrix.rotate(Eigen::AngleAxisd(delta_azimut_rad, Vec3d::UnitZ())); + translate_world(target); +} + +void Camera::rotate_local_around_target(const Vec3d& rotation_rad) +{ + Vec3d target = m_target; + translate_world(-target); + m_view_matrix.rotate(Eigen::AngleAxisd(rotation_rad(0), get_dir_right())); + m_view_matrix.rotate(Eigen::AngleAxisd(rotation_rad(1), get_dir_up())); + m_view_matrix.rotate(Eigen::AngleAxisd(rotation_rad(2), get_dir_forward())); + translate_world(target); +} + +bool Camera::is_looking_downward() const +{ + return get_dir_forward().dot(Vec3d::UnitZ()) < 0.0; +} +#endif // ENABLE_6DOF_CAMERA + std::pair Camera::calc_tight_frustrum_zs_around(const BoundingBoxf3& box) const { std::pair ret; @@ -540,6 +625,63 @@ void Camera::set_distance(double distance) const apply_view_matrix(); } +#if ENABLE_6DOF_CAMERA +Transform3d Camera::look_at(const Vec3d& position, const Vec3d& target, const Vec3d& up) const +{ + Vec3d unit_z = (position - target).normalized(); + Vec3d unit_x = up.cross(unit_z).normalized(); + Vec3d unit_y = unit_z.cross(unit_x).normalized(); + + Transform3d matrix; + + matrix(0, 0) = unit_x(0); + matrix(0, 1) = unit_x(1); + matrix(0, 2) = unit_x(2); + matrix(0, 3) = -unit_x.dot(position); + + matrix(1, 0) = unit_y(0); + matrix(1, 1) = unit_y(1); + matrix(1, 2) = unit_y(2); + matrix(1, 3) = -unit_y.dot(position); + + matrix(2, 0) = unit_z(0); + matrix(2, 1) = unit_z(1); + matrix(2, 2) = unit_z(2); + matrix(2, 3) = -unit_z.dot(position); + + matrix(3, 0) = 0.0; + matrix(3, 1) = 0.0; + matrix(3, 2) = 0.0; + matrix(3, 3) = 1.0; + + return matrix; +} + +void Camera::set_default_orientation() +{ + double theta_rad = Geometry::deg2rad(-45.0); + double phi_rad = Geometry::deg2rad(45.0); + double sin_theta = ::sin(theta_rad); + Vec3d camera_pos = m_target + m_distance * Vec3d(sin_theta * ::sin(phi_rad), sin_theta * ::cos(phi_rad), ::cos(theta_rad)); + m_view_matrix = Transform3d::Identity(); + m_view_matrix.rotate(Eigen::AngleAxisd(theta_rad, Vec3d::UnitX())).rotate(Eigen::AngleAxisd(phi_rad, Vec3d::UnitZ())).translate(-camera_pos); +} + +Vec3d Camera::validate_target(const Vec3d& target) const +{ + BoundingBoxf3 test_box = m_scene_box; + test_box.translate(-m_scene_box.center()); + // We may let this factor be customizable + static const double ScaleFactor = 1.5; + test_box.scale(ScaleFactor); + test_box.translate(m_scene_box.center()); + + return Vec3d(std::clamp(target(0), test_box.min(0), test_box.max(0)), + std::clamp(target(1), test_box.min(1), test_box.max(1)), + std::clamp(target(2), test_box.min(2), test_box.max(2))); +} +#endif // ENABLE_6DOF_CAMERA + } // GUI } // Slic3r diff --git a/src/slic3r/GUI/Camera.hpp b/src/slic3r/GUI/Camera.hpp index 6cd1b75a5..cfb0fd797 100644 --- a/src/slic3r/GUI/Camera.hpp +++ b/src/slic3r/GUI/Camera.hpp @@ -30,21 +30,29 @@ struct Camera Num_types }; +#if !ENABLE_6DOF_CAMERA float phi; - bool requires_zoom_to_bed; bool inverted_phi; +#endif // !ENABLE_6DOF_CAMERA + bool requires_zoom_to_bed; private: EType m_type; Vec3d m_target; +#if !ENABLE_6DOF_CAMERA float m_theta; +#endif // !ENABLE_6DOF_CAMERA double m_zoom; // Distance between camera position and camera target measured along the camera Z axis mutable double m_distance; mutable double m_gui_scale; mutable std::array m_viewport; +#if ENABLE_6DOF_CAMERA + Transform3d m_view_matrix; +#else mutable Transform3d m_view_matrix; +#endif // ENABLE_6DOF_CAMERA mutable Transform3d m_projection_matrix; mutable std::pair m_frustrum_zs; @@ -66,8 +74,10 @@ public: double get_distance() const { return m_distance; } double get_gui_scale() const { return m_gui_scale; } +#if !ENABLE_6DOF_CAMERA float get_theta() const { return m_theta; } void set_theta(float theta, bool apply_limit); +#endif // !ENABLE_6DOF_CAMERA double get_zoom() const { return m_zoom; } void update_zoom(double delta_zoom); @@ -76,7 +86,11 @@ public: const BoundingBoxf3& get_scene_box() const { return m_scene_box; } void set_scene_box(const BoundingBoxf3& box) { m_scene_box = box; } +#if ENABLE_6DOF_CAMERA + void select_view(const std::string& direction); +#else bool select_view(const std::string& direction); +#endif // ENABLE_6DOF_CAMERA const std::array& get_viewport() const { return m_viewport; } const Transform3d& get_view_matrix() const { return m_view_matrix; } @@ -110,6 +124,21 @@ public: void debug_render() const; #endif // ENABLE_CAMERA_STATISTICS +#if ENABLE_6DOF_CAMERA + // translate the camera in world space + void translate_world(const Vec3d& displacement); + + // rotate the camera on a sphere having center == m_target and radius == m_distance + // using the given variations of spherical coordinates + void rotate_on_sphere(double delta_azimut_rad, double delta_zenit_rad, bool apply_limit); + + // rotate the camera around three axes parallel to the camera local axes and passing through m_target + void rotate_local_around_target(const Vec3d& rotation_rad); + + // returns true if the camera z axis (forward) is pointing in the negative direction of the world z axis + bool is_looking_downward() const; +#endif // ENABLE_6DOF_CAMERA + private: // returns tight values for nearZ and farZ plane around the given bounding box // the camera MUST be outside of the bounding box in eye coordinate of the given box @@ -121,6 +150,12 @@ private: double calc_zoom_to_bounding_box_factor(const BoundingBoxf3& box, int canvas_w, int canvas_h) const; #endif // ENABLE_THUMBNAIL_GENERATOR void set_distance(double distance) const; + +#if ENABLE_6DOF_CAMERA + Transform3d look_at(const Vec3d& position, const Vec3d& target, const Vec3d& up) const; + void set_default_orientation(); + Vec3d validate_target(const Vec3d& target) const; +#endif // ENABLE_6DOF_CAMERA }; } // GUI diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index d2428cf96..860eab0fb 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1792,8 +1792,14 @@ void GLCanvas3D::zoom_to_selection() void GLCanvas3D::select_view(const std::string& direction) { +#if ENABLE_6DOF_CAMERA + m_camera.select_view(direction); + if (m_canvas != nullptr) + m_canvas->Refresh(); +#else if (m_camera.select_view(direction) && (m_canvas != nullptr)) m_canvas->Refresh(); +#endif // ENABLE_6DOF_CAMERA } void GLCanvas3D::update_volumes_colors_by_extruder() @@ -1850,10 +1856,12 @@ void GLCanvas3D::render() GLfloat position_top[4] = { -0.5f, -0.5f, 1.0f, 0.0f }; glsafe(::glLightfv(GL_LIGHT0, GL_POSITION, position_top)); +#if !ENABLE_6DOF_CAMERA float theta = m_camera.get_theta(); if (theta > 180.f) // absolute value of the rotation theta = 360.f - theta; +#endif // !ENABLE_6DOF_CAMERA wxGetApp().imgui()->new_frame(); @@ -1878,7 +1886,11 @@ void GLCanvas3D::render() _render_objects(); _render_sla_slices(); _render_selection(); +#if ENABLE_6DOF_CAMERA + _render_bed(!m_camera.is_looking_downward(), true); +#else _render_bed(theta, true); +#endif // ENABLE_6DOF_CAMERA #if ENABLE_RENDER_SELECTION_CENTER _render_selection_center(); @@ -3213,7 +3225,11 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) // we do not want to translate objects if the user just clicked on an object while pressing shift to remove it from the selection and then drag if (m_selection.contains_volume(get_first_hover_volume_idx())) { +#if ENABLE_6DOF_CAMERA + if (std::abs(m_camera.get_dir_forward()(2)) < EPSILON) +#else if (m_camera.get_theta() == 90.0f) +#endif // ENABLE_6DOF_CAMERA { // side view -> move selected volumes orthogonally to camera view direction Linef3 ray = mouse_ray(pos); @@ -3273,9 +3289,15 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) if (m_hover_volume_idxs.empty() && m_mouse.is_start_position_3D_defined()) { const Vec3d& orig = m_mouse.drag.start_position_3D; +#if ENABLE_6DOF_CAMERA + m_camera.rotate_on_sphere(Geometry::deg2rad((pos(0) - orig(0))* (double)TRACKBALLSIZE), + Geometry::deg2rad((pos(1) - orig(1))* (double)TRACKBALLSIZE), + wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA); +#else float sign = m_camera.inverted_phi ? -1.0f : 1.0f; m_camera.phi += sign * ((float)pos(0) - (float)orig(0)) * TRACKBALLSIZE; m_camera.set_theta(m_camera.get_theta() - ((float)pos(1) - (float)orig(1)) * TRACKBALLSIZE, wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA); +#endif // ENABLE_6DOF_CAMERA m_dirty = true; } m_mouse.drag.start_position_3D = Vec3d((double)pos(0), (double)pos(1), 0.0); @@ -3325,9 +3347,11 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) if (!evt.ShiftDown() && m_picking_enabled) deselect_all(); } +#if !ENABLE_6DOF_CAMERA else if (evt.LeftUp() && m_mouse.dragging) // Flips X mouse deltas if bed is upside down m_camera.inverted_phi = (m_camera.get_dir_up()(2) < 0.0); +#endif // !ENABLE_6DOF_CAMERA else if (evt.RightUp()) { m_mouse.position = pos.cast(); @@ -3932,6 +3956,9 @@ void GLCanvas3D::_render_thumbnail_internal(ThumbnailData& thumbnail_data, bool Camera camera; camera.set_type(Camera::Ortho); +#if ENABLE_6DOF_CAMERA + camera.set_scene_box(scene_bounding_box()); +#endif // ENABLE_6DOF_CAMERA camera.zoom_to_volumes(visible_volumes, thumbnail_data.width, thumbnail_data.height); camera.apply_viewport(0, 0, thumbnail_data.width, thumbnail_data.height); camera.apply_view_matrix(); @@ -3982,7 +4009,11 @@ void GLCanvas3D::_render_thumbnail_internal(ThumbnailData& thumbnail_data, bool glsafe(::glDisable(GL_DEPTH_TEST)); if (show_bed) +#if ENABLE_6DOF_CAMERA + _render_bed(!camera.is_looking_downward(), false); +#else _render_bed(camera.get_theta(), false); +#endif // ENABLE_6DOF_CAMERA if (transparent_background) glsafe(::glClearColor(1.0f, 1.0f, 1.0f, 1.0f)); diff --git a/src/slic3r/GUI/Mouse3DController.cpp b/src/slic3r/GUI/Mouse3DController.cpp index 8485c4b27..3dd12e021 100644 --- a/src/slic3r/GUI/Mouse3DController.cpp +++ b/src/slic3r/GUI/Mouse3DController.cpp @@ -168,12 +168,17 @@ bool Mouse3DController::State::apply(Camera& camera) if (has_rotation()) { +#if ENABLE_6DOF_CAMERA + Vec3d rotation = (m_rotation_params.scale * m_rotation.queue.front()).cast(); + camera.rotate_local_around_target(Vec3d(Geometry::deg2rad(rotation(0)), Geometry::deg2rad(-rotation(2)), Geometry::deg2rad(-rotation(1)))); +#else const Vec3f& rotation = m_rotation.queue.front(); float theta = m_rotation_params.scale * rotation(0); float phi = m_rotation_params.scale * rotation(2); float sign = camera.inverted_phi ? -1.0f : 1.0f; camera.phi += sign * phi; camera.set_theta(camera.get_theta() + theta, wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA); +#endif // ENABLE_6DOF_CAMERA m_rotation.queue.pop(); ret = true; } @@ -877,9 +882,15 @@ bool Mouse3DController::handle_packet_translation(const DataPacket& packet) bool Mouse3DController::handle_packet_rotation(const DataPacket& packet, unsigned int first_byte) { double deadzone = (double)m_state.get_rotation_deadzone(); +#if ENABLE_6DOF_CAMERA + Vec3f rotation((float)convert_input(packet[first_byte + 0], packet[first_byte + 1], deadzone), + (float)convert_input(packet[first_byte + 2], packet[first_byte + 3], deadzone), + (float)convert_input(packet[first_byte + 4], packet[first_byte + 5], deadzone)); +#else Vec3f rotation(-(float)convert_input(packet[first_byte + 0], packet[first_byte + 1], deadzone), (float)convert_input(packet[first_byte + 2], packet[first_byte + 3], deadzone), -(float)convert_input(packet[first_byte + 4], packet[first_byte + 5], deadzone)); +#endif // ENABLE_6DOF_CAMERA if (!rotation.isApprox(Vec3f::Zero())) { diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index 13be48289..224f5007d 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -2004,7 +2004,11 @@ void Selection::render_sidebar_layers_hints(const std::string& sidebar_field) co const float max_y = box.max(1) + Margin; // view dependend order of rendering to keep correct transparency +#if ENABLE_6DOF_CAMERA + bool camera_on_top = wxGetApp().plater()->get_camera().is_looking_downward(); +#else bool camera_on_top = wxGetApp().plater()->get_camera().get_theta() <= 90.0f; +#endif // ENABLE_6DOF_CAMERA float z1 = camera_on_top ? min_z : max_z; float z2 = camera_on_top ? max_z : min_z; From 9df7eb4e08872edcd9a47fc8fd3ef5d3cb8e29f6 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 16 Jan 2020 09:12:36 +0100 Subject: [PATCH 2/6] Customizable use of 6 dof camera --- src/slic3r/GUI/AppConfig.cpp | 5 +++++ src/slic3r/GUI/Camera.cpp | 13 ++++++++++++- src/slic3r/GUI/Camera.hpp | 2 +- src/slic3r/GUI/GLCanvas3D.cpp | 9 ++++++--- src/slic3r/GUI/Preferences.cpp | 9 +++++++++ 5 files changed, 33 insertions(+), 5 deletions(-) diff --git a/src/slic3r/GUI/AppConfig.cpp b/src/slic3r/GUI/AppConfig.cpp index d277fc095..12302a5dc 100644 --- a/src/slic3r/GUI/AppConfig.cpp +++ b/src/slic3r/GUI/AppConfig.cpp @@ -87,6 +87,11 @@ void AppConfig::set_defaults() if (get("use_perspective_camera").empty()) set("use_perspective_camera", "1"); +#if ENABLE_6DOF_CAMERA + if (get("use_free_camera").empty()) + set("use_free_camera", "0"); +#endif // ENABLE_6DOF_CAMERA + // Remove legacy window positions/sizes erase("", "main_frame_maximized"); erase("", "main_frame_pos"); diff --git a/src/slic3r/GUI/Camera.cpp b/src/slic3r/GUI/Camera.cpp index b22d27326..49246dbb9 100644 --- a/src/slic3r/GUI/Camera.cpp +++ b/src/slic3r/GUI/Camera.cpp @@ -6,6 +6,11 @@ #endif // !ENABLE_THUMBNAIL_GENERATOR #include "GUI_App.hpp" #include "AppConfig.hpp" +#if ENABLE_CAMERA_STATISTICS +#if ENABLE_6DOF_CAMERA +#include "Mouse3DController.hpp" +#endif // ENABLE_6DOF_CAMERA +#endif // ENABLE_CAMERA_STATISTICS #include @@ -373,6 +378,12 @@ void Camera::debug_render() const imgui.begin(std::string("Camera statistics"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); std::string type = get_type_as_string(); +#if ENABLE_6DOF_CAMERA + if (wxGetApp().plater()->get_mouse3d_controller().is_running() || (wxGetApp().app_config->get("use_free_camera") == "1")) + type += "/free"; + else + type += "/constrained"; +#endif // ENABLE_6DOF_CAMERA Vec3f position = get_position().cast(); Vec3f target = m_target.cast(); float distance = (float)get_distance(); @@ -420,7 +431,7 @@ void Camera::translate_world(const Vec3d& displacement) } } -void Camera::rotate_on_sphere(double delta_azimut_rad, double delta_zenit_rad, bool apply_limit) +void Camera::rotate_on_sphere(double delta_azimut_rad, double delta_zenit_rad) { Vec3d target = m_target; translate_world(-target); diff --git a/src/slic3r/GUI/Camera.hpp b/src/slic3r/GUI/Camera.hpp index cfb0fd797..67c97c0b4 100644 --- a/src/slic3r/GUI/Camera.hpp +++ b/src/slic3r/GUI/Camera.hpp @@ -130,7 +130,7 @@ public: // rotate the camera on a sphere having center == m_target and radius == m_distance // using the given variations of spherical coordinates - void rotate_on_sphere(double delta_azimut_rad, double delta_zenit_rad, bool apply_limit); + void rotate_on_sphere(double delta_azimut_rad, double delta_zenit_rad); // rotate the camera around three axes parallel to the camera local axes and passing through m_target void rotate_local_around_target(const Vec3d& rotation_rad); diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 860eab0fb..1c383841e 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -3290,9 +3290,12 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) { const Vec3d& orig = m_mouse.drag.start_position_3D; #if ENABLE_6DOF_CAMERA - m_camera.rotate_on_sphere(Geometry::deg2rad((pos(0) - orig(0))* (double)TRACKBALLSIZE), - Geometry::deg2rad((pos(1) - orig(1))* (double)TRACKBALLSIZE), - wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA); + double x = Geometry::deg2rad(pos(0) - orig(0)) * (double)TRACKBALLSIZE; + double y = Geometry::deg2rad(pos(1) - orig(1)) * (double)TRACKBALLSIZE; + if (wxGetApp().plater()->get_mouse3d_controller().is_running() || (wxGetApp().app_config->get("use_free_camera") == "1")) + m_camera.rotate_local_around_target(Vec3d(y, x, 0.0)); + else + m_camera.rotate_on_sphere(x, y); #else float sign = m_camera.inverted_phi ? -1.0f : 1.0f; m_camera.phi += sign * ((float)pos(0) - (float)orig(0)) * TRACKBALLSIZE; diff --git a/src/slic3r/GUI/Preferences.cpp b/src/slic3r/GUI/Preferences.cpp index 295c1a6ec..d0686677d 100644 --- a/src/slic3r/GUI/Preferences.cpp +++ b/src/slic3r/GUI/Preferences.cpp @@ -124,6 +124,15 @@ void PreferencesDialog::build() option = Option(def, "use_perspective_camera"); m_optgroup->append_single_option_line(option); +#if ENABLE_6DOF_CAMERA + def.label = L("Use free camera"); + def.type = coBool; + def.tooltip = L("If enabled, use free camera. If not enabled, use constrained camera."); + def.set_default_value(new ConfigOptionBool(app_config->get("use_free_camera") == "1")); + option = Option(def, "use_free_camera"); + m_optgroup->append_single_option_line(option); +#endif // ENABLE_6DOF_CAMERA + def.label = L("Use custom size for toolbar icons"); def.type = coBool; def.tooltip = L("If enabled, you can change size of toolbar icons manually."); From 3f2ccf08d28e5fc8fd0c4443f4d39869ed095e7d Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 16 Jan 2020 10:17:07 +0100 Subject: [PATCH 3/6] 3Dconnexion devices translation linearly dependent on zoom --- src/slic3r/GUI/Camera.hpp | 1 + src/slic3r/GUI/GLCanvas3D.cpp | 24 ++++++++--------------- src/slic3r/GUI/GLSelectionRectangle.cpp | 3 +-- src/slic3r/GUI/GLToolbar.cpp | 18 ++++++----------- src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 2 +- src/slic3r/GUI/Mouse3DController.cpp | 2 +- 6 files changed, 18 insertions(+), 32 deletions(-) diff --git a/src/slic3r/GUI/Camera.hpp b/src/slic3r/GUI/Camera.hpp index 67c97c0b4..257b27901 100644 --- a/src/slic3r/GUI/Camera.hpp +++ b/src/slic3r/GUI/Camera.hpp @@ -80,6 +80,7 @@ public: #endif // !ENABLE_6DOF_CAMERA double get_zoom() const { return m_zoom; } + double get_inv_zoom() const { assert(m_zoom != 0.0); return 1.0 / m_zoom; } void update_zoom(double delta_zoom); void set_zoom(double zoom); diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 1c383841e..617ceb4ba 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -390,8 +390,7 @@ Rect GLCanvas3D::LayersEditing::get_bar_rect_viewport(const GLCanvas3D& canvas) float half_w = 0.5f * (float)cnv_size.get_width(); float half_h = 0.5f * (float)cnv_size.get_height(); - float zoom = (float)canvas.get_camera().get_zoom(); - float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; + float inv_zoom = (float)canvas.get_camera().get_inv_zoom(); #if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE return Rect((half_w - thickness_bar_width(canvas)) * inv_zoom, half_h * inv_zoom, half_w * inv_zoom, -half_h * inv_zoom); @@ -407,8 +406,7 @@ Rect GLCanvas3D::LayersEditing::get_reset_rect_viewport(const GLCanvas3D& canvas float half_w = 0.5f * (float)cnv_size.get_width(); float half_h = 0.5f * (float)cnv_size.get_height(); - float zoom = (float)canvas.get_camera().get_zoom(); - float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; + float inv_zoom = (float)canvas.get_camera().get_inv_zoom(); return Rect((half_w - thickness_bar_width(canvas)) * inv_zoom, (-half_h + reset_button_height(canvas)) * inv_zoom, half_w * inv_zoom, -half_h * inv_zoom); } @@ -468,8 +466,7 @@ void GLCanvas3D::LayersEditing::_render_tooltip_texture(const GLCanvas3D& canvas const float width = (float)m_tooltip_texture.get_width() * scale; const float height = (float)m_tooltip_texture.get_height() * scale; - float zoom = (float)canvas.get_camera().get_zoom(); - float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; + float inv_zoom = (float)canvas.get_camera().get_inv_zoom(); float gap = 10.0f * inv_zoom; float bar_left = bar_rect.get_left(); @@ -964,8 +961,7 @@ void GLCanvas3D::WarningTexture::render(const GLCanvas3D& canvas) const if ((m_id > 0) && (m_original_width > 0) && (m_original_height > 0) && (m_width > 0) && (m_height > 0)) { const Size& cnv_size = canvas.get_canvas_size(); - float zoom = (float)canvas.get_camera().get_zoom(); - float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; + float inv_zoom = (float)canvas.get_camera().get_inv_zoom(); float left = (-0.5f * (float)m_original_width) * inv_zoom; float top = (-0.5f * (float)cnv_size.get_height() + (float)m_original_height + 2.0f) * inv_zoom; float right = left + (float)m_original_width * inv_zoom; @@ -1327,8 +1323,7 @@ void GLCanvas3D::LegendTexture::render(const GLCanvas3D& canvas) const if ((m_id > 0) && (m_original_width > 0) && (m_original_height > 0) && (m_width > 0) && (m_height > 0)) { const Size& cnv_size = canvas.get_canvas_size(); - float zoom = (float)canvas.get_camera().get_zoom(); - float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; + float inv_zoom = (float)canvas.get_camera().get_inv_zoom(); float left = (-0.5f * (float)cnv_size.get_width()) * inv_zoom; float top = (0.5f * (float)cnv_size.get_height()) * inv_zoom; float right = left + (float)m_original_width * inv_zoom; @@ -4973,8 +4968,7 @@ void GLCanvas3D::_render_main_toolbar() const #endif // ENABLE_RETINA_GL Size cnv_size = get_canvas_size(); - float zoom = (float)m_camera.get_zoom(); - float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; + float inv_zoom = (float)m_camera.get_inv_zoom(); float top = 0.5f * (float)cnv_size.get_height() * inv_zoom; float left = -0.5f * (m_main_toolbar.get_width() + m_undoredo_toolbar.get_width()) * inv_zoom; @@ -5000,8 +4994,7 @@ void GLCanvas3D::_render_undoredo_toolbar() const #endif // ENABLE_RETINA_GL Size cnv_size = get_canvas_size(); - float zoom = (float)m_camera.get_zoom(); - float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; + float inv_zoom = (float)m_camera.get_inv_zoom(); float top = 0.5f * (float)cnv_size.get_height() * inv_zoom; float left = (m_main_toolbar.get_width() - 0.5f * (m_main_toolbar.get_width() + m_undoredo_toolbar.get_width())) * inv_zoom; @@ -5023,8 +5016,7 @@ void GLCanvas3D::_render_view_toolbar() const #endif // ENABLE_RETINA_GL Size cnv_size = get_canvas_size(); - float zoom = (float)m_camera.get_zoom(); - float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; + float inv_zoom = (float)m_camera.get_inv_zoom(); // places the toolbar on the bottom-left corner of the 3d scene float top = (-0.5f * (float)cnv_size.get_height() + m_view_toolbar.get_height()) * inv_zoom; diff --git a/src/slic3r/GUI/GLSelectionRectangle.cpp b/src/slic3r/GUI/GLSelectionRectangle.cpp index 684563bff..a8b69d75a 100644 --- a/src/slic3r/GUI/GLSelectionRectangle.cpp +++ b/src/slic3r/GUI/GLSelectionRectangle.cpp @@ -69,8 +69,7 @@ namespace GUI { return; const Camera& camera = canvas.get_camera(); - float zoom = (float)camera.get_zoom(); - float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; + float inv_zoom = (float)camera.get_inv_zoom(); Size cnv_size = canvas.get_canvas_size(); float cnv_half_width = 0.5f * (float)cnv_size.get_width(); diff --git a/src/slic3r/GUI/GLToolbar.cpp b/src/slic3r/GUI/GLToolbar.cpp index 82ac82515..d1edff10f 100644 --- a/src/slic3r/GUI/GLToolbar.cpp +++ b/src/slic3r/GUI/GLToolbar.cpp @@ -653,8 +653,7 @@ std::string GLToolbar::update_hover_state_horizontal(const Vec2d& mouse_pos, GLC { // NB: mouse_pos is already scaled appropriately - float zoom = (float)parent.get_camera().get_zoom(); - float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; + float inv_zoom = (float)parent.get_camera().get_inv_zoom(); float factor = m_layout.scale * inv_zoom; Size cnv_size = parent.get_canvas_size(); @@ -758,8 +757,7 @@ std::string GLToolbar::update_hover_state_vertical(const Vec2d& mouse_pos, GLCan { // NB: mouse_pos is already scaled appropriately - float zoom = (float)parent.get_camera().get_zoom(); - float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; + float inv_zoom = (float)parent.get_camera().get_inv_zoom(); float factor = m_layout.scale * inv_zoom; Size cnv_size = parent.get_canvas_size(); @@ -875,8 +873,7 @@ int GLToolbar::contains_mouse_horizontal(const Vec2d& mouse_pos, const GLCanvas3 { // NB: mouse_pos is already scaled appropriately - float zoom = (float)parent.get_camera().get_zoom(); - float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; + float inv_zoom = (float)parent.get_camera().get_inv_zoom(); float factor = m_layout.scale * inv_zoom; Size cnv_size = parent.get_canvas_size(); @@ -949,8 +946,7 @@ int GLToolbar::contains_mouse_vertical(const Vec2d& mouse_pos, const GLCanvas3D& { // NB: mouse_pos is already scaled appropriately - float zoom = (float)parent.get_camera().get_zoom(); - float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; + float inv_zoom = (float)parent.get_camera().get_inv_zoom(); float factor = m_layout.scale * inv_zoom; Size cnv_size = parent.get_canvas_size(); @@ -1102,8 +1098,7 @@ void GLToolbar::render_horizontal(const GLCanvas3D& parent) const int tex_width = m_icons_texture.get_width(); int tex_height = m_icons_texture.get_height(); - float zoom = (float)parent.get_camera().get_zoom(); - float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; + float inv_zoom = (float)parent.get_camera().get_inv_zoom(); float factor = inv_zoom * m_layout.scale; float scaled_icons_size = m_layout.icons_size * factor; @@ -1151,8 +1146,7 @@ void GLToolbar::render_vertical(const GLCanvas3D& parent) const int tex_width = m_icons_texture.get_width(); int tex_height = m_icons_texture.get_height(); - float zoom = (float)parent.get_camera().get_zoom(); - float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; + float inv_zoom = (float)parent.get_camera().get_inv_zoom(); float factor = inv_zoom * m_layout.scale; float scaled_icons_size = m_layout.icons_size * factor; diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index abcb39c14..ed8d16aa2 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -850,7 +850,7 @@ void GLGizmosManager::do_render_overlay() const float cnv_w = (float)m_parent.get_canvas_size().get_width(); float cnv_h = (float)m_parent.get_canvas_size().get_height(); float zoom = (float)m_parent.get_camera().get_zoom(); - float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; + float inv_zoom = (float)m_parent.get_camera().get_inv_zoom(); float height = get_scaled_total_height(); float width = get_scaled_total_width(); diff --git a/src/slic3r/GUI/Mouse3DController.cpp b/src/slic3r/GUI/Mouse3DController.cpp index 3dd12e021..6de2c0850 100644 --- a/src/slic3r/GUI/Mouse3DController.cpp +++ b/src/slic3r/GUI/Mouse3DController.cpp @@ -156,7 +156,7 @@ bool Mouse3DController::State::apply(Camera& camera) { const Vec3d& translation = m_translation.queue.front(); #if ENABLE_3DCONNEXION_Y_AS_ZOOM - camera.set_target(camera.get_target() + m_translation_params.scale * (translation(0) * camera.get_dir_right() + translation(2) * camera.get_dir_up())); + camera.set_target(camera.get_target() + camera.get_inv_zoom() * m_translation_params.scale * (translation(0) * camera.get_dir_right() + translation(2) * camera.get_dir_up())); if (translation(1) != 0.0) camera.update_zoom(m_zoom_params.scale * translation(1) / std::abs(translation(1))); #else From 89166accbe19c3599fb7c7102bc7d60a973213ed Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 16 Jan 2020 11:08:19 +0100 Subject: [PATCH 4/6] Modified layout of preferences dialog --- src/slic3r/GUI/Preferences.cpp | 82 ++++++++++++++++++++-------------- src/slic3r/GUI/Preferences.hpp | 6 ++- 2 files changed, 53 insertions(+), 35 deletions(-) diff --git a/src/slic3r/GUI/Preferences.cpp b/src/slic3r/GUI/Preferences.cpp index d0686677d..4fd63fe0e 100644 --- a/src/slic3r/GUI/Preferences.cpp +++ b/src/slic3r/GUI/Preferences.cpp @@ -19,16 +19,11 @@ PreferencesDialog::PreferencesDialog(wxWindow* parent) : void PreferencesDialog::build() { auto app_config = get_app_config(); - m_optgroup = std::make_shared(this, _(L("General"))); - m_optgroup->label_width = 40; - m_optgroup->m_on_change = [this](t_config_option_key opt_key, boost::any value) { + m_optgroup_general = std::make_shared(this, _(L("General"))); + m_optgroup_general->label_width = 40; + m_optgroup_general->m_on_change = [this](t_config_option_key opt_key, boost::any value) { m_values[opt_key] = boost::any_cast(value) ? "1" : "0"; - - if (opt_key == "use_custom_toolbar_size") { - m_icon_size_sizer->ShowItems(boost::any_cast(value)); - this->layout(); - } - }; + }; // TODO // $optgroup->append_single_option_line(Slic3r::GUI::OptionsGroup::Option->new( @@ -47,7 +42,7 @@ void PreferencesDialog::build() "instead of the one containing the input files."); def.set_default_value(new ConfigOptionBool{ app_config->has("remember_output_path") ? app_config->get("remember_output_path") == "1" : true }); Option option(def, "remember_output_path"); - m_optgroup->append_single_option_line(option); + m_optgroup_general->append_single_option_line(option); def.label = L("Auto-center parts"); def.type = coBool; @@ -55,7 +50,7 @@ void PreferencesDialog::build() "around the print bed center."); def.set_default_value(new ConfigOptionBool{ app_config->get("autocenter") == "1" }); option = Option (def,"autocenter"); - m_optgroup->append_single_option_line(option); + m_optgroup_general->append_single_option_line(option); def.label = L("Background processing"); def.type = coBool; @@ -63,7 +58,7 @@ void PreferencesDialog::build() "as they\'re loaded in order to save time when exporting G-code."); def.set_default_value(new ConfigOptionBool{ app_config->get("background_processing") == "1" }); option = Option (def,"background_processing"); - m_optgroup->append_single_option_line(option); + m_optgroup_general->append_single_option_line(option); // Please keep in sync with ConfigWizard def.label = L("Check for application updates"); @@ -71,7 +66,7 @@ void PreferencesDialog::build() def.tooltip = L("If enabled, PrusaSlicer will check for the new versions of itself online. When a new version becomes available a notification is displayed at the next application startup (never during program usage). This is only a notification mechanisms, no automatic installation is done."); def.set_default_value(new ConfigOptionBool(app_config->get("version_check") == "1")); option = Option (def, "version_check"); - m_optgroup->append_single_option_line(option); + m_optgroup_general->append_single_option_line(option); #if ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF // Please keep in sync with ConfigWizard @@ -80,7 +75,7 @@ void PreferencesDialog::build() def.tooltip = L("If enabled, allows the Reload from disk command to automatically find and load the files when invoked."); def.set_default_value(new ConfigOptionBool(app_config->get("export_sources_full_pathnames") == "1")); option = Option(def, "export_sources_full_pathnames"); - m_optgroup->append_single_option_line(option); + m_optgroup_general->append_single_option_line(option); #endif // ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF // Please keep in sync with ConfigWizard @@ -89,7 +84,7 @@ void PreferencesDialog::build() def.tooltip = L("If enabled, Slic3r downloads updates of built-in system presets in the background. These updates are downloaded into a separate temporary location. When a new preset version becomes available it is offered at application startup."); def.set_default_value(new ConfigOptionBool(app_config->get("preset_update") == "1")); option = Option (def, "preset_update"); - m_optgroup->append_single_option_line(option); + m_optgroup_general->append_single_option_line(option); def.label = L("Suppress \" - default - \" presets"); def.type = coBool; @@ -97,7 +92,7 @@ void PreferencesDialog::build() "selections once there are any other valid presets available."); def.set_default_value(new ConfigOptionBool{ app_config->get("no_defaults") == "1" }); option = Option (def,"no_defaults"); - m_optgroup->append_single_option_line(option); + m_optgroup_general->append_single_option_line(option); def.label = L("Show incompatible print and filament presets"); def.type = coBool; @@ -105,7 +100,7 @@ void PreferencesDialog::build() "even if they are marked as incompatible with the active printer"); def.set_default_value(new ConfigOptionBool{ app_config->get("show_incompatible_presets") == "1" }); option = Option (def,"show_incompatible_presets"); - m_optgroup->append_single_option_line(option); + m_optgroup_general->append_single_option_line(option); #if __APPLE__ def.label = L("Use Retina resolution for the 3D scene"); @@ -114,15 +109,21 @@ void PreferencesDialog::build() "If you are experiencing 3D performance problems, disabling this option may help."); def.set_default_value(new ConfigOptionBool{ app_config->get("use_retina_opengl") == "1" }); option = Option (def, "use_retina_opengl"); - m_optgroup->append_single_option_line(option); + m_optgroup_general->append_single_option_line(option); #endif - def.label = L("Use perspective camera"); - def.type = coBool; - def.tooltip = L("If enabled, use perspective camera. If not enabled, use orthographic camera."); - def.set_default_value(new ConfigOptionBool{ app_config->get("use_perspective_camera") == "1" }); - option = Option(def, "use_perspective_camera"); - m_optgroup->append_single_option_line(option); + m_optgroup_camera = std::make_shared(this, _(L("Camera"))); + m_optgroup_camera->label_width = 40; + m_optgroup_camera->m_on_change = [this](t_config_option_key opt_key, boost::any value) { + m_values[opt_key] = boost::any_cast(value) ? "1" : "0"; + }; + + def.label = L("Use perspective camera"); + def.type = coBool; + def.tooltip = L("If enabled, use perspective camera. If not enabled, use orthographic camera."); + def.set_default_value(new ConfigOptionBool{ app_config->get("use_perspective_camera") == "1" }); + option = Option(def, "use_perspective_camera"); + m_optgroup_camera->append_single_option_line(option); #if ENABLE_6DOF_CAMERA def.label = L("Use free camera"); @@ -130,21 +131,33 @@ void PreferencesDialog::build() def.tooltip = L("If enabled, use free camera. If not enabled, use constrained camera."); def.set_default_value(new ConfigOptionBool(app_config->get("use_free_camera") == "1")); option = Option(def, "use_free_camera"); - m_optgroup->append_single_option_line(option); + m_optgroup_camera->append_single_option_line(option); #endif // ENABLE_6DOF_CAMERA + m_optgroup_gui = std::make_shared(this, _(L("GUI"))); + m_optgroup_gui->label_width = 40; + m_optgroup_gui->m_on_change = [this](t_config_option_key opt_key, boost::any value) { + m_values[opt_key] = boost::any_cast(value) ? "1" : "0"; + if (opt_key == "use_custom_toolbar_size") { + m_icon_size_sizer->ShowItems(boost::any_cast(value)); + this->layout(); + } + }; + def.label = L("Use custom size for toolbar icons"); def.type = coBool; def.tooltip = L("If enabled, you can change size of toolbar icons manually."); def.set_default_value(new ConfigOptionBool{ app_config->get("use_custom_toolbar_size") == "1" }); - option = Option (def,"use_custom_toolbar_size"); - m_optgroup->append_single_option_line(option); + option = Option(def, "use_custom_toolbar_size"); + m_optgroup_gui->append_single_option_line(option); - create_icon_size_slider(); - m_icon_size_sizer->ShowItems(app_config->get("use_custom_toolbar_size") == "1"); + create_icon_size_slider(); + m_icon_size_sizer->ShowItems(app_config->get("use_custom_toolbar_size") == "1"); auto sizer = new wxBoxSizer(wxVERTICAL); - sizer->Add(m_optgroup->sizer, 0, wxEXPAND | wxBOTTOM | wxLEFT | wxRIGHT, 10); + sizer->Add(m_optgroup_general->sizer, 0, wxEXPAND | wxBOTTOM | wxLEFT | wxRIGHT, 10); + sizer->Add(m_optgroup_camera->sizer, 0, wxEXPAND | wxBOTTOM | wxLEFT | wxRIGHT, 10); + sizer->Add(m_optgroup_gui->sizer, 0, wxEXPAND | wxBOTTOM | wxLEFT | wxRIGHT, 10); SetFont(wxGetApp().normal_font()); @@ -176,7 +189,9 @@ void PreferencesDialog::accept() void PreferencesDialog::on_dpi_changed(const wxRect &suggested_rect) { - m_optgroup->msw_rescale(); + m_optgroup_general->msw_rescale(); + m_optgroup_camera->msw_rescale(); + m_optgroup_gui->msw_rescale(); msw_buttons_rescale(this, em_unit(), { wxID_OK, wxID_CANCEL }); @@ -201,7 +216,7 @@ void PreferencesDialog::create_icon_size_slider() m_icon_size_sizer = new wxBoxSizer(wxHORIZONTAL); - wxWindow* parent = m_optgroup->ctrl_parent(); + wxWindow* parent = m_optgroup_gui->ctrl_parent(); if (isOSX) // For correct rendering of the slider and value label under OSX @@ -249,8 +264,9 @@ void PreferencesDialog::create_icon_size_slider() win->SetBackgroundStyle(wxBG_STYLE_PAINT); } - m_optgroup->sizer->Add(m_icon_size_sizer, 0, wxEXPAND | wxALL, em); + m_optgroup_gui->sizer->Add(m_icon_size_sizer, 0, wxEXPAND | wxALL, em); } + } // GUI } // Slic3r \ No newline at end of file diff --git a/src/slic3r/GUI/Preferences.hpp b/src/slic3r/GUI/Preferences.hpp index 9fffe6a7f..35bf2b8c5 100644 --- a/src/slic3r/GUI/Preferences.hpp +++ b/src/slic3r/GUI/Preferences.hpp @@ -15,8 +15,10 @@ class ConfigOptionsGroup; class PreferencesDialog : public DPIDialog { std::map m_values; - std::shared_ptr m_optgroup; - wxSizer* m_icon_size_sizer; + std::shared_ptr m_optgroup_general; + std::shared_ptr m_optgroup_camera; + std::shared_ptr m_optgroup_gui; + wxSizer* m_icon_size_sizer; bool isOSX {false}; public: PreferencesDialog(wxWindow* parent); From a9529fbcdc314d4dc58b99cb53205dc6100538fd Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 16 Jan 2020 12:00:54 +0100 Subject: [PATCH 5/6] Added method void Camera::rotate_local_around_pivot(const Vec3d& rotation_rad, const Vec3d& pivot) to rotate the camera around a generic point --- src/slic3r/GUI/Camera.cpp | 13 ++++++++++--- src/slic3r/GUI/Camera.hpp | 3 +++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/slic3r/GUI/Camera.cpp b/src/slic3r/GUI/Camera.cpp index 49246dbb9..f2a560c08 100644 --- a/src/slic3r/GUI/Camera.cpp +++ b/src/slic3r/GUI/Camera.cpp @@ -442,12 +442,19 @@ void Camera::rotate_on_sphere(double delta_azimut_rad, double delta_zenit_rad) void Camera::rotate_local_around_target(const Vec3d& rotation_rad) { - Vec3d target = m_target; - translate_world(-target); + rotate_local_around_pivot(rotation_rad, m_target); +} + +void Camera::rotate_local_around_pivot(const Vec3d& rotation_rad, const Vec3d& pivot) +{ + // we use a copy of the pivot because a reference to the current m_target may be passed in (see i.e. rotate_local_around_target()) + // and m_target is modified by the translate_world() calls + Vec3d center = pivot; + translate_world(-center); m_view_matrix.rotate(Eigen::AngleAxisd(rotation_rad(0), get_dir_right())); m_view_matrix.rotate(Eigen::AngleAxisd(rotation_rad(1), get_dir_up())); m_view_matrix.rotate(Eigen::AngleAxisd(rotation_rad(2), get_dir_forward())); - translate_world(target); + translate_world(center); } bool Camera::is_looking_downward() const diff --git a/src/slic3r/GUI/Camera.hpp b/src/slic3r/GUI/Camera.hpp index 257b27901..87060e288 100644 --- a/src/slic3r/GUI/Camera.hpp +++ b/src/slic3r/GUI/Camera.hpp @@ -136,6 +136,9 @@ public: // rotate the camera around three axes parallel to the camera local axes and passing through m_target void rotate_local_around_target(const Vec3d& rotation_rad); + // rotate the camera around three axes parallel to the camera local axes and passing through the given pivot point + void rotate_local_around_pivot(const Vec3d& rotation_rad, const Vec3d& pivot); + // returns true if the camera z axis (forward) is pointing in the negative direction of the world z axis bool is_looking_downward() const; #endif // ENABLE_6DOF_CAMERA From 02aa6294494bc491e0a3294a6c301c24c2574297 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Fri, 17 Jan 2020 09:36:34 +0100 Subject: [PATCH 6/6] 3DConnexion devices -> Tweak of sensitivity parameters and dependency of translation from zoom factor --- src/slic3r/GUI/Camera.cpp | 11 ++++++----- src/slic3r/GUI/Camera.hpp | 5 ++++- src/slic3r/GUI/Mouse3DController.cpp | 15 ++++++++------- 3 files changed, 18 insertions(+), 13 deletions(-) diff --git a/src/slic3r/GUI/Camera.cpp b/src/slic3r/GUI/Camera.cpp index f2a560c08..c21947d58 100644 --- a/src/slic3r/GUI/Camera.cpp +++ b/src/slic3r/GUI/Camera.cpp @@ -143,13 +143,14 @@ void Camera::update_zoom(double delta_zoom) void Camera::set_zoom(double zoom) { // Don't allow to zoom too far outside the scene. - double zoom_min = calc_zoom_to_bounding_box_factor(m_scene_box, (int)m_viewport[2], (int)m_viewport[3]); + double zoom_min = min_zoom(); if (zoom_min > 0.0) - zoom = std::max(zoom, zoom_min * 0.7); + zoom = std::max(zoom, zoom_min); // Don't allow to zoom too close to the scene. - m_zoom = std::min(zoom, 100.0); + m_zoom = std::min(zoom, max_zoom()); } + #if ENABLE_6DOF_CAMERA void Camera::select_view(const std::string& direction) { @@ -457,9 +458,9 @@ void Camera::rotate_local_around_pivot(const Vec3d& rotation_rad, const Vec3d& p translate_world(center); } -bool Camera::is_looking_downward() const +double Camera::min_zoom() const { - return get_dir_forward().dot(Vec3d::UnitZ()) < 0.0; + return 0.7 * calc_zoom_to_bounding_box_factor(m_scene_box, (int)m_viewport[2], (int)m_viewport[3]); } #endif // ENABLE_6DOF_CAMERA diff --git a/src/slic3r/GUI/Camera.hpp b/src/slic3r/GUI/Camera.hpp index 87060e288..2a4336108 100644 --- a/src/slic3r/GUI/Camera.hpp +++ b/src/slic3r/GUI/Camera.hpp @@ -140,7 +140,10 @@ public: void rotate_local_around_pivot(const Vec3d& rotation_rad, const Vec3d& pivot); // returns true if the camera z axis (forward) is pointing in the negative direction of the world z axis - bool is_looking_downward() const; + bool is_looking_downward() const { return get_dir_forward().dot(Vec3d::UnitZ()) < 0.0; } + + double max_zoom() const { return 100.0; } + double min_zoom() const; #endif // ENABLE_6DOF_CAMERA private: diff --git a/src/slic3r/GUI/Mouse3DController.cpp b/src/slic3r/GUI/Mouse3DController.cpp index 6de2c0850..bafb10c52 100644 --- a/src/slic3r/GUI/Mouse3DController.cpp +++ b/src/slic3r/GUI/Mouse3DController.cpp @@ -156,7 +156,8 @@ bool Mouse3DController::State::apply(Camera& camera) { const Vec3d& translation = m_translation.queue.front(); #if ENABLE_3DCONNEXION_Y_AS_ZOOM - camera.set_target(camera.get_target() + camera.get_inv_zoom() * m_translation_params.scale * (translation(0) * camera.get_dir_right() + translation(2) * camera.get_dir_up())); + double zoom_factor = camera.min_zoom() / camera.get_zoom(); + camera.set_target(camera.get_target() + zoom_factor * m_translation_params.scale * (translation(0) * camera.get_dir_right() + translation(2) * camera.get_dir_up())); if (translation(1) != 0.0) camera.update_zoom(m_zoom_params.scale * translation(1) / std::abs(translation(1))); #else @@ -655,12 +656,12 @@ bool Mouse3DController::connect_device() BOOST_LOG_TRIVIAL(info) << "Path................: '" << path << "'"; // get device parameters from the config, if present - double translation_speed = 1.0; - float rotation_speed = 1.0; + double translation_speed = 4.0; + float rotation_speed = 4.0; double translation_deadzone = State::DefaultTranslationDeadzone; float rotation_deadzone = State::DefaultRotationDeadzone; #if ENABLE_3DCONNEXION_Y_AS_ZOOM - double zoom_speed = 1.0; + double zoom_speed = 2.0; #endif // ENABLE_3DCONNEXION_Y_AS_ZOOM wxGetApp().app_config->get_mouse_device_translation_speed(m_device_str, translation_speed); wxGetApp().app_config->get_mouse_device_translation_deadzone(m_device_str, translation_deadzone); @@ -670,12 +671,12 @@ bool Mouse3DController::connect_device() wxGetApp().app_config->get_mouse_device_zoom_speed(m_device_str, zoom_speed); #endif // ENABLE_3DCONNEXION_Y_AS_ZOOM // clamp to valid values - m_state.set_translation_scale(State::DefaultTranslationScale* std::clamp(translation_speed, 0.1, 10.0)); + m_state.set_translation_scale(State::DefaultTranslationScale * std::clamp(translation_speed, 0.1, 10.0)); m_state.set_translation_deadzone(std::clamp(translation_deadzone, 0.0, State::MaxTranslationDeadzone)); - m_state.set_rotation_scale(State::DefaultRotationScale* std::clamp(rotation_speed, 0.1f, 10.0f)); + m_state.set_rotation_scale(State::DefaultRotationScale * std::clamp(rotation_speed, 0.1f, 10.0f)); m_state.set_rotation_deadzone(std::clamp(rotation_deadzone, 0.0f, State::MaxRotationDeadzone)); #if ENABLE_3DCONNEXION_Y_AS_ZOOM - m_state.set_zoom_scale(State::DefaultZoomScale* std::clamp(zoom_speed, 0.1, 10.0)); + m_state.set_zoom_scale(State::DefaultZoomScale * std::clamp(zoom_speed, 0.1, 10.0)); #endif // ENABLE_3DCONNEXION_Y_AS_ZOOM } #if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT