1 #ifndef slic3r_Camera_hpp_
2 #define slic3r_Camera_hpp_
3 
4 #include "libslic3r/BoundingBox.hpp"
5 #include "3DScene.hpp"
6 #include <array>
7 
8 namespace Slic3r {
9 namespace GUI {
10 
11 struct Camera
12 {
13     static const double DefaultDistance;
14     static const double DefaultZoomToBoxMarginFactor;
15     static const double DefaultZoomToVolumesMarginFactor;
16     static double FrustrumMinZRange;
17     static double FrustrumMinNearZ;
18     static double FrustrumZMargin;
19     static double MaxFovDeg;
20 
21     enum EType : unsigned char
22     {
23         Unknown,
24         Ortho,
25         Perspective,
26         Num_types
27     };
28 
29     bool requires_zoom_to_bed;
30 
31 private:
32     EType m_type{ Perspective };
33     bool m_update_config_on_type_change_enabled{ false };
34     Vec3d m_target{ Vec3d::Zero() };
35     float m_zenit{ 45.0f };
36     double m_zoom{ 1.0 };
37     // Distance between camera position and camera target measured along the camera Z axis
38     mutable double m_distance{ DefaultDistance };
39     mutable double m_gui_scale{ 1.0 };
40 
41     mutable std::array<int, 4> m_viewport;
42     mutable Transform3d m_view_matrix{ Transform3d::Identity() };
43     // We are calculating the rotation part of the m_view_matrix from m_view_rotation.
44     mutable Eigen::Quaterniond m_view_rotation{ 1.0, 0.0, 0.0, 0.0 };
45     mutable Transform3d m_projection_matrix{ Transform3d::Identity() };
46     mutable std::pair<double, double> m_frustrum_zs;
47 
48     BoundingBoxf3 m_scene_box;
49 
50 public:
51     Camera();
52 
get_typeSlic3r::GUI::Camera53     EType get_type() const { return m_type; }
54     std::string get_type_as_string() const;
55     void set_type(EType type);
56     // valid values for type: "0" -> ortho, "1" -> perspective
57     void set_type(const std::string& type);
58     void select_next_type();
59 
enable_update_config_on_type_changeSlic3r::GUI::Camera60     void enable_update_config_on_type_change(bool enable) { m_update_config_on_type_change_enabled = enable; }
61 
get_targetSlic3r::GUI::Camera62     const Vec3d& get_target() const { return m_target; }
63     void set_target(const Vec3d& target);
64 
get_distanceSlic3r::GUI::Camera65     double get_distance() const { return (get_position() - m_target).norm(); }
get_gui_scaleSlic3r::GUI::Camera66     double get_gui_scale() const { return m_gui_scale; }
67 
get_zoomSlic3r::GUI::Camera68     double get_zoom() const { return m_zoom; }
get_inv_zoomSlic3r::GUI::Camera69     double get_inv_zoom() const { assert(m_zoom != 0.0); return 1.0 / m_zoom; }
70     void update_zoom(double delta_zoom);
71     void set_zoom(double zoom);
72 
get_scene_boxSlic3r::GUI::Camera73     const BoundingBoxf3& get_scene_box() const { return m_scene_box; }
set_scene_boxSlic3r::GUI::Camera74     void set_scene_box(const BoundingBoxf3& box) { m_scene_box = box; }
75 
76     void select_view(const std::string& direction);
77 
get_viewportSlic3r::GUI::Camera78     const std::array<int, 4>& get_viewport() const { return m_viewport; }
get_view_matrixSlic3r::GUI::Camera79     const Transform3d& get_view_matrix() const { return m_view_matrix; }
get_projection_matrixSlic3r::GUI::Camera80     const Transform3d& get_projection_matrix() const { return m_projection_matrix; }
81 
get_dir_rightSlic3r::GUI::Camera82     Vec3d get_dir_right() const { return m_view_matrix.matrix().block(0, 0, 3, 3).row(0); }
get_dir_upSlic3r::GUI::Camera83     Vec3d get_dir_up() const { return m_view_matrix.matrix().block(0, 0, 3, 3).row(1); }
get_dir_forwardSlic3r::GUI::Camera84     Vec3d get_dir_forward() const { return -m_view_matrix.matrix().block(0, 0, 3, 3).row(2); }
85 
get_positionSlic3r::GUI::Camera86     Vec3d get_position() const { return m_view_matrix.matrix().inverse().block(0, 3, 3, 1); }
87 
get_near_zSlic3r::GUI::Camera88     double get_near_z() const { return m_frustrum_zs.first; }
get_far_zSlic3r::GUI::Camera89     double get_far_z() const { return m_frustrum_zs.second; }
get_z_rangeSlic3r::GUI::Camera90     const std::pair<double, double>& get_z_range() const { return m_frustrum_zs; }
91 
92     double get_fov() const;
93 
94     void apply_viewport(int x, int y, unsigned int w, unsigned int h) const;
95     void apply_view_matrix() const;
96     // Calculates and applies the projection matrix tighting the frustrum z range around the given box.
97     // If larger z span is needed, pass the desired values of near and far z (negative values are ignored)
98     void apply_projection(const BoundingBoxf3& box, double near_z = -1.0, double far_z = -1.0) const;
99 
100     void zoom_to_box(const BoundingBoxf3& box, double margin_factor = DefaultZoomToBoxMarginFactor);
101     void zoom_to_volumes(const GLVolumePtrs& volumes, double margin_factor = DefaultZoomToVolumesMarginFactor);
102 
103 #if ENABLE_CAMERA_STATISTICS
104     void debug_render() const;
105 #endif // ENABLE_CAMERA_STATISTICS
106 
107     // translate the camera in world space
translate_worldSlic3r::GUI::Camera108     void translate_world(const Vec3d& displacement) { this->set_target(m_target + displacement); }
109 
110     // rotate the camera on a sphere having center == m_target and radius == m_distance
111     // using the given variations of spherical coordinates
112     // if apply_limits == true the camera stops rotating when its forward vector is parallel to the world Z axis
113     void rotate_on_sphere(double delta_azimut_rad, double delta_zenit_rad, bool apply_limits);
114 
115     // rotate the camera around three axes parallel to the camera local axes and passing through m_target
116     void rotate_local_around_target(const Vec3d& rotation_rad);
117 
118     // returns true if the camera z axis (forward) is pointing in the negative direction of the world z axis
is_looking_downwardSlic3r::GUI::Camera119     bool is_looking_downward() const { return get_dir_forward().dot(Vec3d::UnitZ()) < 0.0; }
120 
121     // forces camera right vector to be parallel to XY plane
recover_from_free_cameraSlic3r::GUI::Camera122     void recover_from_free_camera()
123     {
124         if (std::abs(get_dir_right()(2)) > EPSILON)
125             look_at(get_position(), m_target, Vec3d::UnitZ());
126     }
127 
128     void look_at(const Vec3d& position, const Vec3d& target, const Vec3d& up);
129 
max_zoomSlic3r::GUI::Camera130     double max_zoom() const { return 250.0; }
131     double min_zoom() const;
132 
133 private:
134     // returns tight values for nearZ and farZ plane around the given bounding box
135     // the camera MUST be outside of the bounding box in eye coordinate of the given box
136     std::pair<double, double> calc_tight_frustrum_zs_around(const BoundingBoxf3& box) const;
137     double calc_zoom_to_bounding_box_factor(const BoundingBoxf3& box, double margin_factor = DefaultZoomToBoxMarginFactor) const;
138     double calc_zoom_to_volumes_factor(const GLVolumePtrs& volumes, Vec3d& center, double margin_factor = DefaultZoomToVolumesMarginFactor) const;
139     void set_distance(double distance) const;
140 
141     void set_default_orientation();
142     Vec3d validate_target(const Vec3d& target) const;
143     void update_zenit();
144 };
145 
146 } // GUI
147 } // Slic3r
148 
149 #endif // slic3r_Camera_hpp_
150 
151