mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-30 20:21:12 -06:00 
			
		
		
		
	Fixed conflicts after merge with branch et_perpsective_camera
This commit is contained in:
		
						commit
						5766e9e915
					
				
					 14 changed files with 471 additions and 253 deletions
				
			
		|  | @ -212,7 +212,7 @@ const double Bed3D::Axes::ArrowLength = 5.0; | |||
| 
 | ||||
| Bed3D::Axes::Axes() | ||||
| : origin(Vec3d::Zero()) | ||||
| , length(Vec3d::Zero()) | ||||
| , length(25.0 * Vec3d::Ones()) | ||||
| { | ||||
|     m_quadric = ::gluNewQuadric(); | ||||
|     if (m_quadric != nullptr) | ||||
|  | @ -292,7 +292,7 @@ bool Bed3D::set_shape(const Pointfs& shape) | |||
|     m_shape = shape; | ||||
|     m_type = new_type; | ||||
| 
 | ||||
|     calc_bounding_box(); | ||||
|     calc_bounding_boxes(); | ||||
| 
 | ||||
|     ExPolygon poly; | ||||
|     for (const Vec2d& p : m_shape) | ||||
|  | @ -313,7 +313,7 @@ bool Bed3D::set_shape(const Pointfs& shape) | |||
| 
 | ||||
|     // Set the origin and size for painting of the coordinate system axes.
 | ||||
|     m_axes.origin = Vec3d(0.0, 0.0, (double)GROUND_Z); | ||||
|     m_axes.length = 0.1 * get_bounding_box().max_size() * Vec3d::Ones(); | ||||
|     m_axes.length = 0.1 * m_bounding_box.max_size() * Vec3d::Ones(); | ||||
| 
 | ||||
|     // Let the calee to update the UI.
 | ||||
|     return true; | ||||
|  | @ -401,13 +401,22 @@ void Bed3D::render_axes() const | |||
|         m_axes.render(); | ||||
| } | ||||
| 
 | ||||
| void Bed3D::calc_bounding_box() | ||||
| void Bed3D::calc_bounding_boxes() const | ||||
| { | ||||
|     m_bounding_box = BoundingBoxf3(); | ||||
|     for (const Vec2d& p : m_shape) | ||||
|     { | ||||
|         m_bounding_box.merge(Vec3d(p(0), p(1), 0.0)); | ||||
|     } | ||||
| 
 | ||||
|     m_extended_bounding_box = m_bounding_box; | ||||
| 
 | ||||
|     // extend to contain axes
 | ||||
|     m_extended_bounding_box.merge(m_axes.length + Axes::ArrowLength * Vec3d::Ones()); | ||||
| 
 | ||||
|     // extend to contain model, if any
 | ||||
|     if (!m_model.get_filename().empty()) | ||||
|         m_extended_bounding_box.merge(m_model.get_transformed_bounding_box()); | ||||
| } | ||||
| 
 | ||||
| void Bed3D::calc_triangles(const ExPolygon& poly) | ||||
|  | @ -550,6 +559,9 @@ void Bed3D::render_prusa(GLCanvas3D* canvas, const std::string &key, bool bottom | |||
|                 offset += Vec3d(0.0, 0.0, -0.03); | ||||
| 
 | ||||
|             m_model.center_around(offset); | ||||
| 
 | ||||
|             // update extended bounding box
 | ||||
|             calc_bounding_boxes(); | ||||
|         } | ||||
| 
 | ||||
|         if (!m_model.get_filename().empty()) | ||||
|  |  | |||
|  | @ -87,7 +87,8 @@ public: | |||
| private: | ||||
|     EType m_type; | ||||
|     Pointfs m_shape; | ||||
|     BoundingBoxf3 m_bounding_box; | ||||
|     mutable BoundingBoxf3 m_bounding_box; | ||||
|     mutable BoundingBoxf3 m_extended_bounding_box; | ||||
|     Polygon m_polygon; | ||||
|     GeometryBuffer m_triangles; | ||||
|     GeometryBuffer m_gridlines; | ||||
|  | @ -123,7 +124,7 @@ public: | |||
|     // Return true if the bed shape changed, so the calee will update the UI.
 | ||||
|     bool set_shape(const Pointfs& shape); | ||||
| 
 | ||||
|     const BoundingBoxf3& get_bounding_box() const { return m_bounding_box; } | ||||
|     const BoundingBoxf3& get_bounding_box(bool extended) const { return extended ? m_extended_bounding_box : m_bounding_box; } | ||||
|     bool contains(const Point& point) const; | ||||
|     Point point_projection(const Point& point) const; | ||||
| 
 | ||||
|  | @ -131,7 +132,7 @@ public: | |||
|     void render_axes() const; | ||||
| 
 | ||||
| private: | ||||
|     void calc_bounding_box(); | ||||
|     void calc_bounding_boxes() const; | ||||
|     void calc_triangles(const ExPolygon& poly); | ||||
|     void calc_gridlines(const ExPolygon& poly, const BoundingBox& bed_bbox); | ||||
|     EType detect_type(const Pointfs& shape) const; | ||||
|  |  | |||
|  | @ -555,6 +555,7 @@ public: | |||
| 
 | ||||
|     const std::string& get_filename() const { return m_filename; } | ||||
|     const BoundingBoxf3& get_bounding_box() const { return m_volume.bounding_box; } | ||||
|     const BoundingBoxf3& get_transformed_bounding_box() const { return m_volume.transformed_bounding_box(); } | ||||
| 
 | ||||
|     void reset(); | ||||
| 
 | ||||
|  |  | |||
|  | @ -73,6 +73,9 @@ void AppConfig::set_defaults() | |||
|     if (get("custom_toolbar_size").empty()) | ||||
|         set("custom_toolbar_size", "100"); | ||||
| 
 | ||||
|     if (get("camera_type").empty()) | ||||
|         set("camera_type", "1"); | ||||
| 
 | ||||
|     // Remove legacy window positions/sizes
 | ||||
|     erase("", "main_frame_maximized"); | ||||
|     erase("", "main_frame_pos"); | ||||
|  |  | |||
|  | @ -2,6 +2,8 @@ | |||
| 
 | ||||
| #include "Camera.hpp" | ||||
| #include "3DScene.hpp" | ||||
| #include "GUI_App.hpp" | ||||
| #include "AppConfig.hpp" | ||||
| 
 | ||||
| #include <GL/glew.h> | ||||
| 
 | ||||
