#ifndef slic3r_GLGizmoMeasure_hpp_ #define slic3r_GLGizmoMeasure_hpp_ #include "GLGizmoBase.hpp" #include "slic3r/GUI/GLModel.hpp" #include "slic3r/GUI/GUI_Utils.hpp" #include "slic3r/GUI/I18N.hpp" #include "libslic3r/Measure.hpp" #include "libslic3r/Model.hpp" namespace Slic3r { enum class ModelVolumeType : int; namespace Measure { class Measuring; } namespace GUI { enum class SLAGizmoEventType : unsigned char; enum class EMeasureMode : unsigned char { ONLY_MEASURE, ONLY_ASSEMBLY }; enum class AssemblyMode : unsigned char { FACE_FACE, POINT_POINT, }; static const Slic3r::ColorRGBA SELECTED_1ST_COLOR = {0.25f, 0.75f, 0.75f, 1.0f}; static const Slic3r::ColorRGBA SELECTED_2ND_COLOR = {0.75f, 0.25f, 0.75f, 1.0f}; static const Slic3r::ColorRGBA NEUTRAL_COLOR = {0.5f, 0.5f, 0.5f, 1.0f}; static const Slic3r::ColorRGBA HOVER_COLOR = {0.0f, 1.0f, 0.0f, 1.0f}; // Green static const int POINT_ID = 100; static const int EDGE_ID = 200; static const int CIRCLE_ID = 300; static const int PLANE_ID = 400; static const int SEL_SPHERE_1_ID = 501; static const int SEL_SPHERE_2_ID = 502; static const float TRIANGLE_BASE = 10.0f; static const float TRIANGLE_HEIGHT = TRIANGLE_BASE * 1.618033f; static const std::string CTRL_STR = #ifdef __APPLE__ "⌘" #else "Ctrl" #endif //__APPLE__ ; class TransformHelper { struct Cache { std::array viewport; Matrix4d ndc_to_ss_matrix; Transform3d ndc_to_ss_matrix_inverse; }; static Cache s_cache; public: static Vec3d model_to_world(const Vec3d &model, const Transform3d &world_matrix); static Vec4d world_to_clip(const Vec3d &world, const Matrix4d &projection_view_matrix); static Vec3d clip_to_ndc(const Vec4d &clip); static Vec2d ndc_to_ss(const Vec3d &ndc, const std::array &viewport); static Vec4d model_to_clip(const Vec3d &model, const Transform3d &world_matrix, const Matrix4d &projection_view_matrix); static Vec3d model_to_ndc(const Vec3d &model, const Transform3d &world_matrix, const Matrix4d &projection_view_matrix); static Vec2d model_to_ss(const Vec3d &model, const Transform3d &world_matrix, const Matrix4d &projection_view_matrix, const std::array &viewport); static Vec2d world_to_ss(const Vec3d &world, const Matrix4d &projection_view_matrix, const std::array &viewport); static const Matrix4d & ndc_to_ss_matrix(const std::array &viewport); static const Transform3d ndc_to_ss_matrix_inverse(const std::array &viewport); private: static void update(const std::array &viewport); }; class GLGizmoMeasure : public GLGizmoBase { protected: enum class EMode : unsigned char { FeatureSelection, PointSelection }; struct SelectedFeatures { struct Item { bool is_center{ false }; std::optional source; std::optional feature; bool operator == (const Item& other) const { return this->is_center == other.is_center && this->source == other.source && this->feature == other.feature; } bool operator != (const Item& other) const { return !operator == (other); } void reset() { is_center = false; source.reset(); feature.reset(); } }; Item first; Item second; void reset() { first.reset(); second.reset(); } bool operator == (const SelectedFeatures & other) const { if (this->first != other.first) return false; return this->second == other.second; } bool operator != (const SelectedFeatures & other) const { return !operator == (other); } }; struct VolumeCacheItem { const ModelObject* object{ nullptr }; const ModelInstance* instance{ nullptr }; const ModelVolume* volume{ nullptr }; Transform3d world_trafo; bool operator == (const VolumeCacheItem& other) const { return this->object == other.object && this->instance == other.instance && this->volume == other.volume && this->world_trafo.isApprox(other.world_trafo); } }; std::vector m_volumes_cache; EMode m_mode{ EMode::FeatureSelection }; Measure::MeasurementResult m_measurement_result; Measure::AssemblyAction m_assembly_action; std::map> m_mesh_measure_map; std::shared_ptr m_curr_measuring{nullptr}; //first feature std::shared_ptr m_sphere{nullptr}; std::shared_ptr m_cylinder{nullptr}; struct CircleGLModel { std::shared_ptr circle{nullptr}; Measure::SurfaceFeature *last_circle_feature{nullptr}; float inv_zoom{0}; }; CircleGLModel m_curr_circle; CircleGLModel m_feature_circle_first; CircleGLModel m_feature_circle_second; void init_circle_glmodel(GripperType gripper_type, const Measure::SurfaceFeature &feature, CircleGLModel &circle_gl_model, float inv_zoom); struct PlaneGLModel { int plane_idx{0}; std::shared_ptr plane{nullptr}; }; PlaneGLModel m_curr_plane; PlaneGLModel m_feature_plane_first; PlaneGLModel m_feature_plane_second; void init_plane_glmodel(GripperType gripper_type, const Measure::SurfaceFeature &feature, PlaneGLModel &plane_gl_model); struct Dimensioning { GLModel line; GLModel triangle; GLModel arc; }; Dimensioning m_dimensioning; std::map> m_mesh_raycaster_map; std::vector m_hit_different_volumes; std::vector m_hit_order_volumes; GLVolume* m_last_hit_volume; //std::vector> m_plane_models_cache; unsigned int m_last_active_item_imgui{0}; Vec3d m_buffered_distance; Vec3d m_distance; double m_buffered_parallel_distance{0}; double m_buffered_around_center{0}; // used to keep the raycasters for point/center spheres //std::vector> m_selected_sphere_raycasters; std::optional m_curr_feature; std::optional m_curr_point_on_feature_position; // These hold information to decide whether recalculation is necessary: float m_last_inv_zoom{ 0.0f }; std::optional m_last_circle_feature; int m_last_plane_idx{ -1 }; bool m_mouse_left_down{ false }; // for detection left_up of this gizmo bool m_mouse_left_down_mesh_deal{false};//for pick mesh KeyAutoRepeatFilter m_shift_kar_filter; SelectedFeatures m_selected_features; int m_pending_scale{ 0 }; bool m_set_center_coincidence{false}; bool m_editing_distance{ false }; bool m_is_editing_distance_first_frame{ true }; bool m_can_set_xyz_distance{false}; void update_if_needed(); void disable_scene_raycasters(); void restore_scene_raycasters_state(); void render_dimensioning(); #if ENABLE_MEASURE_GIZMO_DEBUG void render_debug_dialog(); #endif // ENABLE_MEASURE_GIZMO_DEBUG public: GLGizmoMeasure(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); /// /// Apply rotation on select plane /// /// Keep information about mouse click /// Return True when use the information otherwise False. bool on_mouse(const wxMouseEvent &mouse_event) override; void data_changed(bool is_serializing) override; virtual bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down); bool wants_enter_leave_snapshots() const override { return true; } std::string get_gizmo_entering_text() const override { return _u8L("Entering Measure gizmo"); } std::string get_gizmo_leaving_text() const override { return _u8L("Leaving Measure gizmo"); } //std::string get_action_snapshot_name() const override { return _u8L("Measure gizmo editing"); } protected: bool on_init() override; std::string on_get_name() const override; bool on_is_activable() const override; void on_render() override; void on_set_state() override; virtual void on_render_for_picking() override; void show_selection_ui(); void show_distance_xyz_ui(); void show_point_point_assembly(); void show_face_face_assembly_common(); void show_face_face_assembly_senior(); void init_render_input_window(); virtual void on_render_input_window(float x, float y, float bottom_limit) override; virtual void render_input_window_warning(bool same_model_object); void remove_selected_sphere_raycaster(int id); void update_measurement_result(); void show_tooltip_information(float caption_max, float x, float y); void reset_all_pick(); void reset_gripper_pick(GripperType id,bool is_all = false); void register_single_mesh_pick(); void update_single_mesh_pick(GLVolume* v); std::string format_double(double value); std::string format_vec3(const Vec3d &v); std::string surface_feature_type_as_string(Measure::SurfaceFeatureType type); std::string point_on_feature_type_as_string(Measure::SurfaceFeatureType type, int hover_id); std::string center_on_feature_type_as_string(Measure::SurfaceFeatureType type); bool is_feature_with_center(const Measure::SurfaceFeature &feature); Vec3d get_feature_offset(const Measure::SurfaceFeature &feature); void reset_all_feature(); void reset_feature1_render(); void reset_feature2_render(); void reset_feature1(); void reset_feature2(); bool is_two_volume_in_same_model_object(); Measure::Measuring* get_measuring_of_mesh(GLVolume *v, Transform3d &tran); void update_world_plane_features(Measure::Measuring *cur_measuring, Measure::SurfaceFeature &feautre); void update_feature_by_tran(Measure::SurfaceFeature & feature); void set_distance(bool same_model_object, const Vec3d &displacement, bool take_shot = true); void set_to_parallel(bool same_model_object, bool take_shot = true, bool is_anti_parallel = false); void set_to_reverse_rotation(bool same_model_object,int feature_index); void set_to_around_center_of_faces(bool same_model_object,float rotate_degree); void set_to_center_coincidence(bool same_model_object); void set_parallel_distance(bool same_model_object,float dist); bool is_pick_meet_assembly_mode(const SelectedFeatures::Item& item); protected: // This map holds all translated description texts, so they can be easily referenced during layout calculations // etc. When language changes, GUI is recreated and this class constructed again, so the change takes effect. std::map m_desc; bool m_show_reset_first_tip{false}; bool m_selected_wrong_feature_waring_tip{false}; EMeasureMode m_measure_mode{EMeasureMode::ONLY_MEASURE}; AssemblyMode m_assembly_mode{AssemblyMode::FACE_FACE}; bool m_flip_volume_2{false}; float m_space_size; float m_input_size_max; bool m_use_inches; std::string m_units; mutable bool m_same_model_object; mutable unsigned int m_current_active_imgui_id; }; } // namespace GUI } // namespace Slic3r #endif // slic3r_GLGizmoMeasure_hpp_