|  | @ -19,32 +21,71 @@ static const float VIEW_REAR[2] = { 180.0f, 90.0f }; | |||
| namespace Slic3r { | ||||
| namespace GUI { | ||||
| 
 | ||||
| const double Camera::DefaultDistance = 1000.0; | ||||
| double Camera::FrustrumMinZSize = 50.0; | ||||
| double Camera::FrustrumZMargin = 10.0; | ||||
| double Camera::FovMinDeg = 5.0; | ||||
| double Camera::FovMaxDeg = 75.0; | ||||
| 
 | ||||
| Camera::Camera() | ||||
|     : type(Ortho) | ||||
|     , zoom(1.0f) | ||||
|     , phi(45.0f) | ||||
| //    , distance(0.0f)
 | ||||
|     : phi(45.0f) | ||||
|     , requires_zoom_to_bed(false) | ||||
|     , inverted_phi(false) | ||||
|     , m_theta(45.0f) | ||||
|     , m_type(Ortho) | ||||
|     , m_target(Vec3d::Zero()) | ||||
|     , m_theta(45.0f) | ||||
|     , m_zoom(1.0) | ||||
|     , m_distance(DefaultDistance) | ||||
|     , m_gui_scale(1.0) | ||||
|     , m_view_matrix(Transform3d::Identity()) | ||||
|     , m_projection_matrix(Transform3d::Identity()) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| std::string Camera::get_type_as_string() const | ||||
| { | ||||
|     switch (type) | ||||
|     switch (m_type) | ||||
|     { | ||||
|     default: | ||||
|     case Unknown: | ||||
|         return "unknown"; | ||||
| //    case Perspective:
 | ||||
| //        return "perspective";
 | ||||
|     case Perspective: | ||||
|         return "perspective"; | ||||
|     default: | ||||
|     case Ortho: | ||||
|         return "ortho"; | ||||
|         return "orthographic"; | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
| void Camera::set_type(EType type) | ||||
| { | ||||
|     if (m_type != type) | ||||
|     { | ||||
|         m_type = type; | ||||
| 
 | ||||
|         wxGetApp().app_config->set("camera_type", std::to_string(m_type)); | ||||
|         wxGetApp().app_config->save(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void Camera::set_type(const std::string& type) | ||||
| { | ||||
|     if (!type.empty() && (type != "1")) | ||||
|     { | ||||
|         unsigned char type_id = atoi(type.c_str()); | ||||
|         if (((unsigned char)Ortho < type_id) && (type_id < (unsigned char)Num_types)) | ||||
|             set_type((Camera::EType)type_id); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void Camera::select_next_type() | ||||
| { | ||||
|     unsigned char next = (unsigned char)m_type + 1; | ||||
|     if (next == (unsigned char)Num_types) | ||||
|         next = 1; | ||||
| 
 | ||||
|     set_type((EType)next); | ||||
| } | ||||
| 
 | ||||
| void Camera::set_target(const Vec3d& target) | ||||
| { | ||||
|     m_target = target; | ||||
|  | @ -65,9 +106,20 @@ void Camera::set_theta(float theta, bool apply_limit) | |||
|     } | ||||
| } | ||||
| 
 | ||||
| void Camera::set_scene_box(const BoundingBoxf3& box) | ||||
| void Camera::set_zoom(double zoom, const BoundingBoxf3& max_box, int canvas_w, int canvas_h) | ||||
| { | ||||
|     m_scene_box = box; | ||||
|     zoom = std::max(std::min(zoom, 4.0), -4.0) / 10.0; | ||||
|     zoom = m_zoom / (1.0 - zoom); | ||||
| 
 | ||||
|     // Don't allow to zoom too far outside the scene.
 | ||||
|     double zoom_min = calc_zoom_to_bounding_box_factor(max_box, canvas_w, canvas_h); | ||||
|     if (zoom_min > 0.0) | ||||
|         zoom = std::max(zoom, zoom_min * 0.7); | ||||
| 
 | ||||
|     // Don't allow to zoom too close to the scene.
 | ||||
|     zoom = std::min(zoom, 100.0); | ||||
| 
 | ||||
|     m_zoom = zoom; | ||||
| } | ||||
| 
 | ||||
| bool Camera::select_view(const std::string& direction) | ||||
|  | @ -99,6 +151,18 @@ bool Camera::select_view(const std::string& direction) | |||
|         return false; | ||||
| } | ||||
| 
 | ||||
| double Camera::get_fov() const | ||||
| { | ||||
|     switch (m_type) | ||||
|     { | ||||
|     case Perspective: | ||||
|         return 2.0 * Geometry::rad2deg(std::atan(1.0 / m_projection_matrix.matrix()(1, 1))); | ||||
|     default: | ||||
|     case Ortho: | ||||
|         return 0.0; | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
| void Camera::apply_viewport(int x, int y, unsigned int w, unsigned int h) const | ||||
| { | ||||
|     glsafe(::glViewport(0, 0, w, h)); | ||||
|  | @ -107,27 +171,268 @@ void Camera::apply_viewport(int x, int y, unsigned int w, unsigned int h) const | |||
| 
 | ||||
| void Camera::apply_view_matrix() const | ||||
| { | ||||
|     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)); | ||||
| 
 | ||||
|     glsafe(::glMatrixMode(GL_MODELVIEW)); | ||||
|     glsafe(::glLoadIdentity()); | ||||
| 
 | ||||
|     glsafe(::glRotatef(-m_theta, 1.0f, 0.0f, 0.0f)); // pitch
 | ||||
|     glsafe(::glRotatef(phi, 0.0f, 0.0f, 1.0f));          // yaw
 | ||||
|     glsafe(::glTranslated(-m_target(0), -m_target(1), -m_target(2))); | ||||
|     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())); | ||||
| } | ||||
| 
 | ||||
| void Camera::apply_ortho_projection(float x_min, float x_max, float y_min, float y_max, float z_min, float z_max) const | ||||
| void Camera::apply_projection(const BoundingBoxf3& box) const | ||||
| { | ||||
|     m_distance = DefaultDistance; | ||||
|     double w = 0.0; | ||||
|     double h = 0.0; | ||||
| 
 | ||||
|     while (true) | ||||
|     { | ||||
|         m_frustrum_zs = calc_tight_frustrum_zs_around(box); | ||||
| 
 | ||||
|         w = (double)m_viewport[2]; | ||||
|         h = (double)m_viewport[3]; | ||||
| 
 | ||||
|         double two_zoom = 2.0 * m_zoom; | ||||
|         if (two_zoom != 0.0) | ||||
|         { | ||||
|             double inv_two_zoom = 1.0 / two_zoom; | ||||
|             w *= inv_two_zoom; | ||||
|             h *= inv_two_zoom; | ||||
|         } | ||||
| 
 | ||||
|         switch (m_type) | ||||
|         { | ||||
|         default: | ||||
|         case Ortho: | ||||
|         { | ||||
|             m_gui_scale = 1.0; | ||||
|             break; | ||||
|         } | ||||
|         case Perspective: | ||||
|         { | ||||
|             // scale near plane to keep w and h constant on the plane at z = m_distance
 | ||||
|             double scale = m_frustrum_zs.first / m_distance; | ||||
|             w *= scale; | ||||
|             h *= scale; | ||||
|             m_gui_scale = scale; | ||||
|             break; | ||||
|         } | ||||
|         } | ||||
| 
 | ||||
|         if (m_type == Perspective) | ||||
|         { | ||||
|             double fov_rad = 2.0 * std::atan(h / m_frustrum_zs.first); | ||||
|             double fov_deg = Geometry::rad2deg(fov_rad); | ||||
| 
 | ||||
|             // adjust camera distance to keep fov in a limited range
 | ||||
|             if (fov_deg > FovMaxDeg + 0.001) | ||||
|             { | ||||
|                 double new_near_z = h / ::tan(0.5 * Geometry::deg2rad(FovMaxDeg)); | ||||
|                 m_distance += (new_near_z - m_frustrum_zs.first); | ||||
|                 apply_view_matrix(); | ||||
|             } | ||||
|             else if (fov_deg < FovMinDeg - 0.001) | ||||
|             { | ||||
|                 double new_near_z = h / ::tan(0.5 * Geometry::deg2rad(FovMinDeg)); | ||||
|                 m_distance += (new_near_z - m_frustrum_zs.first); | ||||
|                 apply_view_matrix(); | ||||
|             } | ||||
|             else | ||||
|                 break; | ||||
|         } | ||||
|         else | ||||
|             break; | ||||
|     } | ||||
| 
 | ||||
|     glsafe(::glMatrixMode(GL_PROJECTION)); | ||||
|     glsafe(::glLoadIdentity()); | ||||
| 
 | ||||
|     glsafe(::glOrtho(x_min, x_max, y_min, y_max, z_min, z_max)); | ||||
|     glsafe(::glGetDoublev(GL_PROJECTION_MATRIX, m_projection_matrix.data())); | ||||
|     switch (m_type) | ||||
|     { | ||||
|     default: | ||||
|     case Ortho: | ||||
|     { | ||||
|         glsafe(::glOrtho(-w, w, -h, h, m_frustrum_zs.first, m_frustrum_zs.second)); | ||||
|         break; | ||||
|     } | ||||
|     case Perspective: | ||||
|     { | ||||
|         glsafe(::glFrustum(-w, w, -h, h, m_frustrum_zs.first, m_frustrum_zs.second)); | ||||
|         break; | ||||
|     } | ||||
|     } | ||||
| 
 | ||||
|     glsafe(::glGetDoublev(GL_PROJECTION_MATRIX, m_projection_matrix.data())); | ||||
|     glsafe(::glMatrixMode(GL_MODELVIEW)); | ||||
| } | ||||
| 
 | ||||
| void Camera::zoom_to_box(const BoundingBoxf3& box, int canvas_w, int canvas_h) | ||||
| { | ||||
|     // Calculate the zoom factor needed to adjust the view around the given box.
 | ||||
|     double zoom = calc_zoom_to_bounding_box_factor(box, canvas_w, canvas_h); | ||||
|     if (zoom > 0.0) | ||||
|     { | ||||
|         m_zoom = zoom; | ||||
|         // center view around box center
 | ||||
|         m_target = box.center(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #if ENABLE_CAMERA_STATISTICS | ||||
| void Camera::debug_render() const | ||||
| { | ||||
|     ImGuiWrapper& imgui = *wxGetApp().imgui(); | ||||
|     imgui.set_next_window_bg_alpha(0.5f); | ||||
|     imgui.begin(std::string("Camera statistics"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); | ||||
| 
 | ||||
|     std::string type = get_type_as_string(); | ||||
|     Vec3f position = get_position().cast<float>(); | ||||
|     Vec3f target = m_target.cast<float>(); | ||||
|     float distance = (float)get_distance(); | ||||
|     Vec3f forward = get_dir_forward().cast<float>(); | ||||
|     Vec3f right = get_dir_right().cast<float>(); | ||||
|     Vec3f up = get_dir_up().cast<float>(); | ||||
|     float nearZ = (float)m_frustrum_zs.first; | ||||
|     float farZ = (float)m_frustrum_zs.second; | ||||
|     float deltaZ = farZ - nearZ; | ||||
|     float zoom = (float)m_zoom; | ||||
|     float fov = (float)get_fov(); | ||||
|     float gui_scale = (float)get_gui_scale(); | ||||
| 
 | ||||
|     ImGui::InputText("Type", const_cast<char*>(type.data()), type.length(), ImGuiInputTextFlags_ReadOnly); | ||||
|     ImGui::Separator(); | ||||
|     ImGui::InputFloat3("Position", position.data(), "%.6f", ImGuiInputTextFlags_ReadOnly); | ||||
|     ImGui::InputFloat3("Target", target.data(), "%.6f", ImGuiInputTextFlags_ReadOnly); | ||||
|     ImGui::InputFloat("Distance", &distance, 0.0f, 0.0f, "%.6f", ImGuiInputTextFlags_ReadOnly); | ||||
|     ImGui::Separator(); | ||||
|     ImGui::InputFloat3("Forward", forward.data(), "%.6f", ImGuiInputTextFlags_ReadOnly); | ||||
|     ImGui::InputFloat3("Right", right.data(), "%.6f", ImGuiInputTextFlags_ReadOnly); | ||||
|     ImGui::InputFloat3("Up", up.data(), "%.6f", ImGuiInputTextFlags_ReadOnly); | ||||
|     ImGui::Separator(); | ||||
|     ImGui::InputFloat("Near Z", &nearZ, 0.0f, 0.0f, "%.6f", ImGuiInputTextFlags_ReadOnly); | ||||
|     ImGui::InputFloat("Far Z", &farZ, 0.0f, 0.0f, "%.6f", ImGuiInputTextFlags_ReadOnly); | ||||
|     ImGui::InputFloat("Delta Z", &deltaZ, 0.0f, 0.0f, "%.6f", ImGuiInputTextFlags_ReadOnly); | ||||
|     ImGui::Separator(); | ||||
|     ImGui::InputFloat("Zoom", &zoom, 0.0f, 0.0f, "%.6f", ImGuiInputTextFlags_ReadOnly); | ||||
|     ImGui::InputFloat("Fov", &fov, 0.0f, 0.0f, "%.6f", ImGuiInputTextFlags_ReadOnly); | ||||
|     ImGui::Separator(); | ||||
|     ImGui::InputFloat("GUI scale", &gui_scale, 0.0f, 0.0f, "%.6f", ImGuiInputTextFlags_ReadOnly); | ||||
|     imgui.end(); | ||||
| } | ||||
| #endif // ENABLE_CAMERA_STATISTICS
 | ||||
| 
 | ||||
| std::pair<double, double> Camera::calc_tight_frustrum_zs_around(const BoundingBoxf3& box) const | ||||
| { | ||||
|     std::pair<double, double> ret = std::make_pair(DBL_MAX, -DBL_MAX); | ||||
| 
 | ||||
|     Vec3d bb_min = box.min; | ||||
|     Vec3d bb_max = box.max; | ||||
| 
 | ||||
|     // box vertices in world space
 | ||||
|     std::vector<Vec3d> vertices; | ||||
|     vertices.reserve(8); | ||||
|     vertices.push_back(bb_min); | ||||
|     vertices.emplace_back(bb_max(0), bb_min(1), bb_min(2)); | ||||
|     vertices.emplace_back(bb_max(0), bb_max(1), bb_min(2)); | ||||
|     vertices.emplace_back(bb_min(0), bb_max(1), bb_min(2)); | ||||
|     vertices.emplace_back(bb_min(0), bb_min(1), bb_max(2)); | ||||
|     vertices.emplace_back(bb_max(0), bb_min(1), bb_max(2)); | ||||
|     vertices.push_back(bb_max); | ||||
|     vertices.emplace_back(bb_min(0), bb_max(1), bb_max(2)); | ||||
| 
 | ||||
|     // set the Z range in eye coordinates (negative Zs are in front of the camera)
 | ||||
|     for (const Vec3d& v : vertices) | ||||
|     { | ||||
|         double z = -(m_view_matrix * v)(2); | ||||
|         ret.first = std::min(ret.first, z); | ||||
|         ret.second = std::max(ret.second, z); | ||||
|     } | ||||
| 
 | ||||
|     // apply margin
 | ||||
|     ret.first -= FrustrumZMargin; | ||||
|     ret.second += FrustrumZMargin; | ||||
| 
 | ||||
|     // ensure min size
 | ||||
|     if (ret.second - ret.first < FrustrumMinZSize) | ||||
|     { | ||||
|         double mid_z = 0.5 * (ret.first + ret.second); | ||||
|         double half_size = 0.5 * FrustrumMinZSize; | ||||
|         ret.first = mid_z - half_size; | ||||
|         ret.second = mid_z + half_size; | ||||
|     } | ||||
| 
 | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| double Camera::calc_zoom_to_bounding_box_factor(const BoundingBoxf3& box, int canvas_w, int canvas_h) const | ||||
| { | ||||
|     double max_bb_size = box.max_size(); | ||||
|     if (max_bb_size == 0.0) | ||||
|         return -1.0; | ||||
| 
 | ||||
|     // project the box vertices on a plane perpendicular to the camera forward axis
 | ||||
|     // then calculates the vertices coordinate on this plane along the camera xy axes
 | ||||
| 
 | ||||
|     // ensure that the view matrix is updated
 | ||||
|     apply_view_matrix(); | ||||
| 
 | ||||
|     Vec3d right = get_dir_right(); | ||||
|     Vec3d up = get_dir_up(); | ||||
|     Vec3d forward = get_dir_forward(); | ||||
| 
 | ||||
|     Vec3d bb_min = box.min; | ||||
|     Vec3d bb_max = box.max; | ||||
|     Vec3d bb_center = box.center(); | ||||
| 
 | ||||
|     // box vertices in world space
 | ||||
|     std::vector<Vec3d> vertices; | ||||
|     vertices.reserve(8); | ||||
|     vertices.push_back(bb_min); | ||||
|     vertices.emplace_back(bb_max(0), bb_min(1), bb_min(2)); | ||||
|     vertices.emplace_back(bb_max(0), bb_max(1), bb_min(2)); | ||||
|     vertices.emplace_back(bb_min(0), bb_max(1), bb_min(2)); | ||||
|     vertices.emplace_back(bb_min(0), bb_min(1), bb_max(2)); | ||||
|     vertices.emplace_back(bb_max(0), bb_min(1), bb_max(2)); | ||||
|     vertices.push_back(bb_max); | ||||
|     vertices.emplace_back(bb_min(0), bb_max(1), bb_max(2)); | ||||
| 
 | ||||
|     double max_x = 0.0; | ||||
|     double max_y = 0.0; | ||||
| 
 | ||||
|     // margin factor to give some empty space around the box
 | ||||
|     double margin_factor = 1.25; | ||||
| 
 | ||||
|     for (const Vec3d& v : vertices) | ||||
|     { | ||||
|         // project vertex on the plane perpendicular to camera forward axis
 | ||||
|         Vec3d pos(v(0) - bb_center(0), v(1) - bb_center(1), v(2) - bb_center(2)); | ||||
|         Vec3d proj_on_plane = pos - pos.dot(forward) * forward; | ||||
| 
 | ||||
|         // calculates vertex coordinate along camera xy axes
 | ||||
|         double x_on_plane = proj_on_plane.dot(right); | ||||
|         double y_on_plane = proj_on_plane.dot(up); | ||||
| 
 | ||||
|         max_x = std::max(max_x, std::abs(x_on_plane)); | ||||
|         max_y = std::max(max_y, std::abs(y_on_plane)); | ||||
|     } | ||||
| 
 | ||||
|     if ((max_x == 0.0) || (max_y == 0.0)) | ||||
|         return -1.0f; | ||||
| 
 | ||||
|     max_x *= margin_factor; | ||||
|     max_y *= margin_factor; | ||||
| 
 | ||||
|     return std::min((double)canvas_w / (2.0 * max_x), (double)canvas_h / (2.0 * max_y)); | ||||
| } | ||||
| 
 | ||||
| } // GUI
 | ||||
| } // Slic3r
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -9,44 +9,64 @@ namespace GUI { | |||
| 
 | ||||
| struct Camera | ||||
| { | ||||
|     static const double DefaultDistance; | ||||
|     static double FrustrumMinZSize; | ||||
|     static double FrustrumZMargin; | ||||
|     static double FovMinDeg; | ||||
|     static double FovMaxDeg; | ||||
| 
 | ||||
|     enum EType : unsigned char | ||||
|     { | ||||
|         Unknown, | ||||
| //        Perspective,
 | ||||
|         Ortho, | ||||
|         Perspective, | ||||
|         Num_types | ||||
|     }; | ||||
| 
 | ||||
|     EType type; | ||||
|     float zoom; | ||||
|     float phi; | ||||
| //    float distance;
 | ||||
|     bool requires_zoom_to_bed; | ||||
|     bool inverted_phi; | ||||
| 
 | ||||
| private: | ||||
|     EType m_type; | ||||
|     Vec3d m_target; | ||||
|     float m_theta; | ||||
|     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<int, 4> m_viewport; | ||||
|     mutable Transform3d m_view_matrix; | ||||
|     mutable Transform3d m_projection_matrix; | ||||
|     mutable std::pair<double, double> m_frustrum_zs; | ||||
| 
 | ||||
|     BoundingBoxf3 m_scene_box; | ||||
| 
 | ||||
| public: | ||||
|     Camera(); | ||||
| 
 | ||||
|     EType get_type() const { return m_type; } | ||||
|     std::string get_type_as_string() const; | ||||
|     void set_type(EType type); | ||||
|     void set_type(const std::string& type); | ||||
|     void select_next_type(); | ||||
| 
 | ||||
|     const Vec3d& get_target() const { return m_target; } | ||||
|     void set_target(const Vec3d& target); | ||||
| 
 | ||||
|     double get_distance() const { return m_distance; } | ||||
|     double get_gui_scale() const { return m_gui_scale; } | ||||
| 
 | ||||
|     float get_theta() const { return m_theta; } | ||||
|     void set_theta(float theta, bool apply_limit); | ||||
| 
 | ||||
|     double get_zoom() const { return m_zoom; } | ||||
|     void set_zoom(double zoom, const BoundingBoxf3& max_box, int canvas_w, int canvas_h); | ||||
|     void set_zoom(double zoom) { m_zoom = zoom; } | ||||
| 
 | ||||
|     const BoundingBoxf3& get_scene_box() const { return m_scene_box; } | ||||
|     void set_scene_box(const BoundingBoxf3& box); | ||||
|     void set_scene_box(const BoundingBoxf3& box) { m_scene_box = box; } | ||||
| 
 | ||||
|     bool select_view(const std::string& direction); | ||||
| 
 | ||||
|  | @ -60,9 +80,26 @@ public: | |||
| 
 | ||||
|     Vec3d get_position() const { return m_view_matrix.matrix().inverse().block(0, 3, 3, 1); } | ||||
| 
 | ||||
|     double get_near_z() const { return m_frustrum_zs.first; } | ||||
|     double get_far_z() const { return m_frustrum_zs.second; } | ||||
| 
 | ||||
|     double get_fov() const; | ||||
| 
 | ||||
|     void apply_viewport(int x, int y, unsigned int w, unsigned int h) const; | ||||
|     void apply_view_matrix() const; | ||||
|     void apply_ortho_projection(float x_min, float x_max, float y_min, float y_max, float z_min, float z_max) const; | ||||
|     void apply_projection(const BoundingBoxf3& box) const; | ||||
| 
 | ||||
|     void zoom_to_box(const BoundingBoxf3& box, int canvas_w, int canvas_h); | ||||
| 
 | ||||
| #if ENABLE_CAMERA_STATISTICS | ||||
|     void debug_render() const; | ||||
| #endif // ENABLE_CAMERA_STATISTICS
 | ||||
| 
 | ||||
| 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
 | ||||
|     std::pair<double, double> calc_tight_frustrum_zs_around(const BoundingBoxf3& box) const; | ||||
|     double calc_zoom_to_bounding_box_factor(const BoundingBoxf3& box, int canvas_w, int canvas_h) const; | ||||
| }; | ||||
| 
 | ||||
| } // GUI
 | ||||
|  |  | |||
|  | @ -300,22 +300,10 @@ void GLCanvas3D::LayersEditing::render_overlay(const GLCanvas3D& canvas) const | |||
|     const Rect& bar_rect = get_bar_rect_viewport(canvas); | ||||
|     const Rect& reset_rect = get_reset_rect_viewport(canvas); | ||||
| 
 | ||||
|     glsafe(::glDisable(GL_DEPTH_TEST)); | ||||
| 
 | ||||
|     // The viewport and camera are set to complete view and glOrtho(-$x / 2, $x / 2, -$y / 2, $y / 2, -$depth, $depth),
 | ||||
|     // where x, y is the window size divided by $self->_zoom.
 | ||||
|     glsafe(::glPushMatrix()); | ||||
|     glsafe(::glLoadIdentity()); | ||||
| 
 | ||||
|     _render_tooltip_texture(canvas, bar_rect, reset_rect); | ||||
|     _render_reset_texture(reset_rect); | ||||
|     _render_active_object_annotations(canvas, bar_rect); | ||||
|     _render_profile(bar_rect); | ||||
| 
 | ||||
|     // Revert the matrices.
 | ||||
|     glsafe(::glPopMatrix()); | ||||
| 
 | ||||
|     glsafe(::glEnable(GL_DEPTH_TEST)); | ||||
| } | ||||
| 
 | ||||
| float GLCanvas3D::LayersEditing::get_cursor_z_relative(const GLCanvas3D& canvas) | ||||
|  | @ -370,7 +358,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 = canvas.get_camera().zoom; | ||||
|     float zoom = (float)canvas.get_camera().get_zoom(); | ||||
|     float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; | ||||
| 
 | ||||
|     return Rect((half_w - thickness_bar_width(canvas)) * inv_zoom, half_h * inv_zoom, half_w * inv_zoom, (-half_h + reset_button_height(canvas)) * inv_zoom); | ||||
|  | @ -382,7 +370,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 = canvas.get_camera().zoom; | ||||
|     float zoom = (float)canvas.get_camera().get_zoom(); | ||||
|     float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; | ||||
| 
 | ||||
|     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); | ||||
|  | @ -413,7 +401,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 = canvas.get_camera().zoom; | ||||
|     float zoom = (float)canvas.get_camera().get_zoom(); | ||||
|     float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; | ||||
|     float gap = 10.0f * inv_zoom; | ||||
| 
 | ||||
|  | @ -882,12 +870,8 @@ 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)) | ||||
|     { | ||||
|         glsafe(::glDisable(GL_DEPTH_TEST)); | ||||
|         glsafe(::glPushMatrix()); | ||||
|         glsafe(::glLoadIdentity()); | ||||
| 
 | ||||
|         const Size& cnv_size = canvas.get_canvas_size(); | ||||
|         float zoom = canvas.get_camera().zoom; | ||||
|         float zoom = (float)canvas.get_camera().get_zoom(); | ||||
|         float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; | ||||
|         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; | ||||
|  | @ -906,9 +890,6 @@ void GLCanvas3D::WarningTexture::render(const GLCanvas3D& canvas) const | |||
|         uvs.right_top = { uv_right, uv_top }; | ||||
| 
 | ||||
|         GLTexture::render_sub_texture(m_id, left, right, bottom, top, uvs); | ||||
| 
 | ||||
|         glsafe(::glPopMatrix()); | ||||
|         glsafe(::glEnable(GL_DEPTH_TEST)); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | @ -1165,12 +1146,8 @@ 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)) | ||||
|     { | ||||
|         glsafe(::glDisable(GL_DEPTH_TEST)); | ||||
|         glsafe(::glPushMatrix()); | ||||
|         glsafe(::glLoadIdentity()); | ||||
| 
 | ||||
|         const Size& cnv_size = canvas.get_canvas_size(); | ||||
|         float zoom = canvas.get_camera().zoom; | ||||
|         float zoom = (float)canvas.get_camera().get_zoom(); | ||||
|         float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; | ||||
|         float left = (-0.5f * (float)cnv_size.get_width()) * inv_zoom; | ||||
|         float top = (0.5f * (float)cnv_size.get_height()) * inv_zoom; | ||||
|  | @ -1189,9 +1166,6 @@ void GLCanvas3D::LegendTexture::render(const GLCanvas3D& canvas) const | |||
|         uvs.right_top = { uv_right, uv_top }; | ||||
| 
 | ||||
|         GLTexture::render_sub_texture(m_id, left, right, bottom, top, uvs); | ||||
| 
 | ||||
|         glsafe(::glPopMatrix()); | ||||
|         glsafe(::glEnable(GL_DEPTH_TEST)); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | @ -1476,7 +1450,7 @@ BoundingBoxf3 GLCanvas3D::volumes_bounding_box() const | |||
| BoundingBoxf3 GLCanvas3D::scene_bounding_box() const | ||||
| { | ||||
|     BoundingBoxf3 bb = volumes_bounding_box(); | ||||
|     bb.merge(m_bed.get_bounding_box()); | ||||
|     bb.merge(m_bed.get_bounding_box(false)); | ||||
| 
 | ||||
|     if (m_config != nullptr) | ||||
|     { | ||||
|  | @ -1484,6 +1458,7 @@ BoundingBoxf3 GLCanvas3D::scene_bounding_box() const | |||
|         bb.min(2) = std::min(bb.min(2), -h); | ||||
|         bb.max(2) = std::max(bb.max(2), h); | ||||
|     } | ||||
| 
 | ||||
|     return bb; | ||||
| } | ||||
| 
 | ||||
|  | @ -1559,20 +1534,20 @@ void GLCanvas3D::allow_multisample(bool allow) | |||
| 
 | ||||
| void GLCanvas3D::zoom_to_bed() | ||||
| { | ||||
|     _zoom_to_bounding_box(m_bed.get_bounding_box()); | ||||
|     _zoom_to_box(m_bed.get_bounding_box(false)); | ||||
| } | ||||
| 
 | ||||
| void GLCanvas3D::zoom_to_volumes() | ||||
| { | ||||
|     m_apply_zoom_to_volumes_filter = true; | ||||
|     _zoom_to_bounding_box(volumes_bounding_box()); | ||||
|     _zoom_to_box(volumes_bounding_box()); | ||||
|     m_apply_zoom_to_volumes_filter = false; | ||||
| } | ||||
| 
 | ||||
| void GLCanvas3D::zoom_to_selection() | ||||
| { | ||||
|     if (!m_selection.is_empty()) | ||||
|         _zoom_to_bounding_box(m_selection.get_bounding_box()); | ||||
|         _zoom_to_box(m_selection.get_bounding_box()); | ||||
| } | ||||
| 
 | ||||
| void GLCanvas3D::select_view(const std::string& direction) | ||||
|  | @ -1633,6 +1608,7 @@ void GLCanvas3D::render() | |||
|     } | ||||
| 
 | ||||
|     m_camera.apply_view_matrix(); | ||||
|     m_camera.apply_projection(_max_bounding_box(true)); | ||||
| 
 | ||||
|     GLfloat position_cam[4] = { 1.0f, 0.0f, 1.0f, 0.0f }; | ||||
|     glsafe(::glLightfv(GL_LIGHT1, GL_POSITION, position_cam)); | ||||
|  | @ -1694,16 +1670,7 @@ void GLCanvas3D::render() | |||
|         m_rectangle_selection.render(*this); | ||||
| 
 | ||||
|     // draw overlays
 | ||||
|     _render_gizmos_overlay(); | ||||
|     _render_warning_texture(); | ||||
|     _render_legend_texture(); | ||||
| #if !ENABLE_SVG_ICONS | ||||
|     _resize_toolbars(); | ||||
| #endif // !ENABLE_SVG_ICONS
 | ||||
|     _render_toolbar(); | ||||
|     _render_view_toolbar(); | ||||
|     if ((m_layers_editing.last_object_id >= 0) && (m_layers_editing.object_max_z() > 0.0f)) | ||||
|         m_layers_editing.render_overlay(*this); | ||||
|     _render_overlays(); | ||||
| 
 | ||||
| #if ENABLE_RENDER_STATISTICS | ||||
|     ImGuiWrapper& imgui = *wxGetApp().imgui(); | ||||
|  | @ -1724,6 +1691,10 @@ void GLCanvas3D::render() | |||
|     imgui.end(); | ||||
| #endif // ENABLE_RENDER_STATISTICS
 | ||||
| 
 | ||||
| #if ENABLE_CAMERA_STATISTICS | ||||
|     m_camera.debug_render(); | ||||
| #endif // ENABLE_CAMERA_STATISTICS
 | ||||
| 
 | ||||
|     wxGetApp().imgui()->render(); | ||||
| 
 | ||||
|     m_canvas->SwapBuffers(); | ||||
|  | @ -2426,9 +2397,11 @@ void GLCanvas3D::on_char(wxKeyEvent& evt) | |||
|         case 'B': | ||||
|         case 'b': { zoom_to_bed(); break; } | ||||
|         case 'I': | ||||
|         case 'i': { set_camera_zoom(1.0f); break; } | ||||
|         case 'i': { set_camera_zoom(1.0); break; } | ||||
|         case 'K': | ||||
|         case 'k': { m_camera.select_next_type(); m_dirty = true; break; } | ||||
|         case 'O': | ||||
|         case 'o': { set_camera_zoom(-1.0f); break; } | ||||
|         case 'o': { set_camera_zoom(-1.0); break; } | ||||
|         case 'Z': | ||||
|         case 'z': { m_selection.is_empty() ? zoom_to_volumes() : zoom_to_selection(); break; } | ||||
|         default:  { evt.Skip(); break; } | ||||
|  | @ -2549,7 +2522,7 @@ void GLCanvas3D::on_mouse_wheel(wxMouseEvent& evt) | |||
|                 m_layers_editing.band_width = std::max(std::min(m_layers_editing.band_width * (1.0f + 0.1f * (float)evt.GetWheelRotation() / (float)evt.GetWheelDelta()), 10.0f), 1.5f); | ||||
|                 if (m_canvas != nullptr) | ||||
|                     m_canvas->Refresh(); | ||||
|                  | ||||
| 
 | ||||
|                 return; | ||||
|             } | ||||
|         } | ||||
|  | @ -2560,8 +2533,7 @@ void GLCanvas3D::on_mouse_wheel(wxMouseEvent& evt) | |||
|         return; | ||||
| 
 | ||||
|     // Calculate the zoom delta and apply it to the current zoom factor
 | ||||
|     float zoom = (float)evt.GetWheelRotation() / (float)evt.GetWheelDelta(); | ||||
|     set_camera_zoom(zoom); | ||||
|     set_camera_zoom((double)evt.GetWheelRotation() / (double)evt.GetWheelDelta()); | ||||
| } | ||||
| 
 | ||||
| void GLCanvas3D::on_timer(wxTimerEvent& evt) | ||||
|  | @ -3313,21 +3285,11 @@ void GLCanvas3D::do_mirror() | |||
|     post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); | ||||
| } | ||||
| 
 | ||||
| void GLCanvas3D::set_camera_zoom(float zoom) | ||||
| void GLCanvas3D::set_camera_zoom(double zoom) | ||||
| { | ||||
|     zoom = std::max(std::min(zoom, 4.0f), -4.0f) / 10.0f; | ||||
|     zoom = m_camera.zoom / (1.0f - zoom); | ||||
| 
 | ||||
|     // Don't allow to zoom too far outside the scene.
 | ||||
|     float zoom_min = _get_zoom_to_bounding_box_factor(_max_bounding_box()); | ||||
|     if (zoom_min > 0.0f) | ||||
|         zoom = std::max(zoom, zoom_min * 0.7f); | ||||
| 
 | ||||
|     // Don't allow to zoom too close to the scene.
 | ||||
|     zoom = std::min(zoom, 100.0f); | ||||
| 
 | ||||
|     m_camera.zoom = zoom; | ||||
|     _refresh_if_shown_on_screen(); | ||||
|     const Size& cnv_size = get_canvas_size(); | ||||
|     m_camera.set_zoom(zoom, _max_bounding_box(false), cnv_size.get_width(), cnv_size.get_height()); | ||||
|     m_dirty = true; | ||||
| } | ||||
| 
 | ||||
| void GLCanvas3D::update_gizmos_on_off_state() | ||||
|  | @ -3361,8 +3323,7 @@ void GLCanvas3D::update_ui_from_settings() | |||
|     if (new_scaling != orig_scaling) { | ||||
|         BOOST_LOG_TRIVIAL(debug) << "GLCanvas3D: Scaling factor: " << new_scaling; | ||||
| 
 | ||||
|         m_camera.zoom /= orig_scaling; | ||||
|         m_camera.zoom *= new_scaling; | ||||
|         m_camera.set_zoom(m_camera.get_zoom() * new_scaling / orig_scaling); | ||||
|         _refresh_if_shown_on_screen(); | ||||
|     } | ||||
| #endif | ||||
|  | @ -3409,7 +3370,7 @@ Linef3 GLCanvas3D::mouse_ray(const Point& mouse_pos) | |||
| 
 | ||||
| double GLCanvas3D::get_size_proportional_to_max_bed_size(double factor) const | ||||
| { | ||||
|     return factor * m_bed.get_bounding_box().max_size(); | ||||
|     return factor * m_bed.get_bounding_box(false).max_size(); | ||||
| } | ||||
| 
 | ||||
| void GLCanvas3D::set_cursor(ECursorType type) | ||||
|  | @ -3640,143 +3601,25 @@ void GLCanvas3D::_resize(unsigned int w, unsigned int h) | |||
| 
 | ||||
|     // ensures that this canvas is current
 | ||||
|     _set_current(); | ||||
| 
 | ||||
|     // updates camera
 | ||||
|     m_camera.apply_viewport(0, 0, w, h); | ||||
| 
 | ||||
|     const BoundingBoxf3& bbox = _max_bounding_box(); | ||||
| 
 | ||||
|     switch (m_camera.type) | ||||
|     { | ||||
|     case Camera::Ortho: | ||||
|     { | ||||
|         float w2 = w; | ||||
|         float h2 = h; | ||||
|         float two_zoom = 2.0f * m_camera.zoom; | ||||
|         if (two_zoom != 0.0f) | ||||
|         { | ||||
|             float inv_two_zoom = 1.0f / two_zoom; | ||||
|             w2 *= inv_two_zoom; | ||||
|             h2 *= inv_two_zoom; | ||||
|         } | ||||
| 
 | ||||
|         // FIXME: calculate a tighter value for depth will improve z-fighting
 | ||||
|         // Set at least some minimum depth in case the bounding box is empty to avoid an OpenGL driver error.
 | ||||
|         float depth = std::max(1.f, 5.0f * (float)bbox.max_size()); | ||||
|         m_camera.apply_ortho_projection(-w2, w2, -h2, h2, -depth, depth); | ||||
| 
 | ||||
|         break; | ||||
|     } | ||||
| //    case Camera::Perspective:
 | ||||
| //    {
 | ||||
| //        float bbox_r = (float)bbox.radius();
 | ||||
| //        float fov = PI * 45.0f / 180.0f;
 | ||||
| //        float fov_tan = tan(0.5f * fov);
 | ||||
| //        float cam_distance = 0.5f * bbox_r / fov_tan;
 | ||||
| //        m_camera.distance = cam_distance;
 | ||||
| //
 | ||||
| //        float nr = cam_distance - bbox_r * 1.1f;
 | ||||
| //        float fr = cam_distance + bbox_r * 1.1f;
 | ||||
| //        if (nr < 1.0f)
 | ||||
| //            nr = 1.0f;
 | ||||
| //
 | ||||
| //        if (fr < nr + 1.0f)
 | ||||
| //            fr = nr + 1.0f;
 | ||||
| //
 | ||||
| //        float h2 = fov_tan * nr;
 | ||||
| //        float w2 = h2 * w / h;
 | ||||
| //        ::glFrustum(-w2, w2, -h2, h2, nr, fr);
 | ||||
| //
 | ||||
| //        break;
 | ||||
| //    }
 | ||||
|     default: | ||||
|     { | ||||
|         throw std::runtime_error("Invalid camera type."); | ||||
|         break; | ||||
|     } | ||||
|     } | ||||
| 
 | ||||
|     m_dirty = false; | ||||
| } | ||||
| 
 | ||||
| BoundingBoxf3 GLCanvas3D::_max_bounding_box() const | ||||
| BoundingBoxf3 GLCanvas3D::_max_bounding_box(bool include_bed_model) const | ||||
| { | ||||
|     BoundingBoxf3 bb = volumes_bounding_box(); | ||||
|     bb.merge(m_bed.get_bounding_box()); | ||||
|     bb.merge(m_bed.get_bounding_box(include_bed_model)); | ||||
|     return bb; | ||||
| } | ||||
| 
 | ||||
| void GLCanvas3D::_zoom_to_bounding_box(const BoundingBoxf3& bbox) | ||||
| void GLCanvas3D::_zoom_to_box(const BoundingBoxf3& box) | ||||
| { | ||||
|     // Calculate the zoom factor needed to adjust viewport to bounding box.
 | ||||
|     float zoom = _get_zoom_to_bounding_box_factor(bbox); | ||||
|     if (zoom > 0.0f) | ||||
|     { | ||||
|         m_camera.zoom = zoom; | ||||
|         // center view around bounding box center
 | ||||
|         m_camera.set_target(bbox.center()); | ||||
|         m_dirty = true; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| float GLCanvas3D::_get_zoom_to_bounding_box_factor(const BoundingBoxf3& bbox) const | ||||
| { | ||||
|     float max_bb_size = bbox.max_size(); | ||||
|     if (max_bb_size == 0.0f) | ||||
|         return -1.0f; | ||||
| 
 | ||||
|     // project the bbox vertices on a plane perpendicular to the camera forward axis
 | ||||
|     // then calculates the vertices coordinate on this plane along the camera xy axes
 | ||||
| 
 | ||||
|     // we need the view matrix, we let opengl calculate it (same as done in render())
 | ||||
|     m_camera.apply_view_matrix(); | ||||
| 
 | ||||
|     Vec3d right = m_camera.get_dir_right(); | ||||
|     Vec3d up = m_camera.get_dir_up(); | ||||
|     Vec3d forward = m_camera.get_dir_forward(); | ||||
| 
 | ||||
|     Vec3d bb_min = bbox.min; | ||||
|     Vec3d bb_max = bbox.max; | ||||
|     Vec3d bb_center = bbox.center(); | ||||
| 
 | ||||
|     // bbox vertices in world space
 | ||||
|     std::vector<Vec3d> vertices; | ||||
|     vertices.reserve(8); | ||||
|     vertices.push_back(bb_min); | ||||
|     vertices.emplace_back(bb_max(0), bb_min(1), bb_min(2)); | ||||
|     vertices.emplace_back(bb_max(0), bb_max(1), bb_min(2)); | ||||
|     vertices.emplace_back(bb_min(0), bb_max(1), bb_min(2)); | ||||
|     vertices.emplace_back(bb_min(0), bb_min(1), bb_max(2)); | ||||
|     vertices.emplace_back(bb_max(0), bb_min(1), bb_max(2)); | ||||
|     vertices.push_back(bb_max); | ||||
|     vertices.emplace_back(bb_min(0), bb_max(1), bb_max(2)); | ||||
| 
 | ||||
|     double max_x = 0.0; | ||||
|     double max_y = 0.0; | ||||
| 
 | ||||
|     // margin factor to give some empty space around the bbox
 | ||||
|     double margin_factor = 1.25; | ||||
| 
 | ||||
|     for (const Vec3d& v : vertices) | ||||
|     { | ||||
|         // project vertex on the plane perpendicular to camera forward axis
 | ||||
|         Vec3d pos(v(0) - bb_center(0), v(1) - bb_center(1), v(2) - bb_center(2)); | ||||
|         Vec3d proj_on_plane = pos - pos.dot(forward) * forward; | ||||
| 
 | ||||
|         // calculates vertex coordinate along camera xy axes
 | ||||
|         double x_on_plane = proj_on_plane.dot(right); | ||||
|         double y_on_plane = proj_on_plane.dot(up); | ||||
| 
 | ||||
|         max_x = std::max(max_x, margin_factor * std::abs(x_on_plane)); | ||||
|         max_y = std::max(max_y, margin_factor * std::abs(y_on_plane)); | ||||
|     } | ||||
| 
 | ||||
|     if ((max_x == 0.0) || (max_y == 0.0)) | ||||
|         return -1.0f; | ||||
| 
 | ||||
|     max_x *= 2.0; | ||||
|     max_y *= 2.0; | ||||
| 
 | ||||
|     const Size& cnv_size = get_canvas_size(); | ||||
|     return (float)std::min((double)cnv_size.get_width() / max_x, (double)cnv_size.get_height() / max_y); | ||||
|     m_camera.zoom_to_box(box, cnv_size.get_width(), cnv_size.get_height()); | ||||
|     m_dirty = true; | ||||
| } | ||||
| 
 | ||||
| void GLCanvas3D::_refresh_if_shown_on_screen() | ||||
|  | @ -3991,7 +3834,7 @@ void GLCanvas3D::_render_objects() const | |||
| 
 | ||||
|             if (m_config != nullptr) | ||||
|             { | ||||
|                 const BoundingBoxf3& bed_bb = m_bed.get_bounding_box(); | ||||
|                 const BoundingBoxf3& bed_bb = m_bed.get_bounding_box(false); | ||||
|                 m_volumes.set_print_box((float)bed_bb.min(0), (float)bed_bb.min(1), 0.0f, (float)bed_bb.max(0), (float)bed_bb.max(1), (float)m_config->opt_float("max_print_height")); | ||||
|                 m_volumes.check_outside_state(m_config, nullptr); | ||||
|             } | ||||
|  | @ -4073,6 +3916,32 @@ void GLCanvas3D::_render_selection_center() const | |||
| } | ||||
| #endif // ENABLE_RENDER_SELECTION_CENTER
 | ||||
| 
 | ||||
| void GLCanvas3D::_render_overlays() const | ||||
| { | ||||
|     glsafe(::glDisable(GL_DEPTH_TEST)); | ||||
|     glsafe(::glPushMatrix()); | ||||
|     glsafe(::glLoadIdentity()); | ||||
|     // ensure that the textures are renderered inside the frustrum
 | ||||
|     glsafe(::glTranslated(0.0, 0.0, -(m_camera.get_near_z() + 0.5))); | ||||
|     // ensure that the overlay fits the frustrum near z plane
 | ||||
|     double gui_scale = m_camera.get_gui_scale(); | ||||
|     glsafe(::glScaled(gui_scale, gui_scale, 1.0)); | ||||
| 
 | ||||
|     _render_gizmos_overlay(); | ||||
|     _render_warning_texture(); | ||||
|     _render_legend_texture(); | ||||
| #if !ENABLE_SVG_ICONS | ||||
|     _resize_toolbars(); | ||||
| #endif // !ENABLE_SVG_ICONS
 | ||||
|     _render_toolbar(); | ||||
|     _render_view_toolbar(); | ||||
| 
 | ||||
|     if ((m_layers_editing.last_object_id >= 0) && (m_layers_editing.object_max_z() > 0.0f)) | ||||
|         m_layers_editing.render_overlay(*this); | ||||
| 
 | ||||
|     glsafe(::glPopMatrix()); | ||||
| } | ||||
| 
 | ||||
| void GLCanvas3D::_render_warning_texture() const | ||||
| { | ||||
|     m_warning_texture.render(*this); | ||||
|  | @ -4169,7 +4038,7 @@ void GLCanvas3D::_render_toolbar() const | |||
| #endif // ENABLE_RETINA_GL
 | ||||
| 
 | ||||
|     Size cnv_size = get_canvas_size(); | ||||
|     float zoom = m_camera.zoom; | ||||
|     float zoom = (float)m_camera.get_zoom(); | ||||
|     float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; | ||||
| 
 | ||||
|     GLToolbar::Layout::EOrientation orientation = m_toolbar.get_layout_orientation(); | ||||
|  | @ -4237,7 +4106,7 @@ void GLCanvas3D::_render_view_toolbar() const | |||
| #endif // ENABLE_RETINA_GL
 | ||||
| 
 | ||||
|     Size cnv_size = get_canvas_size(); | ||||
|     float zoom = m_camera.zoom; | ||||
|     float zoom = (float)m_camera.get_zoom(); | ||||
|     float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; | ||||
| 
 | ||||
|     // places the toolbar on the bottom-left corner of the 3d scene
 | ||||
|  |  | |||
|  | @ -600,7 +600,7 @@ public: | |||
|     void do_flatten(); | ||||
|     void do_mirror(); | ||||
| 
 | ||||
|     void set_camera_zoom(float zoom); | ||||
|     void set_camera_zoom(double zoom); | ||||
| 
 | ||||
|     void update_gizmos_on_off_state(); | ||||
|     void reset_all_gizmos() { m_gizmos.reset_all_states(); } | ||||
|  | @ -641,10 +641,9 @@ private: | |||
|     bool _set_current(); | ||||
|     void _resize(unsigned int w, unsigned int h); | ||||
| 
 | ||||
|     BoundingBoxf3 _max_bounding_box() const; | ||||
|     BoundingBoxf3 _max_bounding_box(bool include_bed_model) const; | ||||
| 
 | ||||
|     void _zoom_to_bounding_box(const BoundingBoxf3& bbox); | ||||
|     float _get_zoom_to_bounding_box_factor(const BoundingBoxf3& bbox) const; | ||||
|     void _zoom_to_box(const BoundingBoxf3& box); | ||||
| 
 | ||||
|     void _refresh_if_shown_on_screen(); | ||||
| 
 | ||||
|  | @ -658,6 +657,7 @@ private: | |||
| #if ENABLE_RENDER_SELECTION_CENTER | ||||
|     void _render_selection_center() const; | ||||
| #endif // ENABLE_RENDER_SELECTION_CENTER
 | ||||
|     void _render_overlays() const; | ||||
|     void _render_warning_texture() const; | ||||
|     void _render_legend_texture() const; | ||||
|     void _render_volumes_for_picking() const; | ||||
|  |  | |||
|  | @ -68,7 +68,7 @@ namespace GUI { | |||
|         if (!is_dragging()) | ||||
|             return; | ||||
| 
 | ||||
|         float zoom = canvas.get_camera().zoom; | ||||
|         float zoom = (float)canvas.get_camera().get_zoom(); | ||||
|         float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; | ||||
| 
 | ||||
|         Size cnv_size = canvas.get_canvas_size(); | ||||
|  |  | |||
|  | @ -390,19 +390,12 @@ void GLToolbar::render(const GLCanvas3D& parent) const | |||
|         generate_icons_texture(); | ||||
| #endif // ENABLE_SVG_ICONS
 | ||||
| 
 | ||||
|     glsafe(::glDisable(GL_DEPTH_TEST)); | ||||
| 
 | ||||
|     glsafe(::glPushMatrix()); | ||||
|     glsafe(::glLoadIdentity()); | ||||
| 
 | ||||
|     switch (m_layout.type) | ||||
|     { | ||||
|     default: | ||||
|     case Layout::Horizontal: { render_horizontal(parent); break; } | ||||
|     case Layout::Vertical: { render_vertical(parent); break; } | ||||
|     } | ||||
| 
 | ||||
|     glsafe(::glPopMatrix()); | ||||
| } | ||||
| 
 | ||||
| bool GLToolbar::on_mouse(wxMouseEvent& evt, GLCanvas3D& parent) | ||||
|  | @ -614,7 +607,7 @@ std::string GLToolbar::update_hover_state_horizontal(const Vec2d& mouse_pos, GLC | |||
| { | ||||
|     // NB: mouse_pos is already scaled appropriately
 | ||||
| 
 | ||||
|     float zoom = parent.get_camera().zoom; | ||||
|     float zoom = (float)parent.get_camera().get_zoom(); | ||||
|     float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; | ||||
| #if ENABLE_SVG_ICONS | ||||
|     float factor = m_layout.scale * inv_zoom; | ||||
|  | @ -719,7 +712,7 @@ std::string GLToolbar::update_hover_state_vertical(const Vec2d& mouse_pos, GLCan | |||
| { | ||||
|     // NB: mouse_pos is already scaled appropriately
 | ||||
| 
 | ||||
|     float zoom = parent.get_camera().zoom; | ||||
|     float zoom = (float)parent.get_camera().get_zoom(); | ||||
|     float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; | ||||
| #if ENABLE_SVG_ICONS | ||||
|     float factor = m_layout.scale * inv_zoom; | ||||
|  | @ -836,7 +829,7 @@ int GLToolbar::contains_mouse_horizontal(const Vec2d& mouse_pos, const GLCanvas3 | |||
| { | ||||
|     // NB: mouse_pos is already scaled appropriately
 | ||||
| 
 | ||||
|     float zoom = parent.get_camera().zoom; | ||||
|     float zoom = (float)parent.get_camera().get_zoom(); | ||||
|     float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; | ||||
| #if ENABLE_SVG_ICONS | ||||
|     float factor = m_layout.scale * inv_zoom; | ||||
|  | @ -919,7 +912,7 @@ int GLToolbar::contains_mouse_vertical(const Vec2d& mouse_pos, const GLCanvas3D& | |||
| { | ||||
|     // NB: mouse_pos is already scaled appropriately
 | ||||
| 
 | ||||
|     float zoom = parent.get_camera().zoom; | ||||
|     float zoom = (float)parent.get_camera().get_zoom(); | ||||
|     float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; | ||||
| #if ENABLE_SVG_ICONS | ||||
|     float factor = m_layout.scale * inv_zoom; | ||||
|  | @ -1015,7 +1008,7 @@ void GLToolbar::render_horizontal(const GLCanvas3D& parent) const | |||
|         return; | ||||
| #endif // !ENABLE_SVG_ICONS
 | ||||
| 
 | ||||
|     float zoom = parent.get_camera().zoom; | ||||
|     float zoom = (float)parent.get_camera().get_zoom(); | ||||
|     float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; | ||||
| #if ENABLE_SVG_ICONS | ||||
|     float factor = inv_zoom * m_layout.scale; | ||||
|  | @ -1170,7 +1163,7 @@ void GLToolbar::render_vertical(const GLCanvas3D& parent) const | |||
|         return; | ||||
| #endif // !ENABLE_SVG_ICONS
 | ||||
| 
 | ||||
|     float zoom = parent.get_camera().zoom; | ||||
|     float zoom = (float)parent.get_camera().get_zoom(); | ||||
|     float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; | ||||
| #if ENABLE_SVG_ICONS | ||||
|     float factor = inv_zoom * m_layout.scale; | ||||
|  |  | |||
|  | @ -531,18 +531,9 @@ void GLGizmosManager::render_overlay(const GLCanvas3D& canvas, const Selection& | |||
|         generate_icons_texture(); | ||||
| #endif // ENABLE_SVG_ICONS
 | ||||
| 
 | ||||
|     glsafe(::glDisable(GL_DEPTH_TEST)); | ||||
| 
 | ||||
|     glsafe(::glPushMatrix()); | ||||
|     glsafe(::glLoadIdentity()); | ||||
| 
 | ||||
|     do_render_overlay(canvas, selection); | ||||
| 
 | ||||
|     glsafe(::glPopMatrix()); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| bool GLGizmosManager::on_mouse_wheel(wxMouseEvent& evt, GLCanvas3D& canvas) | ||||
| { | ||||
|     bool processed = false; | ||||
|  | @ -939,7 +930,7 @@ void GLGizmosManager::do_render_overlay(const GLCanvas3D& canvas, const Selectio | |||
| 
 | ||||
|     float cnv_w = (float)canvas.get_canvas_size().get_width(); | ||||
|     float cnv_h = (float)canvas.get_canvas_size().get_height(); | ||||
|     float zoom = canvas.get_camera().zoom; | ||||
|     float zoom = (float)canvas.get_camera().get_zoom(); | ||||
|     float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; | ||||
| 
 | ||||
|     float height = get_total_overlay_height(); | ||||
|  |  | |||
|  | @ -147,6 +147,7 @@ void KBShortcutsDialog::fill_shortcuts() | |||
|     plater_shortcuts.push_back(Shortcut("F",        L("Press to scale selection to fit print volume\nin Gizmo scale"))); | ||||
|     plater_shortcuts.push_back(Shortcut(alt,        L("Press to activate deselection rectangle\nor to scale or rotate selected objects\naround their own center"))); | ||||
|     plater_shortcuts.push_back(Shortcut(ctrl,       L("Press to activate one direction scaling in Gizmo scale"))); | ||||
|     plater_shortcuts.push_back(Shortcut("K",        L("Change camera type"))); | ||||
|     plater_shortcuts.push_back(Shortcut("B",        L("Zoom to Bed"))); | ||||
|     plater_shortcuts.push_back(Shortcut("Z",        L("Zoom to all objects in scene, if none selected"))); | ||||
|     plater_shortcuts.push_back(Shortcut("Z",        L("Zoom to selected object"))); | ||||
|  |  | |||
|  | @ -1772,6 +1772,9 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) | |||
|     q->Layout(); | ||||
| 
 | ||||
|     set_current_panel(view3D); | ||||
| 
 | ||||
|     // updates camera type from .ini file
 | ||||
|     camera.set_type(get_config("camera_type")); | ||||
| } | ||||
| 
 | ||||
| void Plater::priv::update(bool force_full_scene_refresh) | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Enrico Turri
						Enrico Turri