From 3c0e33136358c6f32ecf507c09021a7d72014dee Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 15 Nov 2022 12:17:18 +0100 Subject: [PATCH 01/89] Gizmo measure modified to accept single full instance selection, to combine the volumes meshes into a single mesh and pass it to the back end after transform it in world coordinates Changes embedded into tech ENABLE_GIZMO_MEASURE_WORLD_COORDINATES --- src/libslic3r/Measure.cpp | 37 ++++ src/libslic3r/Measure.hpp | 19 +- src/libslic3r/Technologies.hpp | 2 + src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 215 ++++++++++++++++++++++- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 35 ++++ src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp | 13 ++ src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp | 7 + src/slic3r/GUI/Selection.cpp | 13 ++ src/slic3r/GUI/Selection.hpp | 4 + 9 files changed, 338 insertions(+), 7 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index 43b9782a83..1ffd72c14d 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -45,6 +45,9 @@ public: std::optional get_feature(size_t face_idx, const Vec3d& point) const; std::vector> get_planes_triangle_indices() const; const std::vector& get_plane_features(unsigned int plane_id) const; +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + const TriangleMesh& get_mesh() const; +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES private: void update_planes(); @@ -52,7 +55,11 @@ private: std::vector m_planes; std::vector m_face_to_plane; +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + TriangleMesh m_mesh; +#else const indexed_triangle_set& m_its; +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES }; @@ -61,7 +68,11 @@ private: MeasuringImpl::MeasuringImpl(const indexed_triangle_set& its) +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES +: m_mesh(its) +#else : m_its{its} +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES { update_planes(); extract_features(); @@ -74,10 +85,17 @@ void MeasuringImpl::update_planes() // Now we'll go through all the facets and append Points of facets sharing the same normal. // This part is still performed in mesh coordinate system. +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + const size_t num_of_facets = m_mesh.its.indices.size(); + m_face_to_plane.resize(num_of_facets, size_t(-1)); + const std::vector face_normals = its_face_normals(m_mesh.its); + const std::vector face_neighbors = its_face_neighbors(m_mesh.its); +#else const size_t num_of_facets = m_its.indices.size(); m_face_to_plane.resize(num_of_facets, size_t(-1)); const std::vector face_normals = its_face_normals(m_its); const std::vector face_neighbors = its_face_neighbors(m_its); +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES std::vector facet_queue(num_of_facets, 0); int facet_queue_cnt = 0; const stl_normal* normal_ptr = nullptr; @@ -126,7 +144,11 @@ void MeasuringImpl::update_planes() assert(std::none_of(m_face_to_plane.begin(), m_face_to_plane.end(), [](size_t val) { return val == size_t(-1); })); // Now we will walk around each of the planes and save vertices which form the border. +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + SurfaceMesh sm(m_mesh.its); +#else SurfaceMesh sm(m_its); +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES for (int plane_id=0; plane_id < int(m_planes.size()); ++plane_id) { const auto& facets = m_planes[plane_id].facets; m_planes[plane_id].borders.clear(); @@ -508,6 +530,12 @@ const std::vector& MeasuringImpl::get_plane_features(unsigned in return m_planes[plane_id].surface_features; } +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES +const TriangleMesh& MeasuringImpl::get_mesh() const +{ + return this->m_mesh; +} +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES @@ -549,6 +577,13 @@ const std::vector& Measuring::get_plane_features(unsigned int pl return priv->get_plane_features(plane_id); } +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES +const TriangleMesh& Measuring::get_mesh() const +{ + return priv->get_mesh(); +} +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + const AngleAndEdges AngleAndEdges::Dummy = { 0.0, Vec3d::Zero(), { Vec3d::Zero(), Vec3d::Zero() }, { Vec3d::Zero(), Vec3d::Zero() }, 0.0, true }; static AngleAndEdges angle_edge_edge(const std::pair& e1, const std::pair& e2) @@ -1147,6 +1182,7 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& return result; } +#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES void DistAndPoints::transform(const Transform3d& trafo) { from = trafo * from; to = trafo * to; @@ -1167,6 +1203,7 @@ void AngleAndEdges::transform(const Transform3d& trafo) { const double average_scale = 0.5 * (new_e1.norm() / old_e1.norm() + new_e2.norm() / old_e2.norm()); radius = average_scale * radius; } +#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES diff --git a/src/libslic3r/Measure.hpp b/src/libslic3r/Measure.hpp index ede8c634ee..b2e2008d15 100644 --- a/src/libslic3r/Measure.hpp +++ b/src/libslic3r/Measure.hpp @@ -87,9 +87,11 @@ class MeasuringImpl; class Measuring { public: - // Construct the measurement object on a given its. The its must remain - // valid and unchanged during the whole lifetime of the object. - explicit Measuring(const indexed_triangle_set& its); + // Construct the measurement object on a given its. +#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + // The its must remain valid and unchanged during the whole lifetime of the object. +#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + explicit Measuring(const indexed_triangle_set& its); ~Measuring(); // Return a reference to a list of all features identified on the its. @@ -108,6 +110,11 @@ public: // Returns the surface features of the plane with the given index const std::vector& get_plane_features(unsigned int plane_id) const; +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + // Returns the mesh used for measuring + const TriangleMesh& get_mesh() const; +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + private: std::unique_ptr priv; }; @@ -119,7 +126,9 @@ struct DistAndPoints { Vec3d from; Vec3d to; +#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES void transform(const Transform3d& trafo); +#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES }; struct AngleAndEdges { @@ -132,7 +141,9 @@ struct AngleAndEdges { double radius; bool coplanar; +#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES void transform(const Transform3d& trafo); +#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES static const AngleAndEdges Dummy; }; @@ -151,6 +162,7 @@ struct MeasurementResult { return angle.has_value() || distance_infinite.has_value() || distance_strict.has_value() || distance_xyz.has_value(); } +#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES void transform(const Transform3d& trafo) { if (angle.has_value()) angle->transform(trafo); @@ -161,6 +173,7 @@ struct MeasurementResult { distance_xyz = (distance_strict->to - distance_strict->from).cwiseAbs(); } } +#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES }; // Returns distance/angle between two SurfaceFeatures. diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index a3e72cf0c5..9e7c660ae0 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -64,6 +64,8 @@ // Enable picking using raytracing #define ENABLE_RAYCAST_PICKING (1 && ENABLE_LEGACY_OPENGL_REMOVAL) #define ENABLE_RAYCAST_PICKING_DEBUG (0 && ENABLE_RAYCAST_PICKING) +// Enable gizmo measure combining volumes meshes and passing them to the backend in world coordinates +#define ENABLE_GIZMO_MEASURE_WORLD_COORDINATES (1 && ENABLE_2_5_0_ALPHA1) #endif // _prusaslicer_technologies_h_ diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 8b26422c8f..5ae906eac9 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -5,9 +5,11 @@ #include "slic3r/GUI/Plater.hpp" #include "slic3r/GUI/GUI_ObjectManipulation.hpp" -#include "slic3r/GUI/Gizmos/GLGizmosCommon.hpp" +#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES +#include "slic3r/GUI/Gizmos/GLGizmosCommon.hpp" #include "libslic3r/Model.hpp" +#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES #include "libslic3r/PresetBundle.hpp" #include "libslic3r/MeasureUtils.hpp" @@ -242,7 +244,10 @@ private: TransformHelper::Cache TransformHelper::s_cache = { { 0, 0, 0, 0 }, Matrix4d::Identity(), Transform3d::Identity() }; GLGizmoMeasure::GLGizmoMeasure(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) - : GLGizmoBase(parent, icon_filename, sprite_id) +: GLGizmoBase(parent, icon_filename, sprite_id) +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES +, m_raycaster(nullptr) +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES { GLModel::Geometry sphere_geometry = smooth_sphere(16, 7.5f); m_sphere.mesh_raycaster = std::make_unique(std::make_shared(sphere_geometry.get_as_indexed_triangle_set())); @@ -370,8 +375,10 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) if (m_selected_features != selected_features_old && m_selected_features.second.feature.has_value()) { m_measurement_result = Measure::get_measurement(*m_selected_features.first.feature, *m_selected_features.second.feature, m_measuring.get()); +#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES // transform to world coordinates m_measurement_result.transform(m_volume_matrix); +#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES } m_imgui->set_requires_extra_frame(); @@ -419,6 +426,9 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) void GLGizmoMeasure::data_changed() { +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + update_if_needed(); +#else const Selection& selection = m_parent.get_selection(); const ModelObject* model_object = nullptr; const ModelVolume* model_volume = nullptr; @@ -429,13 +439,16 @@ void GLGizmoMeasure::data_changed() } if (model_object != m_old_model_object || model_volume != m_old_model_volume) update_if_needed(); +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES m_last_inv_zoom = 0.0f; m_last_plane_idx = -1; if (m_pending_scale) { m_measurement_result = Measure::get_measurement(*m_selected_features.first.feature, *m_selected_features.second.feature, m_measuring.get()); +#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES // transform to world coordinates m_measurement_result.transform(m_volume_matrix); +#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES m_pending_scale = false; } else @@ -512,6 +525,9 @@ void GLGizmoMeasure::on_set_state() m_editing_distance = false; m_is_editing_distance_first_frame = true; m_measuring.reset(); +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + m_raycaster.release(); +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES } else { m_mode = EMode::FeatureSelection; @@ -528,10 +544,12 @@ void GLGizmoMeasure::on_set_state() } } +#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES CommonGizmosDataID GLGizmoMeasure::on_get_requirements() const { return CommonGizmosDataID(int(CommonGizmosDataID::SelectionInfo) | int(CommonGizmosDataID::Raycaster)); } +#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES std::string GLGizmoMeasure::on_get_name() const { @@ -543,9 +561,15 @@ bool GLGizmoMeasure::on_is_activable() const const Selection& selection = m_parent.get_selection(); bool res = (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA) ? selection.is_single_full_instance() : +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + selection.is_single_full_instance() || selection.is_single_volume() || selection.is_single_modifier(); + if (res) + res &= !selection.contains_sinking_volumes(); +#else selection.is_single_volume() || selection.is_single_volume_instance(); if (res) res &= !selection.get_first_volume()->is_sinking(); +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES return res; } @@ -562,8 +586,10 @@ void GLGizmoMeasure::on_render() const Selection& selection = m_parent.get_selection(); +#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES if ((wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA && selection.is_single_full_instance()) || (selection.is_single_volume() || selection.is_single_volume_instance())) { +#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES update_if_needed(); const Camera& camera = wxGetApp().plater()->get_camera(); @@ -572,7 +598,11 @@ void GLGizmoMeasure::on_render() Vec3f position_on_model; Vec3f normal_on_model; size_t model_facet_idx; +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + const bool mouse_on_object = m_raycaster.raycaster()->unproject_on_mesh(m_mouse_pos, Transform3d::Identity(), camera, position_on_model, normal_on_model, nullptr, &model_facet_idx); +#else const bool mouse_on_object = m_c->raycaster()->raycasters().front()->unproject_on_mesh(m_mouse_pos, m_volume_matrix, camera, position_on_model, normal_on_model, nullptr, &model_facet_idx); +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES const bool is_hovering_on_feature = (m_mode == EMode::PointSelection || m_mode == EMode::CenterSelection) && m_hover_id != -1; auto update_circle = [this, inv_zoom]() { @@ -581,7 +611,11 @@ void GLGizmoMeasure::on_render() m_last_circle = m_curr_feature; m_circle.reset(); const auto [center, radius, normal] = m_curr_feature->get_circle(); +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + GLModel::Geometry circle_geometry = init_torus_data(64, 16, center.cast(), float(radius), 5.0f * inv_zoom, normal.cast(), Transform3f::Identity()); +#else GLModel::Geometry circle_geometry = init_torus_data(64, 16, center.cast(), float(radius), 5.0f * inv_zoom, normal.cast(), m_volume_matrix.cast()); +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES m_circle.mesh_raycaster = std::make_unique(std::make_shared(circle_geometry.get_as_indexed_triangle_set())); m_circle.model.init_from(std::move(circle_geometry)); return true; @@ -639,7 +673,11 @@ void GLGizmoMeasure::on_render() const auto [idx, normal, point] = m_curr_feature->get_plane(); if (m_last_plane_idx != idx) { m_last_plane_idx = idx; +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + const indexed_triangle_set& its = m_measuring->get_mesh().its; +#else const indexed_triangle_set its = (m_old_model_volume != nullptr) ? m_old_model_volume->mesh().its : m_old_model_object->volumes.front()->mesh().its; +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES const std::vector> planes_triangles = m_measuring->get_planes_triangle_indices(); GLModel::Geometry init_data = init_plane_data(its, planes_triangles, idx); m_plane.reset(); @@ -689,12 +727,20 @@ void GLGizmoMeasure::on_render() if (extra.has_value() && m_hover_id == POINT_ID) m_curr_point_on_feature_position = *extra; else +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + m_curr_point_on_feature_position = position_on_feature(EDGE_ID, camera, [](const Vec3f& v) { return Vec3f(0.0f, 0.0f, v.z()); }); +#else m_curr_point_on_feature_position = m_volume_matrix.inverse() * position_on_feature(EDGE_ID, camera, [](const Vec3f& v) { return Vec3f(0.0f, 0.0f, v.z()); }); +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES break; } case Measure::SurfaceFeatureType::Plane: { +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + m_curr_point_on_feature_position = position_on_feature(PLANE_ID, camera); +#else m_curr_point_on_feature_position = m_volume_matrix.inverse() * position_on_feature(PLANE_ID, camera); +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES break; } case Measure::SurfaceFeatureType::Circle: @@ -704,9 +750,17 @@ void GLGizmoMeasure::on_render() m_curr_point_on_feature_position = center; else { const Vec3d world_pof = position_on_feature(CIRCLE_ID, camera, [](const Vec3f& v) { return v; }); +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + const Eigen::Hyperplane plane(normal, center); +#else const Eigen::Hyperplane plane(m_volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal, m_volume_matrix * center); +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES const Transform3d local_to_model_matrix = Geometry::translation_transform(center) * Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), normal); +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + const Vec3d local_proj = local_to_model_matrix.inverse() * plane.projection(world_pof); +#else const Vec3d local_proj = local_to_model_matrix.inverse() * m_volume_matrix.inverse() * plane.projection(world_pof); +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES double angle = std::atan2(local_proj.y(), local_proj.x()); if (angle < 0.0) angle += 2.0 * double(M_PI); @@ -767,8 +821,12 @@ void GLGizmoMeasure::on_render() default: { assert(false); break; } case Measure::SurfaceFeatureType::Point: { +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + const Transform3d feature_matrix = Geometry::translation_transform(feature.get_point()) * Geometry::scale_transform(inv_zoom); +#else const Vec3d position = TransformHelper::model_to_world(feature.get_point(), m_volume_matrix); const Transform3d feature_matrix = Geometry::translation_transform(position) * Geometry::scale_transform(inv_zoom); +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES set_matrix_uniforms(feature_matrix); set_emission_uniform(colors.front(), hover); m_sphere.model.set_color(colors.front()); @@ -785,8 +843,12 @@ void GLGizmoMeasure::on_render() const auto& [center, radius, normal] = feature.get_circle(); // render center if (update_raycasters_transform) { +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + const Transform3d center_matrix = Geometry::translation_transform(center) * Geometry::scale_transform(inv_zoom); +#else const Vec3d center_world = TransformHelper::model_to_world(center, m_volume_matrix); const Transform3d center_matrix = Geometry::translation_transform(center_world) * Geometry::scale_transform(inv_zoom); +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES set_matrix_uniforms(center_matrix); set_emission_uniform(colors.front(), hover); m_sphere.model.set_color(colors.front()); @@ -809,7 +871,11 @@ void GLGizmoMeasure::on_render() } else { GLModel circle; +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + GLModel::Geometry circle_geometry = init_torus_data(64, 16, center.cast(), float(radius), 5.0f * inv_zoom, normal.cast(), Transform3f::Identity()); +#else GLModel::Geometry circle_geometry = init_torus_data(64, 16, center.cast(), float(radius), 5.0f * inv_zoom, normal.cast(), m_volume_matrix.cast()); +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES circle.init_from(std::move(circle_geometry)); set_emission_uniform(colors.back(), hover); circle.set_color(colors.back()); @@ -825,8 +891,12 @@ void GLGizmoMeasure::on_render() if (update_raycasters_transform) { const std::optional extra = feature.get_extra_point(); if (extra.has_value()) { +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + const Transform3d point_matrix = Geometry::translation_transform(*extra) * Geometry::scale_transform(inv_zoom); +#else const Vec3d extra_world = TransformHelper::model_to_world(*extra, m_volume_matrix); const Transform3d point_matrix = Geometry::translation_transform(extra_world) * Geometry::scale_transform(inv_zoom); +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES set_matrix_uniforms(point_matrix); set_emission_uniform(colors.front(), hover); m_sphere.model.set_color(colors.front()); @@ -838,11 +908,17 @@ void GLGizmoMeasure::on_render() } // render edge if (m_mode != EMode::CenterSelection) { +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + const Transform3d edge_matrix = Geometry::translation_transform(from) * + Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), to - from) * + Geometry::scale_transform({ (double)inv_zoom, (double)inv_zoom, (to - from).norm() }); +#else const Vec3d from_world = TransformHelper::model_to_world(from, m_volume_matrix); const Vec3d to_world = TransformHelper::model_to_world(to, m_volume_matrix); const Transform3d edge_matrix = Geometry::translation_transform(from_world) * Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), to_world - from_world) * Geometry::scale_transform({ (double)inv_zoom, (double)inv_zoom, (to_world - from_world).norm() }); +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES set_matrix_uniforms(edge_matrix); set_emission_uniform(colors.back(), hover); m_cylinder.model.set_color(colors.back()); @@ -861,7 +937,11 @@ void GLGizmoMeasure::on_render() if (colors.front() != m_parent.get_selection().get_first_volume()->render_color) { const auto& [idx, normal, pt] = feature.get_plane(); assert(idx < m_plane_models_cache.size()); +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + set_matrix_uniforms(Transform3d::Identity()); +#else set_matrix_uniforms(m_volume_matrix); +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES set_emission_uniform(colors.front(), hover); m_plane_models_cache[idx].set_color(colors.front()); m_plane_models_cache[idx].render(); @@ -869,7 +949,11 @@ void GLGizmoMeasure::on_render() if (update_raycasters_transform) { auto it = m_raycasters.find(PLANE_ID); if (it != m_raycasters.end() && it->second != nullptr) +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + it->second->set_transform(Transform3d::Identity()); +#else it->second->set_transform(m_volume_matrix); +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES } break; } @@ -924,7 +1008,11 @@ void GLGizmoMeasure::on_render() auto it = std::find_if(m_selection_raycasters.begin(), m_selection_raycasters.end(), [](std::shared_ptr item) { return SceneRaycaster::decode_id(SceneRaycaster::EType::Gizmo, item->get_id()) == SELECTION_1_ID; }); if (it != m_selection_raycasters.end()) +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + (*it)->set_transform(Geometry::translation_transform(m_selected_features.first.feature->get_point()) * Geometry::scale_transform(inv_zoom)); +#else (*it)->set_transform(m_volume_matrix * Geometry::translation_transform(m_selected_features.first.feature->get_point()) * Geometry::scale_transform(inv_zoom)); +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES } } if (m_selected_features.second.feature.has_value() && (!m_curr_feature.has_value() || *m_curr_feature != *m_selected_features.second.feature)) { @@ -934,14 +1022,22 @@ void GLGizmoMeasure::on_render() auto it = std::find_if(m_selection_raycasters.begin(), m_selection_raycasters.end(), [](std::shared_ptr item) { return SceneRaycaster::decode_id(SceneRaycaster::EType::Gizmo, item->get_id()) == SELECTION_2_ID; }); if (it != m_selection_raycasters.end()) +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + (*it)->set_transform(Geometry::translation_transform(m_selected_features.second.feature->get_point()) * Geometry::scale_transform(inv_zoom)); +#else (*it)->set_transform(m_volume_matrix * Geometry::translation_transform(m_selected_features.second.feature->get_point()) * Geometry::scale_transform(inv_zoom)); +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES } } if (is_hovering_on_feature && m_curr_point_on_feature_position.has_value()) { if (m_hover_id != POINT_ID) { +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + const Transform3d matrix = Geometry::translation_transform(*m_curr_point_on_feature_position) * Geometry::scale_transform(inv_zoom); +#else const Vec3d position = TransformHelper::model_to_world(*m_curr_point_on_feature_position, m_volume_matrix); const Transform3d matrix = Geometry::translation_transform(position) * Geometry::scale_transform(inv_zoom); +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES set_matrix_uniforms(matrix); const ColorRGBA color = hover_selection_color(); set_emission_uniform(color, true); @@ -954,7 +1050,9 @@ void GLGizmoMeasure::on_render() if (old_cullface) glsafe(::glEnable(GL_CULL_FACE)); +#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES } +#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES render_dimensioning(); } @@ -971,6 +1069,24 @@ void GLGizmoMeasure::update_if_needed() } }; +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + auto do_update = [this, update_plane_models_cache](const std::vector& volumes_cache, const Selection& selection) { + TriangleMesh composite_mesh; + for (const auto& vol : volumes_cache) { +// if (selection.is_single_full_instance() && vol.volume->is_modifier()) +// continue; + + TriangleMesh volume_mesh = vol.volume->mesh(); + volume_mesh.transform(vol.instance->get_transformation().get_matrix() * vol.volume->get_transformation().get_matrix()); + composite_mesh.merge(volume_mesh); + } + + m_measuring.reset(new Measure::Measuring(composite_mesh.its)); + update_plane_models_cache(m_measuring->get_mesh().its); + m_raycaster.update_from(m_measuring->get_mesh()); + m_volumes_cache = volumes_cache; + }; +#else auto do_update = [this, update_plane_models_cache](const ModelObject* object, const ModelVolume* volume) { const indexed_triangle_set& its = (volume != nullptr) ? volume->mesh().its : object->volumes.front()->mesh().its; m_measuring.reset(new Measure::Measuring(its)); @@ -980,24 +1096,44 @@ void GLGizmoMeasure::update_if_needed() // Let's save what we calculated it from: m_volumes_matrices.clear(); m_volumes_types.clear(); - m_first_instance_scale = Vec3d::Ones(); + m_first_instance_scale = Vec3d::Ones(); m_first_instance_mirror = Vec3d::Ones(); if (object != nullptr) { for (const ModelVolume* vol : object->volumes) { m_volumes_matrices.push_back(vol->get_matrix()); m_volumes_types.push_back(vol->type()); } - m_first_instance_scale = object->instances.front()->get_scaling_factor(); + m_first_instance_scale = object->instances.front()->get_scaling_factor(); m_first_instance_mirror = object->instances.front()->get_mirror(); } m_old_model_object = object; m_old_model_volume = volume; }; +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES const Selection& selection = m_parent.get_selection(); if (selection.is_empty()) return; +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + const Selection::IndicesList& idxs = selection.get_volume_idxs(); + std::vector volumes_cache; + volumes_cache.reserve(idxs.size()); + for (unsigned int idx : idxs) { + const GLVolume* v = selection.get_volume(idx); + const ModelObject* obj = selection.get_model()->objects[v->object_idx()]; + const ModelInstance* inst = obj->instances[v->instance_idx()]; + const ModelVolume* vol = obj->volumes[v->volume_idx()]; + const VolumeCacheItem item = { obj, inst, vol, inst->get_matrix() * vol->get_matrix() }; + volumes_cache.emplace_back(item); + } + + if (m_state != On || volumes_cache.empty()) + return; + + if (m_measuring == nullptr || m_volumes_cache != volumes_cache) + do_update(volumes_cache, selection); +#else m_volume_matrix = selection.get_first_volume()->world_matrix(); const ModelObject* mo = m_c->selection_info()->model_object(); @@ -1026,6 +1162,7 @@ void GLGizmoMeasure::update_if_needed() break; } } +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES } void GLGizmoMeasure::disable_scene_raycasters() @@ -1145,6 +1282,62 @@ void GLGizmoMeasure::render_dimensioning() const double ratio = new_value / old_value; wxGetApp().plater()->take_snapshot(_L("Scale")); +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + struct TrafoData + { + double ratio; + Vec3d old_pivot; + Vec3d new_pivot; + Transform3d scale_matrix; + + TrafoData(double ratio, const Vec3d& pivot) { + this->ratio = ratio; + this->scale_matrix = Geometry::scale_transform(ratio); + this->old_pivot = pivot; + this->new_pivot = { pivot.x(), pivot.y(), (this->scale_matrix * pivot).z() }; + } + + Vec3d transform(const Vec3d& point) const { + return this->scale_matrix * (point - this->old_pivot) + this->new_pivot; + } + }; + + auto scale_feature = [this](Measure::SurfaceFeature& feature, const TrafoData& trafo_data) { + switch (feature.get_type()) + { + case Measure::SurfaceFeatureType::Point: + { + feature = Measure::SurfaceFeature(trafo_data.transform(feature.get_point())); + break; + } + case Measure::SurfaceFeatureType::Edge: + { + const auto [from, to] = feature.get_edge(); + const std::optional extra = feature.get_extra_point(); + const std::optional new_extra = extra.has_value() ? trafo_data.transform(*extra) : extra; + feature = Measure::SurfaceFeature(Measure::SurfaceFeatureType::Edge, trafo_data.transform(from), trafo_data.transform(to), new_extra); + break; + } + case Measure::SurfaceFeatureType::Circle: + { + const auto [center, radius, normal] = feature.get_circle(); + feature = Measure::SurfaceFeature(Measure::SurfaceFeatureType::Circle, trafo_data.transform(center), normal, std::nullopt, trafo_data.ratio * radius); + break; + } + case Measure::SurfaceFeatureType::Plane: + { + const auto [idx, normal, origin] = feature.get_plane(); + feature = Measure::SurfaceFeature(Measure::SurfaceFeatureType::Plane, normal, trafo_data.transform(origin), std::nullopt, idx); + break; + } + } + }; + + const TrafoData trafo_data(ratio, m_parent.get_selection().get_bounding_box().center()); + scale_feature(*m_selected_features.first.feature, trafo_data); + scale_feature(*m_selected_features.second.feature, trafo_data); +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + TransformationType type; type.set_world(); type.set_relative(); @@ -1203,8 +1396,10 @@ void GLGizmoMeasure::render_dimensioning() assert(f1.get_type() == Measure::SurfaceFeatureType::Point && f2.get_type() == Measure::SurfaceFeatureType::Edge); std::pair e = f2.get_edge(); // Transform to world coordinates +#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES e.first = TransformHelper::model_to_world(e.first, m_volume_matrix); e.second = TransformHelper::model_to_world(e.second, m_volume_matrix); +#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES const Vec3d v_proj = m_measurement_result.distance_infinite->to; @@ -1485,15 +1680,21 @@ void GLGizmoMeasure::render_debug_dialog() { case Measure::SurfaceFeatureType::Point: { +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + add_strings_row_to_table(*m_imgui, "m_pt1", ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(item.feature->get_point()), ImGui::GetStyleColorVec4(ImGuiCol_Text)); +#else const Vec3d position = m_volume_matrix * item.feature->get_point(); add_strings_row_to_table(*m_imgui, "m_pt1", ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(position), ImGui::GetStyleColorVec4(ImGuiCol_Text)); +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES break; } case Measure::SurfaceFeatureType::Edge: { auto [from, to] = item.feature->get_edge(); +#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES from = m_volume_matrix * from; to = m_volume_matrix * to; +#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES add_strings_row_to_table(*m_imgui, "m_pt1", ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(from), ImGui::GetStyleColorVec4(ImGuiCol_Text)); add_strings_row_to_table(*m_imgui, "m_pt2", ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(to), ImGui::GetStyleColorVec4(ImGuiCol_Text)); break; @@ -1501,8 +1702,10 @@ void GLGizmoMeasure::render_debug_dialog() case Measure::SurfaceFeatureType::Plane: { auto [idx, normal, origin] = item.feature->get_plane(); +#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES origin = m_volume_matrix * origin; normal = m_volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal; +#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES add_strings_row_to_table(*m_imgui, "m_pt1", ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(normal), ImGui::GetStyleColorVec4(ImGuiCol_Text)); add_strings_row_to_table(*m_imgui, "m_pt2", ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(origin), ImGui::GetStyleColorVec4(ImGuiCol_Text)); add_strings_row_to_table(*m_imgui, "m_value", ImGuiWrapper::COL_ORANGE_LIGHT, format_double(idx), ImGui::GetStyleColorVec4(ImGuiCol_Text)); @@ -1511,9 +1714,13 @@ void GLGizmoMeasure::render_debug_dialog() case Measure::SurfaceFeatureType::Circle: { auto [center, radius, normal] = item.feature->get_circle(); +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + const Vec3d on_circle = center + radius * Measure::get_orthogonal(normal, true); +#else const Vec3d on_circle = m_volume_matrix * (center + radius * Measure::get_orthogonal(normal, true)); center = m_volume_matrix * center; normal = (m_volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal).normalized(); +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES radius = (on_circle - center).norm(); add_strings_row_to_table(*m_imgui, "m_pt1", ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(center), ImGui::GetStyleColorVec4(ImGuiCol_Text)); add_strings_row_to_table(*m_imgui, "m_pt2", ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(normal), ImGui::GetStyleColorVec4(ImGuiCol_Text)); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 7bfc2e8c93..606012f7c4 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -5,10 +5,16 @@ #include "slic3r/GUI/GLModel.hpp" #include "slic3r/GUI/GUI_Utils.hpp" #include "libslic3r/Measure.hpp" +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES +#include "slic3r/GUI/Gizmos/GLGizmosCommon.hpp" +#include "libslic3r/Model.hpp" +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES namespace Slic3r { +#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES class ModelVolume; +#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES enum class ModelVolumeType : int; @@ -68,6 +74,23 @@ class GLGizmoMeasure : public GLGizmoBase } }; +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + 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; +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + EMode m_mode{ EMode::FeatureSelection }; Measure::MeasurementResult m_measurement_result; @@ -85,7 +108,13 @@ class GLGizmoMeasure : public GLGizmoBase }; Dimensioning m_dimensioning; +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + // Uses a standalone raycaster and not the shared one because of the + // difference in how the mesh is updated + CommonGizmosDataObjects::Raycaster m_raycaster; +#else Transform3d m_volume_matrix{ Transform3d::Identity() }; +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES std::vector m_plane_models_cache; std::map> m_raycasters; std::vector> m_selection_raycasters; @@ -100,17 +129,21 @@ class GLGizmoMeasure : public GLGizmoBase std::vector m_scene_raycasters; // These hold information to decide whether recalculation is necessary: +#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES std::vector m_volumes_matrices; std::vector m_volumes_types; Vec3d m_first_instance_scale{ Vec3d::Ones() }; Vec3d m_first_instance_mirror{ Vec3d::Ones() }; +#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES float m_last_inv_zoom{ 0.0f }; std::optional m_last_circle; int m_last_plane_idx{ -1 }; bool m_mouse_left_down{ false }; // for detection left_up of this gizmo +#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES const ModelObject* m_old_model_object{ nullptr }; const ModelVolume* m_old_model_volume{ nullptr }; +#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES Vec2d m_mouse_pos{ Vec2d::Zero() }; @@ -153,7 +186,9 @@ protected: bool on_is_activable() const override; void on_render() override; void on_set_state() override; +#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES CommonGizmosDataID on_get_requirements() const override; +#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES virtual void on_render_input_window(float x, float y, float bottom_limit) override; virtual void on_register_raycasters_for_picking() override; diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp index 394e879b7c..dca64a5266 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp @@ -327,6 +327,19 @@ const TriangleMesh* HollowedMesh::get_hollowed_interior() const } +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES +void Raycaster::update_from(const TriangleMesh& mesh) +{ + std::vector meshes = { &mesh }; + if (meshes != m_old_meshes) { + wxBusyCursor wait; + m_raycasters.clear(); + m_raycasters.emplace_back(new MeshRaycaster(std::make_shared(mesh))); + m_old_meshes = meshes; + } + validate(); +} +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES void Raycaster::on_update() diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp index 42faa25f84..b02e3a920c 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp @@ -137,6 +137,9 @@ protected: virtual void on_update() = 0; CommonGizmosDataPool* get_pool() const { return m_common; } +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + void validate() { m_is_valid = true; } +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES private: bool m_is_valid = false; @@ -242,6 +245,10 @@ public: const MeshRaycaster* raycaster() const { assert(m_raycasters.size() == 1); return m_raycasters.front().get(); } std::vector raycasters() const; +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + void update_from(const TriangleMesh& mesh); +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + protected: void on_update() override; void on_release() override; diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index 9a4169b318..2e50fc37c9 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -602,6 +602,19 @@ bool Selection::contains_any_volume(const std::vector& volume_idxs return false; } +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES +bool Selection::contains_sinking_volumes(bool ignore_modifiers) const +{ + for (const GLVolume* v : *m_volumes) { + if (!ignore_modifiers || !v->is_modifier) { + if (v->is_sinking()) + return true; + } + } + return false; +} +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + bool Selection::matches(const std::vector& volume_idxs) const { unsigned int count = 0; diff --git a/src/slic3r/GUI/Selection.hpp b/src/slic3r/GUI/Selection.hpp index c4720a3081..0064f27999 100644 --- a/src/slic3r/GUI/Selection.hpp +++ b/src/slic3r/GUI/Selection.hpp @@ -337,6 +337,10 @@ public: bool contains_all_volumes(const std::vector& volume_idxs) const; // returns true if the selection contains at least one of the given indices bool contains_any_volume(const std::vector& volume_idxs) const; +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + // returns true if the selection contains any sinking volume + bool contains_sinking_volumes(bool ignore_modifiers = true) const; +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES // returns true if the selection contains all and only the given indices bool matches(const std::vector& volume_idxs) const; From 182e5ece2e47547a243962d518a667b40b3556d8 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 15 Nov 2022 12:42:22 +0100 Subject: [PATCH 02/89] Added missing declaration --- src/libslic3r/Measure.hpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/libslic3r/Measure.hpp b/src/libslic3r/Measure.hpp index b2e2008d15..9cc380dd2b 100644 --- a/src/libslic3r/Measure.hpp +++ b/src/libslic3r/Measure.hpp @@ -12,6 +12,11 @@ struct indexed_triangle_set; namespace Slic3r { + +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES +class TriangleMesh; +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + namespace Measure { From c98ba0e651d63fc277e879232276adce0bdd49c9 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Tue, 15 Nov 2022 16:07:38 +0100 Subject: [PATCH 03/89] Measurement: refactoring - do not touch common raycaster interface when there is no need --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 9 +++------ src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 4 ++-- src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp | 15 --------------- src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp | 8 -------- 4 files changed, 5 insertions(+), 31 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 5ae906eac9..8cfbf634eb 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -245,9 +245,6 @@ TransformHelper::Cache TransformHelper::s_cache = { { 0, 0, 0, 0 }, Matrix4d::Id GLGizmoMeasure::GLGizmoMeasure(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) : GLGizmoBase(parent, icon_filename, sprite_id) -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES -, m_raycaster(nullptr) -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES { GLModel::Geometry sphere_geometry = smooth_sphere(16, 7.5f); m_sphere.mesh_raycaster = std::make_unique(std::make_shared(sphere_geometry.get_as_indexed_triangle_set())); @@ -526,7 +523,7 @@ void GLGizmoMeasure::on_set_state() m_is_editing_distance_first_frame = true; m_measuring.reset(); #if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - m_raycaster.release(); + m_raycaster.reset(); #endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES } else { @@ -599,7 +596,7 @@ void GLGizmoMeasure::on_render() Vec3f normal_on_model; size_t model_facet_idx; #if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - const bool mouse_on_object = m_raycaster.raycaster()->unproject_on_mesh(m_mouse_pos, Transform3d::Identity(), camera, position_on_model, normal_on_model, nullptr, &model_facet_idx); + const bool mouse_on_object = m_raycaster->unproject_on_mesh(m_mouse_pos, Transform3d::Identity(), camera, position_on_model, normal_on_model, nullptr, &model_facet_idx); #else const bool mouse_on_object = m_c->raycaster()->raycasters().front()->unproject_on_mesh(m_mouse_pos, m_volume_matrix, camera, position_on_model, normal_on_model, nullptr, &model_facet_idx); #endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES @@ -1083,7 +1080,7 @@ void GLGizmoMeasure::update_if_needed() m_measuring.reset(new Measure::Measuring(composite_mesh.its)); update_plane_models_cache(m_measuring->get_mesh().its); - m_raycaster.update_from(m_measuring->get_mesh()); + m_raycaster.reset(new MeshRaycaster(std::make_shared(m_measuring->get_mesh()))); m_volumes_cache = volumes_cache; }; #else diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 606012f7c4..fbbf30da78 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -4,9 +4,9 @@ #include "GLGizmoBase.hpp" #include "slic3r/GUI/GLModel.hpp" #include "slic3r/GUI/GUI_Utils.hpp" +#include "slic3r/GUI/MeshUtils.hpp" #include "libslic3r/Measure.hpp" #if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES -#include "slic3r/GUI/Gizmos/GLGizmosCommon.hpp" #include "libslic3r/Model.hpp" #endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES @@ -111,7 +111,7 @@ class GLGizmoMeasure : public GLGizmoBase #if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES // Uses a standalone raycaster and not the shared one because of the // difference in how the mesh is updated - CommonGizmosDataObjects::Raycaster m_raycaster; + std::unique_ptr m_raycaster; #else Transform3d m_volume_matrix{ Transform3d::Identity() }; #endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp index dca64a5266..11c44113bc 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp @@ -327,21 +327,6 @@ const TriangleMesh* HollowedMesh::get_hollowed_interior() const } -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES -void Raycaster::update_from(const TriangleMesh& mesh) -{ - std::vector meshes = { &mesh }; - if (meshes != m_old_meshes) { - wxBusyCursor wait; - m_raycasters.clear(); - m_raycasters.emplace_back(new MeshRaycaster(std::make_shared(mesh))); - m_old_meshes = meshes; - } - validate(); -} -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - - void Raycaster::on_update() { wxBusyCursor wait; diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp index b02e3a920c..3878c6b25a 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp @@ -137,10 +137,6 @@ protected: virtual void on_update() = 0; CommonGizmosDataPool* get_pool() const { return m_common; } -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - void validate() { m_is_valid = true; } -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - private: bool m_is_valid = false; CommonGizmosDataPool* m_common = nullptr; @@ -245,10 +241,6 @@ public: const MeshRaycaster* raycaster() const { assert(m_raycasters.size() == 1); return m_raycasters.front().get(); } std::vector raycasters() const; -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - void update_from(const TriangleMesh& mesh); -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - protected: void on_update() override; void on_release() override; From 6dac9f2aca0439fef6af8e6c0f6b0d6a77788b03 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Tue, 15 Nov 2022 16:08:27 +0100 Subject: [PATCH 04/89] Measurement: Partially fixed the common gizmo raycaster for self-intersecting meshes --- src/slic3r/GUI/MeshUtils.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/MeshUtils.cpp b/src/slic3r/GUI/MeshUtils.cpp index e33d29ba16..3805151af1 100644 --- a/src/slic3r/GUI/MeshUtils.cpp +++ b/src/slic3r/GUI/MeshUtils.cpp @@ -409,6 +409,12 @@ bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& Vec3d direction; line_from_mouse_pos(mouse_pos, trafo, camera, point, direction); + if (rand()%100 == 0) { + int a=5; + int b=6; + int c=7; + } + std::vector hits = m_emesh.query_ray_hits(point, direction); if (hits.empty()) @@ -429,10 +435,10 @@ bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& // All hits are clipped. return false; } - if ((hits.size()-i) % 2 != 0) { + if (clipping_plane && (hits.size()-i) % 2 != 0) { // There is an odd number of unclipped hits - meaning the nearest must be from inside the mesh. // In that case, calculate intersection with the clipping place. - if (clipping_plane && was_clipping_plane_hit) { + if (was_clipping_plane_hit) { direction = direction + point; point = trafo * point; // transform to world coords direction = trafo * direction - point; From c24ce158054bf23daaca10499799cbd946dca15b Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 16 Nov 2022 08:53:02 +0100 Subject: [PATCH 05/89] Tech ENABLE_GIZMO_MEASURE_WORLD_COORDINATES set as default --- src/libslic3r/Measure.cpp | 48 -- src/libslic3r/Measure.hpp | 30 +- src/libslic3r/Technologies.hpp | 2 - src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 850 +++++++++-------------- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 26 +- src/slic3r/GUI/Selection.cpp | 2 - src/slic3r/GUI/Selection.hpp | 2 - 7 files changed, 323 insertions(+), 637 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index 1ffd72c14d..cea9f0b77e 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -45,9 +45,7 @@ public: std::optional get_feature(size_t face_idx, const Vec3d& point) const; std::vector> get_planes_triangle_indices() const; const std::vector& get_plane_features(unsigned int plane_id) const; -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES const TriangleMesh& get_mesh() const; -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES private: void update_planes(); @@ -55,11 +53,7 @@ private: std::vector m_planes; std::vector m_face_to_plane; -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES TriangleMesh m_mesh; -#else - const indexed_triangle_set& m_its; -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES }; @@ -68,11 +62,7 @@ private: MeasuringImpl::MeasuringImpl(const indexed_triangle_set& its) -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES : m_mesh(its) -#else -: m_its{its} -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES { update_planes(); extract_features(); @@ -85,17 +75,10 @@ void MeasuringImpl::update_planes() // Now we'll go through all the facets and append Points of facets sharing the same normal. // This part is still performed in mesh coordinate system. -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES const size_t num_of_facets = m_mesh.its.indices.size(); m_face_to_plane.resize(num_of_facets, size_t(-1)); const std::vector face_normals = its_face_normals(m_mesh.its); const std::vector face_neighbors = its_face_neighbors(m_mesh.its); -#else - const size_t num_of_facets = m_its.indices.size(); - m_face_to_plane.resize(num_of_facets, size_t(-1)); - const std::vector face_normals = its_face_normals(m_its); - const std::vector face_neighbors = its_face_neighbors(m_its); -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES std::vector facet_queue(num_of_facets, 0); int facet_queue_cnt = 0; const stl_normal* normal_ptr = nullptr; @@ -144,11 +127,7 @@ void MeasuringImpl::update_planes() assert(std::none_of(m_face_to_plane.begin(), m_face_to_plane.end(), [](size_t val) { return val == size_t(-1); })); // Now we will walk around each of the planes and save vertices which form the border. -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES SurfaceMesh sm(m_mesh.its); -#else - SurfaceMesh sm(m_its); -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES for (int plane_id=0; plane_id < int(m_planes.size()); ++plane_id) { const auto& facets = m_planes[plane_id].facets; m_planes[plane_id].borders.clear(); @@ -530,12 +509,10 @@ const std::vector& MeasuringImpl::get_plane_features(unsigned in return m_planes[plane_id].surface_features; } -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES const TriangleMesh& MeasuringImpl::get_mesh() const { return this->m_mesh; } -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES @@ -577,12 +554,10 @@ const std::vector& Measuring::get_plane_features(unsigned int pl return priv->get_plane_features(plane_id); } -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES const TriangleMesh& Measuring::get_mesh() const { return priv->get_mesh(); } -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES const AngleAndEdges AngleAndEdges::Dummy = { 0.0, Vec3d::Zero(), { Vec3d::Zero(), Vec3d::Zero() }, { Vec3d::Zero(), Vec3d::Zero() }, 0.0, true }; @@ -1182,29 +1157,6 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& return result; } -#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES -void DistAndPoints::transform(const Transform3d& trafo) { - from = trafo * from; - to = trafo * to; - dist = (to - from).norm(); -} - -void AngleAndEdges::transform(const Transform3d& trafo) { - const Vec3d old_e1 = e1.second - e1.first; - const Vec3d old_e2 = e2.second - e2.first; - center = trafo * center; - e1.first = trafo * e1.first; - e1.second = trafo * e1.second; - e2.first = trafo * e2.first; - e2.second = trafo * e2.second; - angle = std::acos(std::clamp(Measure::edge_direction(e1).dot(Measure::edge_direction(e2)), -1.0, 1.0)); - const Vec3d new_e1 = e1.second - e1.first; - const Vec3d new_e2 = e2.second - e2.first; - const double average_scale = 0.5 * (new_e1.norm() / old_e1.norm() + new_e2.norm() / old_e2.norm()); - radius = average_scale * radius; -} -#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - diff --git a/src/libslic3r/Measure.hpp b/src/libslic3r/Measure.hpp index 9cc380dd2b..3a1a4b89d9 100644 --- a/src/libslic3r/Measure.hpp +++ b/src/libslic3r/Measure.hpp @@ -13,9 +13,7 @@ struct indexed_triangle_set; namespace Slic3r { -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES class TriangleMesh; -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES namespace Measure { @@ -93,10 +91,7 @@ class MeasuringImpl; class Measuring { public: // Construct the measurement object on a given its. -#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - // The its must remain valid and unchanged during the whole lifetime of the object. -#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - explicit Measuring(const indexed_triangle_set& its); + explicit Measuring(const indexed_triangle_set& its); ~Measuring(); // Return a reference to a list of all features identified on the its. @@ -115,10 +110,8 @@ public: // Returns the surface features of the plane with the given index const std::vector& get_plane_features(unsigned int plane_id) const; -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES // Returns the mesh used for measuring const TriangleMesh& get_mesh() const; -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES private: std::unique_ptr priv; @@ -130,10 +123,6 @@ struct DistAndPoints { double dist; Vec3d from; Vec3d to; - -#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - void transform(const Transform3d& trafo); -#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES }; struct AngleAndEdges { @@ -146,10 +135,6 @@ struct AngleAndEdges { double radius; bool coplanar; -#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - void transform(const Transform3d& trafo); -#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - static const AngleAndEdges Dummy; }; @@ -166,19 +151,6 @@ struct MeasurementResult { bool has_any_data() const { return angle.has_value() || distance_infinite.has_value() || distance_strict.has_value() || distance_xyz.has_value(); } - -#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - void transform(const Transform3d& trafo) { - if (angle.has_value()) - angle->transform(trafo); - if (distance_infinite.has_value()) - distance_infinite->transform(trafo); - if (distance_strict.has_value()) { - distance_strict->transform(trafo); - distance_xyz = (distance_strict->to - distance_strict->from).cwiseAbs(); - } - } -#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES }; // Returns distance/angle between two SurfaceFeatures. diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index 9e7c660ae0..a3e72cf0c5 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -64,8 +64,6 @@ // Enable picking using raytracing #define ENABLE_RAYCAST_PICKING (1 && ENABLE_LEGACY_OPENGL_REMOVAL) #define ENABLE_RAYCAST_PICKING_DEBUG (0 && ENABLE_RAYCAST_PICKING) -// Enable gizmo measure combining volumes meshes and passing them to the backend in world coordinates -#define ENABLE_GIZMO_MEASURE_WORLD_COORDINATES (1 && ENABLE_2_5_0_ALPHA1) #endif // _prusaslicer_technologies_h_ diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 8cfbf634eb..35767121d7 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -6,10 +6,6 @@ #include "slic3r/GUI/GUI_ObjectManipulation.hpp" -#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES -#include "slic3r/GUI/Gizmos/GLGizmosCommon.hpp" -#include "libslic3r/Model.hpp" -#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES #include "libslic3r/PresetBundle.hpp" #include "libslic3r/MeasureUtils.hpp" @@ -370,13 +366,8 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) } } - if (m_selected_features != selected_features_old && m_selected_features.second.feature.has_value()) { + if (m_selected_features != selected_features_old && m_selected_features.second.feature.has_value()) m_measurement_result = Measure::get_measurement(*m_selected_features.first.feature, *m_selected_features.second.feature, m_measuring.get()); -#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - // transform to world coordinates - m_measurement_result.transform(m_volume_matrix); -#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - } m_imgui->set_requires_extra_frame(); @@ -423,29 +414,12 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) void GLGizmoMeasure::data_changed() { -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES update_if_needed(); -#else - const Selection& selection = m_parent.get_selection(); - const ModelObject* model_object = nullptr; - const ModelVolume* model_volume = nullptr; - if (selection.is_single_full_instance() || - selection.is_from_single_object() ) { - model_object = selection.get_model()->objects[selection.get_object_idx()]; - model_volume = model_object->volumes[selection.get_first_volume()->volume_idx()]; - } - if (model_object != m_old_model_object || model_volume != m_old_model_volume) - update_if_needed(); -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES m_last_inv_zoom = 0.0f; m_last_plane_idx = -1; if (m_pending_scale) { m_measurement_result = Measure::get_measurement(*m_selected_features.first.feature, *m_selected_features.second.feature, m_measuring.get()); -#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - // transform to world coordinates - m_measurement_result.transform(m_volume_matrix); -#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES m_pending_scale = false; } else @@ -522,9 +496,7 @@ void GLGizmoMeasure::on_set_state() m_editing_distance = false; m_is_editing_distance_first_frame = true; m_measuring.reset(); -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES m_raycaster.reset(); -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES } else { m_mode = EMode::FeatureSelection; @@ -541,13 +513,6 @@ void GLGizmoMeasure::on_set_state() } } -#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES -CommonGizmosDataID GLGizmoMeasure::on_get_requirements() const -{ - return CommonGizmosDataID(int(CommonGizmosDataID::SelectionInfo) | int(CommonGizmosDataID::Raycaster)); -} -#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - std::string GLGizmoMeasure::on_get_name() const { return _u8L("Measure"); @@ -558,15 +523,9 @@ bool GLGizmoMeasure::on_is_activable() const const Selection& selection = m_parent.get_selection(); bool res = (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA) ? selection.is_single_full_instance() : -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES selection.is_single_full_instance() || selection.is_single_volume() || selection.is_single_modifier(); if (res) res &= !selection.contains_sinking_volumes(); -#else - selection.is_single_volume() || selection.is_single_volume_instance(); - if (res) - res &= !selection.get_first_volume()->is_sinking(); -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES return res; } @@ -583,473 +542,390 @@ void GLGizmoMeasure::on_render() const Selection& selection = m_parent.get_selection(); -#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - if ((wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA && selection.is_single_full_instance()) || - (selection.is_single_volume() || selection.is_single_volume_instance())) { -#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - update_if_needed(); + update_if_needed(); - const Camera& camera = wxGetApp().plater()->get_camera(); - const float inv_zoom = (float)camera.get_inv_zoom(); + const Camera& camera = wxGetApp().plater()->get_camera(); + const float inv_zoom = (float)camera.get_inv_zoom(); - Vec3f position_on_model; - Vec3f normal_on_model; - size_t model_facet_idx; -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - const bool mouse_on_object = m_raycaster->unproject_on_mesh(m_mouse_pos, Transform3d::Identity(), camera, position_on_model, normal_on_model, nullptr, &model_facet_idx); -#else - const bool mouse_on_object = m_c->raycaster()->raycasters().front()->unproject_on_mesh(m_mouse_pos, m_volume_matrix, camera, position_on_model, normal_on_model, nullptr, &model_facet_idx); -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - const bool is_hovering_on_feature = (m_mode == EMode::PointSelection || m_mode == EMode::CenterSelection) && m_hover_id != -1; + Vec3f position_on_model; + Vec3f normal_on_model; + size_t model_facet_idx; + const bool mouse_on_object = m_raycaster->unproject_on_mesh(m_mouse_pos, Transform3d::Identity(), camera, position_on_model, normal_on_model, nullptr, &model_facet_idx); + const bool is_hovering_on_feature = (m_mode == EMode::PointSelection || m_mode == EMode::CenterSelection) && m_hover_id != -1; - auto update_circle = [this, inv_zoom]() { - if (m_last_inv_zoom != inv_zoom || m_last_circle != m_curr_feature) { - m_last_inv_zoom = inv_zoom; - m_last_circle = m_curr_feature; - m_circle.reset(); - const auto [center, radius, normal] = m_curr_feature->get_circle(); -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - GLModel::Geometry circle_geometry = init_torus_data(64, 16, center.cast(), float(radius), 5.0f * inv_zoom, normal.cast(), Transform3f::Identity()); -#else - GLModel::Geometry circle_geometry = init_torus_data(64, 16, center.cast(), float(radius), 5.0f * inv_zoom, normal.cast(), m_volume_matrix.cast()); -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - m_circle.mesh_raycaster = std::make_unique(std::make_shared(circle_geometry.get_as_indexed_triangle_set())); - m_circle.model.init_from(std::move(circle_geometry)); - return true; - } - return false; - }; + auto update_circle = [this, inv_zoom]() { + if (m_last_inv_zoom != inv_zoom || m_last_circle != m_curr_feature) { + m_last_inv_zoom = inv_zoom; + m_last_circle = m_curr_feature; + m_circle.reset(); + const auto [center, radius, normal] = m_curr_feature->get_circle(); + GLModel::Geometry circle_geometry = init_torus_data(64, 16, center.cast(), float(radius), 5.0f * inv_zoom, normal.cast(), Transform3f::Identity()); + m_circle.mesh_raycaster = std::make_unique(std::make_shared(circle_geometry.get_as_indexed_triangle_set())); + m_circle.model.init_from(std::move(circle_geometry)); + return true; + } + return false; + }; - if (m_mode == EMode::FeatureSelection || m_mode == EMode::PointSelection) { - if ((m_hover_id == SELECTION_1_ID && boost::algorithm::istarts_with(m_selected_features.first.source, _u8L("Center"))) || - (m_hover_id == SELECTION_2_ID && boost::algorithm::istarts_with(m_selected_features.second.source, _u8L("Center")))) { - // Skip feature detection if hovering on a selected center - m_curr_feature.reset(); + if (m_mode == EMode::FeatureSelection || m_mode == EMode::PointSelection) { + if ((m_hover_id == SELECTION_1_ID && boost::algorithm::istarts_with(m_selected_features.first.source, _u8L("Center"))) || + (m_hover_id == SELECTION_2_ID && boost::algorithm::istarts_with(m_selected_features.second.source, _u8L("Center")))) { + // Skip feature detection if hovering on a selected center + m_curr_feature.reset(); + m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, POINT_ID); + m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, EDGE_ID); + m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, PLANE_ID); + m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_ID); + m_curr_point_on_feature_position.reset(); + } + else { + std::optional curr_feature = mouse_on_object ? m_measuring->get_feature(model_facet_idx, position_on_model.cast()) : std::nullopt; + if (m_curr_feature != curr_feature || + (curr_feature.has_value() && curr_feature->get_type() == Measure::SurfaceFeatureType::Circle && (m_curr_feature != curr_feature || m_last_inv_zoom != inv_zoom))) { m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, POINT_ID); m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, EDGE_ID); m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, PLANE_ID); m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_ID); - m_curr_point_on_feature_position.reset(); - } - else { - std::optional curr_feature = mouse_on_object ? m_measuring->get_feature(model_facet_idx, position_on_model.cast()) : std::nullopt; - if (m_curr_feature != curr_feature || - (curr_feature.has_value() && curr_feature->get_type() == Measure::SurfaceFeatureType::Circle && (m_curr_feature != curr_feature || m_last_inv_zoom != inv_zoom))) { - m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, POINT_ID); - m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, EDGE_ID); - m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, PLANE_ID); - m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_ID); - m_raycasters.clear(); - m_curr_feature = curr_feature; - if (!m_curr_feature.has_value()) - return; + m_raycasters.clear(); + m_curr_feature = curr_feature; + if (!m_curr_feature.has_value()) + return; - switch (m_curr_feature->get_type()) { - default: { assert(false); break; } - case Measure::SurfaceFeatureType::Point: - { - m_raycasters.insert({ POINT_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, POINT_ID, *m_sphere.mesh_raycaster) }); - break; - } - case Measure::SurfaceFeatureType::Edge: - { - m_raycasters.insert({ EDGE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, EDGE_ID, *m_cylinder.mesh_raycaster) }); - if (m_curr_feature->get_extra_point().has_value()) - m_raycasters.insert({ POINT_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, POINT_ID, *m_sphere.mesh_raycaster) }); - break; - } - case Measure::SurfaceFeatureType::Circle: - { - update_circle(); - m_raycasters.insert({ CIRCLE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_ID, *m_circle.mesh_raycaster) }); - m_raycasters.insert({ POINT_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, POINT_ID, *m_sphere.mesh_raycaster) }); - break; - } - case Measure::SurfaceFeatureType::Plane: - { - const auto [idx, normal, point] = m_curr_feature->get_plane(); - if (m_last_plane_idx != idx) { - m_last_plane_idx = idx; -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - const indexed_triangle_set& its = m_measuring->get_mesh().its; -#else - const indexed_triangle_set its = (m_old_model_volume != nullptr) ? m_old_model_volume->mesh().its : m_old_model_object->volumes.front()->mesh().its; -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - const std::vector> planes_triangles = m_measuring->get_planes_triangle_indices(); - GLModel::Geometry init_data = init_plane_data(its, planes_triangles, idx); - m_plane.reset(); - m_plane.mesh_raycaster = std::make_unique(std::make_shared(init_data.get_as_indexed_triangle_set())); - m_plane.model.init_from(std::move(init_data)); - } - - m_raycasters.insert({ PLANE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, PLANE_ID, *m_plane.mesh_raycaster) }); - break; - } - } - } - } - } - - if (m_mode != EMode::PointSelection) - m_curr_point_on_feature_position.reset(); - else if (is_hovering_on_feature) { - auto position_on_feature = [this](int feature_type_id, const Camera& camera, std::function callback = nullptr) -> Vec3d { - auto it = m_raycasters.find(feature_type_id); - if (it != m_raycasters.end() && it->second != nullptr) { - Vec3f p; - Vec3f n; - const Transform3d& trafo = it->second->get_transform(); - bool res = it->second->get_raycaster()->closest_hit(m_mouse_pos, trafo, camera, p, n); - if (res) { - if (callback) - p = callback(p); - return trafo * p.cast(); - } - } - return Vec3d::Zero(); - }; - - if (m_curr_feature.has_value()) { - switch (m_curr_feature->get_type()) - { + switch (m_curr_feature->get_type()) { default: { assert(false); break; } case Measure::SurfaceFeatureType::Point: { - m_curr_point_on_feature_position = m_curr_feature->get_point(); + m_raycasters.insert({ POINT_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, POINT_ID, *m_sphere.mesh_raycaster) }); break; } case Measure::SurfaceFeatureType::Edge: { - const std::optional extra = m_curr_feature->get_extra_point(); - if (extra.has_value() && m_hover_id == POINT_ID) - m_curr_point_on_feature_position = *extra; - else -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - m_curr_point_on_feature_position = position_on_feature(EDGE_ID, camera, [](const Vec3f& v) { return Vec3f(0.0f, 0.0f, v.z()); }); -#else - m_curr_point_on_feature_position = m_volume_matrix.inverse() * position_on_feature(EDGE_ID, camera, [](const Vec3f& v) { return Vec3f(0.0f, 0.0f, v.z()); }); -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + m_raycasters.insert({ EDGE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, EDGE_ID, *m_cylinder.mesh_raycaster) }); + if (m_curr_feature->get_extra_point().has_value()) + m_raycasters.insert({ POINT_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, POINT_ID, *m_sphere.mesh_raycaster) }); + break; + } + case Measure::SurfaceFeatureType::Circle: + { + update_circle(); + m_raycasters.insert({ CIRCLE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_ID, *m_circle.mesh_raycaster) }); + m_raycasters.insert({ POINT_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, POINT_ID, *m_sphere.mesh_raycaster) }); break; } case Measure::SurfaceFeatureType::Plane: { -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - m_curr_point_on_feature_position = position_on_feature(PLANE_ID, camera); -#else - m_curr_point_on_feature_position = m_volume_matrix.inverse() * position_on_feature(PLANE_ID, camera); -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - break; - } - case Measure::SurfaceFeatureType::Circle: - { - const auto [center, radius, normal] = m_curr_feature->get_circle(); - if (m_hover_id == POINT_ID) - m_curr_point_on_feature_position = center; - else { - const Vec3d world_pof = position_on_feature(CIRCLE_ID, camera, [](const Vec3f& v) { return v; }); -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - const Eigen::Hyperplane plane(normal, center); -#else - const Eigen::Hyperplane plane(m_volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal, m_volume_matrix * center); -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - const Transform3d local_to_model_matrix = Geometry::translation_transform(center) * Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), normal); -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - const Vec3d local_proj = local_to_model_matrix.inverse() * plane.projection(world_pof); -#else - const Vec3d local_proj = local_to_model_matrix.inverse() * m_volume_matrix.inverse() * plane.projection(world_pof); -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - double angle = std::atan2(local_proj.y(), local_proj.x()); - if (angle < 0.0) - angle += 2.0 * double(M_PI); - - const Vec3d local_pos = radius * Vec3d(std::cos(angle), std::sin(angle), 0.0); - m_curr_point_on_feature_position = local_to_model_matrix * local_pos; + const auto [idx, normal, point] = m_curr_feature->get_plane(); + if (m_last_plane_idx != idx) { + m_last_plane_idx = idx; + const indexed_triangle_set& its = m_measuring->get_mesh().its; + const std::vector> planes_triangles = m_measuring->get_planes_triangle_indices(); + GLModel::Geometry init_data = init_plane_data(its, planes_triangles, idx); + m_plane.reset(); + m_plane.mesh_raycaster = std::make_unique(std::make_shared(init_data.get_as_indexed_triangle_set())); + m_plane.model.init_from(std::move(init_data)); } + + m_raycasters.insert({ PLANE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, PLANE_ID, *m_plane.mesh_raycaster) }); break; } } } } - else { - if (m_curr_feature.has_value() && m_curr_feature->get_type() == Measure::SurfaceFeatureType::Circle) { - if (update_circle()) { - m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_ID); - auto it = m_raycasters.find(CIRCLE_ID); - if (it != m_raycasters.end()) - m_raycasters.erase(it); - m_raycasters.insert({ CIRCLE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_ID, *m_circle.mesh_raycaster) }); + } + + if (m_mode != EMode::PointSelection) + m_curr_point_on_feature_position.reset(); + else if (is_hovering_on_feature) { + auto position_on_feature = [this](int feature_type_id, const Camera& camera, std::function callback = nullptr) -> Vec3d { + auto it = m_raycasters.find(feature_type_id); + if (it != m_raycasters.end() && it->second != nullptr) { + Vec3f p; + Vec3f n; + const Transform3d& trafo = it->second->get_transform(); + bool res = it->second->get_raycaster()->closest_hit(m_mouse_pos, trafo, camera, p, n); + if (res) { + if (callback) + p = callback(p); + return trafo * p.cast(); } } + return Vec3d::Zero(); + }; + + if (m_curr_feature.has_value()) { + switch (m_curr_feature->get_type()) + { + default: { assert(false); break; } + case Measure::SurfaceFeatureType::Point: + { + m_curr_point_on_feature_position = m_curr_feature->get_point(); + break; + } + case Measure::SurfaceFeatureType::Edge: + { + const std::optional extra = m_curr_feature->get_extra_point(); + if (extra.has_value() && m_hover_id == POINT_ID) + m_curr_point_on_feature_position = *extra; + else + m_curr_point_on_feature_position = position_on_feature(EDGE_ID, camera, [](const Vec3f& v) { return Vec3f(0.0f, 0.0f, v.z()); }); + break; + } + case Measure::SurfaceFeatureType::Plane: + { + m_curr_point_on_feature_position = position_on_feature(PLANE_ID, camera); + break; + } + case Measure::SurfaceFeatureType::Circle: + { + const auto [center, radius, normal] = m_curr_feature->get_circle(); + if (m_hover_id == POINT_ID) + m_curr_point_on_feature_position = center; + else { + const Vec3d world_pof = position_on_feature(CIRCLE_ID, camera, [](const Vec3f& v) { return v; }); + const Eigen::Hyperplane plane(normal, center); + const Transform3d local_to_model_matrix = Geometry::translation_transform(center) * Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), normal); + const Vec3d local_proj = local_to_model_matrix.inverse() * plane.projection(world_pof); + double angle = std::atan2(local_proj.y(), local_proj.x()); + if (angle < 0.0) + angle += 2.0 * double(M_PI); + + const Vec3d local_pos = radius * Vec3d(std::cos(angle), std::sin(angle), 0.0); + m_curr_point_on_feature_position = local_to_model_matrix * local_pos; + } + break; + } + } } + } + else { + if (m_curr_feature.has_value() && m_curr_feature->get_type() == Measure::SurfaceFeatureType::Circle) { + if (update_circle()) { + m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_ID); + auto it = m_raycasters.find(CIRCLE_ID); + if (it != m_raycasters.end()) + m_raycasters.erase(it); + m_raycasters.insert({ CIRCLE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_ID, *m_circle.mesh_raycaster) }); + } + } + } - if (!m_curr_feature.has_value() && !m_selected_features.first.feature.has_value()) - return; + if (!m_curr_feature.has_value() && !m_selected_features.first.feature.has_value()) + return; - GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light"); - if (shader == nullptr) - return; + GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light"); + if (shader == nullptr) + return; - shader->start_using(); - shader->set_uniform("projection_matrix", camera.get_projection_matrix()); + shader->start_using(); + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); - glsafe(::glClear(GL_DEPTH_BUFFER_BIT)); - glsafe(::glEnable(GL_DEPTH_TEST)); - const bool old_cullface = ::glIsEnabled(GL_CULL_FACE); - glsafe(::glDisable(GL_CULL_FACE)); + glsafe(::glClear(GL_DEPTH_BUFFER_BIT)); + glsafe(::glEnable(GL_DEPTH_TEST)); + const bool old_cullface = ::glIsEnabled(GL_CULL_FACE); + glsafe(::glDisable(GL_CULL_FACE)); - const Transform3d& view_matrix = camera.get_view_matrix(); + const Transform3d& view_matrix = camera.get_view_matrix(); - auto set_matrix_uniforms = [shader, &view_matrix](const Transform3d& model_matrix) { - const Transform3d view_model_matrix = view_matrix * model_matrix; - shader->set_uniform("view_model_matrix", view_model_matrix); - const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); - shader->set_uniform("view_normal_matrix", view_normal_matrix); - }; + auto set_matrix_uniforms = [shader, &view_matrix](const Transform3d& model_matrix) { + const Transform3d view_model_matrix = view_matrix * model_matrix; + shader->set_uniform("view_model_matrix", view_model_matrix); + const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); + shader->set_uniform("view_normal_matrix", view_normal_matrix); + }; - auto set_emission_uniform = [this, shader](const ColorRGBA& color, bool hover) { - shader->set_uniform("emission_factor", (color == m_parent.get_selection().get_first_volume()->render_color) ? 0.0f : - hover ? 0.5f : 0.25f); - }; + auto set_emission_uniform = [this, shader](const ColorRGBA& color, bool hover) { + shader->set_uniform("emission_factor", (color == m_parent.get_selection().get_first_volume()->render_color) ? 0.0f : + hover ? 0.5f : 0.25f); + }; - auto render_feature = [this, set_matrix_uniforms, set_emission_uniform](const Measure::SurfaceFeature& feature, const std::vector& colors, - float inv_zoom, bool hover, bool update_raycasters_transform) { - switch (feature.get_type()) - { - default: { assert(false); break; } - case Measure::SurfaceFeatureType::Point: - { -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - const Transform3d feature_matrix = Geometry::translation_transform(feature.get_point()) * Geometry::scale_transform(inv_zoom); -#else - const Vec3d position = TransformHelper::model_to_world(feature.get_point(), m_volume_matrix); - const Transform3d feature_matrix = Geometry::translation_transform(position) * Geometry::scale_transform(inv_zoom); -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - set_matrix_uniforms(feature_matrix); + auto render_feature = [this, set_matrix_uniforms, set_emission_uniform](const Measure::SurfaceFeature& feature, const std::vector& colors, + float inv_zoom, bool hover, bool update_raycasters_transform) { + switch (feature.get_type()) + { + default: { assert(false); break; } + case Measure::SurfaceFeatureType::Point: + { + const Transform3d feature_matrix = Geometry::translation_transform(feature.get_point()) * Geometry::scale_transform(inv_zoom); + set_matrix_uniforms(feature_matrix); + set_emission_uniform(colors.front(), hover); + m_sphere.model.set_color(colors.front()); + m_sphere.model.render(); + if (update_raycasters_transform) { + auto it = m_raycasters.find(POINT_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(feature_matrix); + } + break; + } + case Measure::SurfaceFeatureType::Circle: + { + const auto& [center, radius, normal] = feature.get_circle(); + // render center + if (update_raycasters_transform) { + const Transform3d center_matrix = Geometry::translation_transform(center) * Geometry::scale_transform(inv_zoom); + set_matrix_uniforms(center_matrix); set_emission_uniform(colors.front(), hover); m_sphere.model.set_color(colors.front()); m_sphere.model.render(); - if (update_raycasters_transform) { - auto it = m_raycasters.find(POINT_ID); - if (it != m_raycasters.end() && it->second != nullptr) - it->second->set_transform(feature_matrix); - } - break; + auto it = m_raycasters.find(POINT_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(center_matrix); } - case Measure::SurfaceFeatureType::Circle: - { - const auto& [center, radius, normal] = feature.get_circle(); - // render center + // render circle + if (m_mode != EMode::CenterSelection) { + const Transform3d circle_matrix = Transform3d::Identity(); + set_matrix_uniforms(circle_matrix); if (update_raycasters_transform) { -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - const Transform3d center_matrix = Geometry::translation_transform(center) * Geometry::scale_transform(inv_zoom); -#else - const Vec3d center_world = TransformHelper::model_to_world(center, m_volume_matrix); - const Transform3d center_matrix = Geometry::translation_transform(center_world) * Geometry::scale_transform(inv_zoom); -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - set_matrix_uniforms(center_matrix); + set_emission_uniform(colors.back(), hover); + m_circle.model.set_color(colors.back()); + m_circle.model.render(); + auto it = m_raycasters.find(CIRCLE_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(circle_matrix); + } + else { + GLModel circle; + GLModel::Geometry circle_geometry = init_torus_data(64, 16, center.cast(), float(radius), 5.0f * inv_zoom, normal.cast(), Transform3f::Identity()); + circle.init_from(std::move(circle_geometry)); + set_emission_uniform(colors.back(), hover); + circle.set_color(colors.back()); + circle.render(); + } + } + break; + } + case Measure::SurfaceFeatureType::Edge: + { + const auto& [from, to] = feature.get_edge(); + // render extra point + if (update_raycasters_transform) { + const std::optional extra = feature.get_extra_point(); + if (extra.has_value()) { + const Transform3d point_matrix = Geometry::translation_transform(*extra) * Geometry::scale_transform(inv_zoom); + set_matrix_uniforms(point_matrix); set_emission_uniform(colors.front(), hover); m_sphere.model.set_color(colors.front()); m_sphere.model.render(); auto it = m_raycasters.find(POINT_ID); if (it != m_raycasters.end() && it->second != nullptr) - it->second->set_transform(center_matrix); + it->second->set_transform(point_matrix); } - // render circle - if (m_mode != EMode::CenterSelection) { - const Transform3d circle_matrix = Transform3d::Identity(); - set_matrix_uniforms(circle_matrix); - if (update_raycasters_transform) { - set_emission_uniform(colors.back(), hover); - m_circle.model.set_color(colors.back()); - m_circle.model.render(); - auto it = m_raycasters.find(CIRCLE_ID); - if (it != m_raycasters.end() && it->second != nullptr) - it->second->set_transform(circle_matrix); - } - else { - GLModel circle; -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - GLModel::Geometry circle_geometry = init_torus_data(64, 16, center.cast(), float(radius), 5.0f * inv_zoom, normal.cast(), Transform3f::Identity()); -#else - GLModel::Geometry circle_geometry = init_torus_data(64, 16, center.cast(), float(radius), 5.0f * inv_zoom, normal.cast(), m_volume_matrix.cast()); -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - circle.init_from(std::move(circle_geometry)); - set_emission_uniform(colors.back(), hover); - circle.set_color(colors.back()); - circle.render(); - } - } - break; } - case Measure::SurfaceFeatureType::Edge: - { - const auto& [from, to] = feature.get_edge(); - // render extra point + // render edge + if (m_mode != EMode::CenterSelection) { + const Transform3d edge_matrix = Geometry::translation_transform(from) * + Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), to - from) * + Geometry::scale_transform({ (double)inv_zoom, (double)inv_zoom, (to - from).norm() }); + set_matrix_uniforms(edge_matrix); + set_emission_uniform(colors.back(), hover); + m_cylinder.model.set_color(colors.back()); + m_cylinder.model.render(); if (update_raycasters_transform) { - const std::optional extra = feature.get_extra_point(); - if (extra.has_value()) { -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - const Transform3d point_matrix = Geometry::translation_transform(*extra) * Geometry::scale_transform(inv_zoom); -#else - const Vec3d extra_world = TransformHelper::model_to_world(*extra, m_volume_matrix); - const Transform3d point_matrix = Geometry::translation_transform(extra_world) * Geometry::scale_transform(inv_zoom); -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - set_matrix_uniforms(point_matrix); - set_emission_uniform(colors.front(), hover); - m_sphere.model.set_color(colors.front()); - m_sphere.model.render(); - auto it = m_raycasters.find(POINT_ID); - if (it != m_raycasters.end() && it->second != nullptr) - it->second->set_transform(point_matrix); - } - } - // render edge - if (m_mode != EMode::CenterSelection) { -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - const Transform3d edge_matrix = Geometry::translation_transform(from) * - Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), to - from) * - Geometry::scale_transform({ (double)inv_zoom, (double)inv_zoom, (to - from).norm() }); -#else - const Vec3d from_world = TransformHelper::model_to_world(from, m_volume_matrix); - const Vec3d to_world = TransformHelper::model_to_world(to, m_volume_matrix); - const Transform3d edge_matrix = Geometry::translation_transform(from_world) * - Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), to_world - from_world) * - Geometry::scale_transform({ (double)inv_zoom, (double)inv_zoom, (to_world - from_world).norm() }); -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - set_matrix_uniforms(edge_matrix); - set_emission_uniform(colors.back(), hover); - m_cylinder.model.set_color(colors.back()); - m_cylinder.model.render(); - if (update_raycasters_transform) { - auto it = m_raycasters.find(EDGE_ID); - if (it != m_raycasters.end() && it->second != nullptr) - it->second->set_transform(edge_matrix); - } - } - break; - } - case Measure::SurfaceFeatureType::Plane: - { - // no need to render the plane in case it is rendered with the same color as the volume in the 3D scene - if (colors.front() != m_parent.get_selection().get_first_volume()->render_color) { - const auto& [idx, normal, pt] = feature.get_plane(); - assert(idx < m_plane_models_cache.size()); -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - set_matrix_uniforms(Transform3d::Identity()); -#else - set_matrix_uniforms(m_volume_matrix); -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - set_emission_uniform(colors.front(), hover); - m_plane_models_cache[idx].set_color(colors.front()); - m_plane_models_cache[idx].render(); - } - if (update_raycasters_transform) { - auto it = m_raycasters.find(PLANE_ID); + auto it = m_raycasters.find(EDGE_ID); if (it != m_raycasters.end() && it->second != nullptr) -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - it->second->set_transform(Transform3d::Identity()); -#else - it->second->set_transform(m_volume_matrix); -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + it->second->set_transform(edge_matrix); } - break; } + break; + } + case Measure::SurfaceFeatureType::Plane: + { + // no need to render the plane in case it is rendered with the same color as the volume in the 3D scene + if (colors.front() != m_parent.get_selection().get_first_volume()->render_color) { + const auto& [idx, normal, pt] = feature.get_plane(); + assert(idx < m_plane_models_cache.size()); + set_matrix_uniforms(Transform3d::Identity()); + set_emission_uniform(colors.front(), hover); + m_plane_models_cache[idx].set_color(colors.front()); + m_plane_models_cache[idx].render(); } - }; + if (update_raycasters_transform) { + auto it = m_raycasters.find(PLANE_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(Transform3d::Identity()); + } + break; + } + } + }; - auto hover_selection_color = [this]() { - return !m_selected_features.first.feature.has_value() ? SELECTED_1ST_COLOR : SELECTED_2ND_COLOR; - }; + auto hover_selection_color = [this]() { + return !m_selected_features.first.feature.has_value() ? SELECTED_1ST_COLOR : SELECTED_2ND_COLOR; + }; - auto hovering_color = [this, hover_selection_color, &selection]() { - return (m_mode == EMode::PointSelection) ? selection.get_first_volume()->render_color : hover_selection_color(); - }; + auto hovering_color = [this, hover_selection_color, &selection]() { + return (m_mode == EMode::PointSelection) ? selection.get_first_volume()->render_color : hover_selection_color(); + }; - if (m_curr_feature.has_value()) { - std::vector colors; - if (m_selected_features.first.feature.has_value() && *m_curr_feature == *m_selected_features.first.feature) + if (m_curr_feature.has_value()) { + std::vector colors; + if (m_selected_features.first.feature.has_value() && *m_curr_feature == *m_selected_features.first.feature) + colors.emplace_back(hovering_color()); + else if (m_selected_features.second.feature.has_value() && *m_curr_feature == *m_selected_features.second.feature) + colors.emplace_back(hovering_color()); + else { + switch (m_curr_feature->get_type()) + { + default: { assert(false); break; } + case Measure::SurfaceFeatureType::Point: + { + colors.emplace_back(hover_selection_color()); + break; + } + case Measure::SurfaceFeatureType::Edge: + case Measure::SurfaceFeatureType::Circle: + { + colors.emplace_back((m_hover_id == POINT_ID) ? hover_selection_color() : hovering_color()); colors.emplace_back(hovering_color()); - else if (m_selected_features.second.feature.has_value() && *m_curr_feature == *m_selected_features.second.feature) + break; + } + case Measure::SurfaceFeatureType::Plane: + { colors.emplace_back(hovering_color()); - else { - switch (m_curr_feature->get_type()) - { - default: { assert(false); break; } - case Measure::SurfaceFeatureType::Point: - { - colors.emplace_back(hover_selection_color()); - break; - } - case Measure::SurfaceFeatureType::Edge: - case Measure::SurfaceFeatureType::Circle: - { - colors.emplace_back((m_hover_id == POINT_ID) ? hover_selection_color() : hovering_color()); - colors.emplace_back(hovering_color()); - break; - } - case Measure::SurfaceFeatureType::Plane: - { - colors.emplace_back(hovering_color()); - break; - } - } + break; } - - render_feature(*m_curr_feature, colors, inv_zoom, true, true); - } - - if (m_selected_features.first.feature.has_value() && (!m_curr_feature.has_value() || *m_curr_feature != *m_selected_features.first.feature)) { - const std::vector colors = { SELECTED_1ST_COLOR }; - render_feature(*m_selected_features.first.feature, colors, inv_zoom, m_hover_id == SELECTION_1_ID, false); - if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Point) { - auto it = std::find_if(m_selection_raycasters.begin(), m_selection_raycasters.end(), - [](std::shared_ptr item) { return SceneRaycaster::decode_id(SceneRaycaster::EType::Gizmo, item->get_id()) == SELECTION_1_ID; }); - if (it != m_selection_raycasters.end()) -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - (*it)->set_transform(Geometry::translation_transform(m_selected_features.first.feature->get_point()) * Geometry::scale_transform(inv_zoom)); -#else - (*it)->set_transform(m_volume_matrix * Geometry::translation_transform(m_selected_features.first.feature->get_point()) * Geometry::scale_transform(inv_zoom)); -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - } - } - if (m_selected_features.second.feature.has_value() && (!m_curr_feature.has_value() || *m_curr_feature != *m_selected_features.second.feature)) { - const std::vector colors = { SELECTED_2ND_COLOR }; - render_feature(*m_selected_features.second.feature, colors, inv_zoom, m_hover_id == SELECTION_2_ID, false); - if (m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Point) { - auto it = std::find_if(m_selection_raycasters.begin(), m_selection_raycasters.end(), - [](std::shared_ptr item) { return SceneRaycaster::decode_id(SceneRaycaster::EType::Gizmo, item->get_id()) == SELECTION_2_ID; }); - if (it != m_selection_raycasters.end()) -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - (*it)->set_transform(Geometry::translation_transform(m_selected_features.second.feature->get_point()) * Geometry::scale_transform(inv_zoom)); -#else - (*it)->set_transform(m_volume_matrix * Geometry::translation_transform(m_selected_features.second.feature->get_point()) * Geometry::scale_transform(inv_zoom)); -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES } } - if (is_hovering_on_feature && m_curr_point_on_feature_position.has_value()) { - if (m_hover_id != POINT_ID) { -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - const Transform3d matrix = Geometry::translation_transform(*m_curr_point_on_feature_position) * Geometry::scale_transform(inv_zoom); -#else - const Vec3d position = TransformHelper::model_to_world(*m_curr_point_on_feature_position, m_volume_matrix); - const Transform3d matrix = Geometry::translation_transform(position) * Geometry::scale_transform(inv_zoom); -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - set_matrix_uniforms(matrix); - const ColorRGBA color = hover_selection_color(); - set_emission_uniform(color, true); - m_sphere.model.set_color(color); - m_sphere.model.render(); - } - } - - shader->stop_using(); - - if (old_cullface) - glsafe(::glEnable(GL_CULL_FACE)); -#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + render_feature(*m_curr_feature, colors, inv_zoom, true, true); } -#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + + if (m_selected_features.first.feature.has_value() && (!m_curr_feature.has_value() || *m_curr_feature != *m_selected_features.first.feature)) { + const std::vector colors = { SELECTED_1ST_COLOR }; + render_feature(*m_selected_features.first.feature, colors, inv_zoom, m_hover_id == SELECTION_1_ID, false); + if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Point) { + auto it = std::find_if(m_selection_raycasters.begin(), m_selection_raycasters.end(), + [](std::shared_ptr item) { return SceneRaycaster::decode_id(SceneRaycaster::EType::Gizmo, item->get_id()) == SELECTION_1_ID; }); + if (it != m_selection_raycasters.end()) + (*it)->set_transform(Geometry::translation_transform(m_selected_features.first.feature->get_point()) * Geometry::scale_transform(inv_zoom)); + } + } + if (m_selected_features.second.feature.has_value() && (!m_curr_feature.has_value() || *m_curr_feature != *m_selected_features.second.feature)) { + const std::vector colors = { SELECTED_2ND_COLOR }; + render_feature(*m_selected_features.second.feature, colors, inv_zoom, m_hover_id == SELECTION_2_ID, false); + if (m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Point) { + auto it = std::find_if(m_selection_raycasters.begin(), m_selection_raycasters.end(), + [](std::shared_ptr item) { return SceneRaycaster::decode_id(SceneRaycaster::EType::Gizmo, item->get_id()) == SELECTION_2_ID; }); + if (it != m_selection_raycasters.end()) + (*it)->set_transform(Geometry::translation_transform(m_selected_features.second.feature->get_point()) * Geometry::scale_transform(inv_zoom)); + } + } + + if (is_hovering_on_feature && m_curr_point_on_feature_position.has_value()) { + if (m_hover_id != POINT_ID) { + const Transform3d matrix = Geometry::translation_transform(*m_curr_point_on_feature_position) * Geometry::scale_transform(inv_zoom); + set_matrix_uniforms(matrix); + const ColorRGBA color = hover_selection_color(); + set_emission_uniform(color, true); + m_sphere.model.set_color(color); + m_sphere.model.render(); + } + } + + shader->stop_using(); + + if (old_cullface) + glsafe(::glEnable(GL_CULL_FACE)); render_dimensioning(); } @@ -1066,7 +942,6 @@ void GLGizmoMeasure::update_if_needed() } }; -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES auto do_update = [this, update_plane_models_cache](const std::vector& volumes_cache, const Selection& selection) { TriangleMesh composite_mesh; for (const auto& vol : volumes_cache) { @@ -1083,36 +958,11 @@ void GLGizmoMeasure::update_if_needed() m_raycaster.reset(new MeshRaycaster(std::make_shared(m_measuring->get_mesh()))); m_volumes_cache = volumes_cache; }; -#else - auto do_update = [this, update_plane_models_cache](const ModelObject* object, const ModelVolume* volume) { - const indexed_triangle_set& its = (volume != nullptr) ? volume->mesh().its : object->volumes.front()->mesh().its; - m_measuring.reset(new Measure::Measuring(its)); - - update_plane_models_cache(its); - - // Let's save what we calculated it from: - m_volumes_matrices.clear(); - m_volumes_types.clear(); - m_first_instance_scale = Vec3d::Ones(); - m_first_instance_mirror = Vec3d::Ones(); - if (object != nullptr) { - for (const ModelVolume* vol : object->volumes) { - m_volumes_matrices.push_back(vol->get_matrix()); - m_volumes_types.push_back(vol->type()); - } - m_first_instance_scale = object->instances.front()->get_scaling_factor(); - m_first_instance_mirror = object->instances.front()->get_mirror(); - } - m_old_model_object = object; - m_old_model_volume = volume; - }; -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES const Selection& selection = m_parent.get_selection(); if (selection.is_empty()) return; -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES const Selection::IndicesList& idxs = selection.get_volume_idxs(); std::vector volumes_cache; volumes_cache.reserve(idxs.size()); @@ -1130,36 +980,6 @@ void GLGizmoMeasure::update_if_needed() if (m_measuring == nullptr || m_volumes_cache != volumes_cache) do_update(volumes_cache, selection); -#else - m_volume_matrix = selection.get_first_volume()->world_matrix(); - - const ModelObject* mo = m_c->selection_info()->model_object(); - const ModelVolume* mv = m_c->selection_info()->model_volume(); - if (m_state != On || (mo == nullptr && mv == nullptr)) - return; - - if (mo == nullptr) - mo = mv->get_object(); - - if (mo->instances.empty()) - return; - - if (!m_measuring || mo != m_old_model_object || mv != m_old_model_volume || mo->volumes.size() != m_volumes_matrices.size()) - do_update(mo, mv); - - // We want to recalculate when the scale changes - some planes could (dis)appear. - if (!mo->instances.front()->get_scaling_factor().isApprox(m_first_instance_scale) || - !mo->instances.front()->get_mirror().isApprox(m_first_instance_mirror)) - do_update(mo, mv); - - for (unsigned int i = 0; i < mo->volumes.size(); ++i) { - if (!mo->volumes[i]->get_matrix().isApprox(m_volumes_matrices[i]) || - mo->volumes[i]->type() != m_volumes_types[i]) { - do_update(mo, mv); - break; - } - } -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES } void GLGizmoMeasure::disable_scene_raycasters() @@ -1279,7 +1099,6 @@ void GLGizmoMeasure::render_dimensioning() const double ratio = new_value / old_value; wxGetApp().plater()->take_snapshot(_L("Scale")); -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES struct TrafoData { double ratio; @@ -1333,7 +1152,6 @@ void GLGizmoMeasure::render_dimensioning() const TrafoData trafo_data(ratio, m_parent.get_selection().get_bounding_box().center()); scale_feature(*m_selected_features.first.feature, trafo_data); scale_feature(*m_selected_features.second.feature, trafo_data); -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES TransformationType type; type.set_world(); @@ -1392,14 +1210,7 @@ void GLGizmoMeasure::render_dimensioning() auto point_edge = [this, shader](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2) { assert(f1.get_type() == Measure::SurfaceFeatureType::Point && f2.get_type() == Measure::SurfaceFeatureType::Edge); std::pair e = f2.get_edge(); - // Transform to world coordinates -#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - e.first = TransformHelper::model_to_world(e.first, m_volume_matrix); - e.second = TransformHelper::model_to_world(e.second, m_volume_matrix); -#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - const Vec3d v_proj = m_measurement_result.distance_infinite->to; - const Vec3d e1e2 = e.second - e.first; const Vec3d v_proje1 = v_proj - e.first; const bool on_e1_side = v_proje1.dot(e1e2) < -EPSILON; @@ -1677,21 +1488,12 @@ void GLGizmoMeasure::render_debug_dialog() { case Measure::SurfaceFeatureType::Point: { -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES add_strings_row_to_table(*m_imgui, "m_pt1", ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(item.feature->get_point()), ImGui::GetStyleColorVec4(ImGuiCol_Text)); -#else - const Vec3d position = m_volume_matrix * item.feature->get_point(); - add_strings_row_to_table(*m_imgui, "m_pt1", ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(position), ImGui::GetStyleColorVec4(ImGuiCol_Text)); -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES break; } case Measure::SurfaceFeatureType::Edge: { auto [from, to] = item.feature->get_edge(); -#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - from = m_volume_matrix * from; - to = m_volume_matrix * to; -#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES add_strings_row_to_table(*m_imgui, "m_pt1", ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(from), ImGui::GetStyleColorVec4(ImGuiCol_Text)); add_strings_row_to_table(*m_imgui, "m_pt2", ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(to), ImGui::GetStyleColorVec4(ImGuiCol_Text)); break; @@ -1699,10 +1501,6 @@ void GLGizmoMeasure::render_debug_dialog() case Measure::SurfaceFeatureType::Plane: { auto [idx, normal, origin] = item.feature->get_plane(); -#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - origin = m_volume_matrix * origin; - normal = m_volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal; -#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES add_strings_row_to_table(*m_imgui, "m_pt1", ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(normal), ImGui::GetStyleColorVec4(ImGuiCol_Text)); add_strings_row_to_table(*m_imgui, "m_pt2", ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(origin), ImGui::GetStyleColorVec4(ImGuiCol_Text)); add_strings_row_to_table(*m_imgui, "m_value", ImGuiWrapper::COL_ORANGE_LIGHT, format_double(idx), ImGui::GetStyleColorVec4(ImGuiCol_Text)); @@ -1711,13 +1509,7 @@ void GLGizmoMeasure::render_debug_dialog() case Measure::SurfaceFeatureType::Circle: { auto [center, radius, normal] = item.feature->get_circle(); -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES const Vec3d on_circle = center + radius * Measure::get_orthogonal(normal, true); -#else - const Vec3d on_circle = m_volume_matrix * (center + radius * Measure::get_orthogonal(normal, true)); - center = m_volume_matrix * center; - normal = (m_volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal).normalized(); -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES radius = (on_circle - center).norm(); add_strings_row_to_table(*m_imgui, "m_pt1", ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(center), ImGui::GetStyleColorVec4(ImGuiCol_Text)); add_strings_row_to_table(*m_imgui, "m_pt2", ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(normal), ImGui::GetStyleColorVec4(ImGuiCol_Text)); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index fbbf30da78..9699d73cc8 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -6,16 +6,10 @@ #include "slic3r/GUI/GUI_Utils.hpp" #include "slic3r/GUI/MeshUtils.hpp" #include "libslic3r/Measure.hpp" -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES #include "libslic3r/Model.hpp" -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES namespace Slic3r { -#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES -class ModelVolume; -#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - enum class ModelVolumeType : int; namespace Measure { class Measuring; } @@ -74,7 +68,6 @@ class GLGizmoMeasure : public GLGizmoBase } }; -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES struct VolumeCacheItem { const ModelObject* object{ nullptr }; @@ -89,7 +82,6 @@ class GLGizmoMeasure : public GLGizmoBase }; std::vector m_volumes_cache; -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES EMode m_mode{ EMode::FeatureSelection }; Measure::MeasurementResult m_measurement_result; @@ -108,13 +100,10 @@ class GLGizmoMeasure : public GLGizmoBase }; Dimensioning m_dimensioning; -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES // Uses a standalone raycaster and not the shared one because of the // difference in how the mesh is updated std::unique_ptr m_raycaster; -#else - Transform3d m_volume_matrix{ Transform3d::Identity() }; -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + std::vector m_plane_models_cache; std::map> m_raycasters; std::vector> m_selection_raycasters; @@ -129,21 +118,11 @@ class GLGizmoMeasure : public GLGizmoBase std::vector m_scene_raycasters; // These hold information to decide whether recalculation is necessary: -#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - std::vector m_volumes_matrices; - std::vector m_volumes_types; - Vec3d m_first_instance_scale{ Vec3d::Ones() }; - Vec3d m_first_instance_mirror{ Vec3d::Ones() }; -#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES float m_last_inv_zoom{ 0.0f }; std::optional m_last_circle; int m_last_plane_idx{ -1 }; bool m_mouse_left_down{ false }; // for detection left_up of this gizmo -#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - const ModelObject* m_old_model_object{ nullptr }; - const ModelVolume* m_old_model_volume{ nullptr }; -#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES Vec2d m_mouse_pos{ Vec2d::Zero() }; @@ -186,9 +165,6 @@ protected: bool on_is_activable() const override; void on_render() override; void on_set_state() override; -#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - CommonGizmosDataID on_get_requirements() const override; -#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES virtual void on_render_input_window(float x, float y, float bottom_limit) override; virtual void on_register_raycasters_for_picking() override; diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index 2e50fc37c9..ee06e008b9 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -602,7 +602,6 @@ bool Selection::contains_any_volume(const std::vector& volume_idxs return false; } -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES bool Selection::contains_sinking_volumes(bool ignore_modifiers) const { for (const GLVolume* v : *m_volumes) { @@ -613,7 +612,6 @@ bool Selection::contains_sinking_volumes(bool ignore_modifiers) const } return false; } -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES bool Selection::matches(const std::vector& volume_idxs) const { diff --git a/src/slic3r/GUI/Selection.hpp b/src/slic3r/GUI/Selection.hpp index 0064f27999..080acda0d1 100644 --- a/src/slic3r/GUI/Selection.hpp +++ b/src/slic3r/GUI/Selection.hpp @@ -337,10 +337,8 @@ public: bool contains_all_volumes(const std::vector& volume_idxs) const; // returns true if the selection contains at least one of the given indices bool contains_any_volume(const std::vector& volume_idxs) const; -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES // returns true if the selection contains any sinking volume bool contains_sinking_volumes(bool ignore_modifiers = true) const; -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES // returns true if the selection contains all and only the given indices bool matches(const std::vector& volume_idxs) const; From 45e6dbab8fc3b023a800918734832c032ac977e1 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 16 Nov 2022 09:38:19 +0100 Subject: [PATCH 06/89] Gizmo measure - Fixed orientation of arrows in arc dimensioning --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index e35dc79fd2..e4973287e6 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -1292,7 +1292,7 @@ void GLGizmoMeasure::render_dimensioning() const double angle = (endpoint_id == 1) ? 0.0 : step * double(resolution); const Vec3d position_model = Geometry::translation_transform(center) * (draw_radius * (Eigen::Quaternion(Eigen::AngleAxisd(angle, normal)) * e1_unit)); const Vec3d direction_model = (endpoint_id == 1) ? -normal.cross(position_model - center).normalized() : normal.cross(position_model - center).normalized(); - const auto qz = Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), normal); + const auto qz = Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), (endpoint_id == 1) ? normal : -normal); const auto qx = Eigen::Quaternion::FromTwoVectors(qz * Vec3d::UnitX(), direction_model); const Transform3d view_model_matrix = camera.get_view_matrix() * Geometry::translation_transform(position_model) * qx * qz * Geometry::scale_transform(camera.get_inv_zoom()); From 5e6041823873055e55d9286d2a6df9c421046053 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 16 Nov 2022 09:42:55 +0100 Subject: [PATCH 07/89] Fixed warnings --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index e4973287e6..23b130d282 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -1115,7 +1115,7 @@ void GLGizmoMeasure::render_dimensioning() } }; - auto scale_feature = [this](Measure::SurfaceFeature& feature, const TrafoData& trafo_data) { + auto scale_feature = [](Measure::SurfaceFeature& feature, const TrafoData& trafo_data) { switch (feature.get_type()) { case Measure::SurfaceFeatureType::Point: @@ -1143,6 +1143,7 @@ void GLGizmoMeasure::render_dimensioning() feature = Measure::SurfaceFeature(Measure::SurfaceFeatureType::Plane, normal, trafo_data.transform(origin), std::nullopt, idx); break; } + default: { break; } } }; From 2c2f10beb7855654ff1289e8adbd39b917108806 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 16 Nov 2022 09:46:50 +0100 Subject: [PATCH 08/89] Fixed warnings --- src/libslic3r/Measure.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index cea9f0b77e..e3cd61cd1d 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -289,14 +289,14 @@ void MeasuringImpl::extract_features() // point happened to be inside the segment. The discrimination of too small segments // will follow, so we need a complete picture before that. if (circles_idxs.size() > 1 - && circles_idxs.back().second == angles.size()-1 + && circles_idxs.back().second == (int)angles.size()-1 && circles_idxs.front().first == 0) { // Possibly the same circle. Check that the angle and length criterion holds along the combined segment. bool same = true; double last_len = -1.; double last_angle = 0.; for (int i=circles_idxs.back().first + 1; i != circles_idxs.front().second; ++i) { - if (i == angles.size()) + if (i == (int)angles.size()) i = 1; if (last_len == -1.) { last_len = lengths[i]; @@ -345,12 +345,12 @@ void MeasuringImpl::extract_features() for (int i=int(circles_idxs.size())-1; i>=0; --i) { const auto& [start, end] = circles_idxs[i]; int N = start >= 0 - ? end - start + (start == 0 && end == border.size()-1 ? 0 : 1) // last point is the same as first + ? end - start + (start == 0 && end == (int)border.size()-1 ? 0 : 1) // last point is the same as first : end + (border.size() + start); if (N < 5) { circles.erase(circles.begin() + i); circles_idxs.erase(circles_idxs.begin() + i); - } else if (N <= 8 && start == 0 && end == border.size()-1) { + } else if (N <= 8 && start == 0 && end == (int)border.size()-1) { // This is a regular 5-8 polygon. Add the edges as edges with a special // point and remove the circle. Leave the indices in circles_idxs, so // the edges are not picked up again later. From 692573abf112e6b797cfa291cadec3c03544e9b9 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 16 Nov 2022 10:04:25 +0100 Subject: [PATCH 09/89] Removed debug code --- src/slic3r/GUI/MeshUtils.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/slic3r/GUI/MeshUtils.cpp b/src/slic3r/GUI/MeshUtils.cpp index 3805151af1..ba16aad251 100644 --- a/src/slic3r/GUI/MeshUtils.cpp +++ b/src/slic3r/GUI/MeshUtils.cpp @@ -409,12 +409,6 @@ bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& Vec3d direction; line_from_mouse_pos(mouse_pos, trafo, camera, point, direction); - if (rand()%100 == 0) { - int a=5; - int b=6; - int c=7; - } - std::vector hits = m_emesh.query_ray_hits(point, direction); if (hits.empty()) From 1f0fbd500afd7f41e5e84426fdbcb9b0c3f281f9 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 16 Nov 2022 12:04:38 +0100 Subject: [PATCH 10/89] Gizmo measure - Fixed angle for perpendicular edge-plane use case --- src/libslic3r/Measure.cpp | 53 +++++++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 19 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index e3cd61cd1d..535b898cf4 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -27,6 +27,21 @@ static std::pair get_center_and_radius(const std::vector& return std::make_pair(trafo.inverse() * Vec3d(circle.center.x(), circle.center.y(), z), circle.radius); } +static std::array orthonormal_basis(const Vec3d& v) +{ + std::array ret; + ret[2] = v.normalized(); + int index; + ret[2].maxCoeff(&index); + switch (index) + { + case 0: { ret[0] = Vec3d(ret[2].y(), -ret[2].x(), 0.0).normalized(); break; } + case 1: { ret[0] = Vec3d(0.0, ret[2].z(), -ret[2].y()).normalized(); break; } + case 2: { ret[0] = Vec3d(-ret[2].z(), 0.0, ret[2].x()).normalized(); break; } + } + ret[1] = ret[2].cross(ret[0]).normalized(); + return ret; +} @@ -628,8 +643,8 @@ static AngleAndEdges angle_edge_edge(const std::pair& e1, const st static AngleAndEdges angle_edge_plane(const std::pair& e, const std::tuple& p) { const auto& [idx, normal, origin] = p; - const Vec3d e1e2_unit = edge_direction(e); - if (are_parallel(e1e2_unit, normal) || are_perpendicular(e1e2_unit, normal)) + Vec3d e1e2_unit = edge_direction(e); + if (are_perpendicular(e1e2_unit, normal)) return AngleAndEdges::Dummy; // ensure the edge is pointing away from the intersection @@ -641,8 +656,22 @@ static AngleAndEdges angle_edge_plane(const std::pair& e, const st // then verify edge direction and revert it, if needed Vec3d e1 = e.first; Vec3d e2 = e.second; - if ((e1 - inters).squaredNorm() > (e2 - inters).squaredNorm()) + if ((e1 - inters).squaredNorm() > (e2 - inters).squaredNorm()) { std::swap(e1, e2); + e1e2_unit = -e1e2_unit; + } + + if (are_parallel(e1e2_unit, normal)) { + const std::array basis = orthonormal_basis(e1e2_unit); + const double radius = (0.5 * (e1 + e2) - inters).norm(); + const Vec3d edge_on_plane_dir = (basis[1].dot(origin - inters) >= 0.0) ? basis[1] : -basis[1]; + std::pair edge_on_plane = std::make_pair(inters, inters + radius * edge_on_plane_dir); + if (!inters.isApprox(e1)) { + edge_on_plane.first += radius * edge_on_plane_dir; + edge_on_plane.second += radius * edge_on_plane_dir; + } + return AngleAndEdges(0.5 * double(PI), inters, std::make_pair(e1, e2), edge_on_plane, radius, inters.isApprox(e1)); + } const Vec3d e1e2 = e2 - e1; const double e1e2_len = e1e2.norm(); @@ -771,7 +800,8 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// - } else if (f1.get_type() == SurfaceFeatureType::Edge) { + } + else if (f1.get_type() == SurfaceFeatureType::Edge) { if (f2.get_type() == SurfaceFeatureType::Edge) { std::vector distances; @@ -898,21 +928,6 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& const Vec3d D = c1 - c0; if (!are_parallel(n0, n1)) { - auto orthonormal_basis = [](const Vec3d& v) { - std::array ret; - ret[2] = v.normalized(); - int index; - ret[2].maxCoeff(&index); - switch (index) - { - case 0: { ret[0] = Vec3d(ret[2].y(), -ret[2].x(), 0.0).normalized(); break; } - case 1: { ret[0] = Vec3d(0.0, ret[2].z(), -ret[2].y()).normalized(); break; } - case 2: { ret[0] = Vec3d(-ret[2].z(), 0.0, ret[2].x()).normalized(); break; } - } - ret[1] = ret[2].cross(ret[0]).normalized(); - return ret; - }; - // Get parameters for constructing the degree-8 polynomial phi. const double one = 1.0; const double two = 2.0; From c57247b044928ed74318686d24a654bb26f61c84 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 16 Nov 2022 15:44:01 +0100 Subject: [PATCH 11/89] Removed debug code --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 23b130d282..33d65ddc53 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -396,7 +396,6 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) else if (mouse_event.RightDown()) { // let the event pass through to allow panning/rotating the 3D scene if ((m_mode != EMode::CenterSelection && mouse_event.CmdDown()) || (m_mode == EMode::CenterSelection && m_hover_id != SELECTION_1_ID && m_hover_id != SELECTION_2_ID)) { - std::cout << "RightDown -> false\n"; return false; } From 3eaa4b014996b8c37efba17eebaa048ad0eb9df8 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 18 Nov 2022 08:42:47 +0100 Subject: [PATCH 12/89] Gizmo measure - Draw background for dimensioning labels --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 33d65ddc53..6dfd5dbcec 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -1068,8 +1068,17 @@ void GLGizmoMeasure::render_dimensioning() ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, { 1.0f, 1.0f }); m_imgui->begin(std::string("distance"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration); + ImGui::BringWindowToDisplayFront(ImGui::GetCurrentWindow()); ImGui::AlignTextToFramePadding(); - m_imgui->text(curr_value_str + " " + units); + ImDrawList* draw_list = ImGui::GetWindowDrawList(); + const ImVec2 pos = ImGui::GetCursorScreenPos(); + const std::string txt = curr_value_str + " " + units; + ImVec2 txt_size = ImGui::CalcTextSize(txt.c_str()); + const ImGuiStyle& style = ImGui::GetStyle(); + draw_list->AddRectFilled({ pos.x - style.FramePadding.x, pos.y + style.FramePadding.y }, { pos.x + txt_size.x + 2.0f * style.FramePadding.x , pos.y + txt_size.y + 2.0f * style.FramePadding.y }, + ImGuiWrapper::to_ImU32(ColorRGBA(0.5f, 0.5f, 0.5f, 0.5f))); + ImGui::SetCursorScreenPos({ pos.x + style.FramePadding.x, pos.y }); + m_imgui->text(txt); ImGui::SameLine(); if (m_imgui->image_button(ImGui::SliderFloatEditBtnIcon, _L("Edit to scale"))) { m_editing_distance = true; @@ -1342,7 +1351,16 @@ void GLGizmoMeasure::render_dimensioning() ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); m_imgui->begin(_L("##angle"), ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove); ImGui::BringWindowToDisplayFront(ImGui::GetCurrentWindow()); - m_imgui->text(format_double(Geometry::rad2deg(angle)) + "°"); + ImGui::AlignTextToFramePadding(); + ImDrawList* draw_list = ImGui::GetWindowDrawList(); + const ImVec2 pos = ImGui::GetCursorScreenPos(); + const std::string txt = format_double(Geometry::rad2deg(angle)) + "°"; + ImVec2 txt_size = ImGui::CalcTextSize(txt.c_str()); + const ImGuiStyle& style = ImGui::GetStyle(); + draw_list->AddRectFilled({ pos.x - style.FramePadding.x, pos.y + style.FramePadding.y }, { pos.x + txt_size.x + 2.0f * style.FramePadding.x , pos.y + txt_size.y + 2.0f * style.FramePadding.y }, + ImGuiWrapper::to_ImU32(ColorRGBA(0.5f, 0.5f, 0.5f, 0.5f))); + ImGui::SetCursorScreenPos({ pos.x + style.FramePadding.x, pos.y }); + m_imgui->text(txt); m_imgui->end(); ImGui::PopStyleVar(); }; From 4435484a0a9aa254add6a7b2285910778efbd967 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 18 Nov 2022 10:53:42 +0100 Subject: [PATCH 13/89] Gizmo measure - Show diameter of selected circles into imgui dialog --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 6dfd5dbcec..36a8ab0474 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -1786,10 +1786,23 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit ImGui::Separator(); const ImGuiTableFlags flags = ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersH; if (ImGui::BeginTable("Selection", 2, flags)) { - add_strings_row_to_table(*m_imgui, _u8L("Selection") + " 1:", ImGuiWrapper::to_ImVec4(SELECTED_1ST_COLOR), m_selected_features.first.feature.has_value() ? - m_selected_features.first.source : _u8L("None"), ImGuiWrapper::to_ImVec4(SELECTED_1ST_COLOR)); - add_strings_row_to_table(*m_imgui, _u8L("Selection") + " 2:", ImGuiWrapper::to_ImVec4(SELECTED_2ND_COLOR), m_selected_features.second.feature.has_value() ? - m_selected_features.second.source : _u8L("None"), ImGuiWrapper::to_ImVec4(SELECTED_2ND_COLOR)); + auto format_item_text = [use_inches, &units](const SelectedFeatures::Item& item) { + std::string txt = item.feature.has_value() ? item.source : _u8L("None"); + if (item.feature.has_value() && item.feature->get_type() == Measure::SurfaceFeatureType::Circle) { + auto [center, radius, normal] = item.feature->get_circle(); + const Vec3d on_circle = center + radius * Measure::get_orthogonal(normal, true); + radius = (on_circle - center).norm(); + if (use_inches) + radius = ObjectManipulation::mm_to_in * radius; + txt += " (" + _u8L("Diameter:") + " " + format_double(2.0 * radius) + units + ")"; + } + return txt; + }; + + add_strings_row_to_table(*m_imgui, _u8L("Selection") + " 1:", ImGuiWrapper::to_ImVec4(SELECTED_1ST_COLOR), format_item_text(m_selected_features.first), + ImGuiWrapper::to_ImVec4(SELECTED_1ST_COLOR)); + add_strings_row_to_table(*m_imgui, _u8L("Selection") + " 2:", ImGuiWrapper::to_ImVec4(SELECTED_2ND_COLOR), format_item_text(m_selected_features.second), + ImGuiWrapper::to_ImVec4(SELECTED_2ND_COLOR)); ImGui::EndTable(); } From 83c0be60610aec8d763a4a7abeb1c501928203b0 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 18 Nov 2022 11:17:20 +0100 Subject: [PATCH 14/89] Removed commented out code --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 104 ----------------------- 1 file changed, 104 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 36a8ab0474..0b7a43c746 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -1679,110 +1679,6 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit const bool use_inches = wxGetApp().app_config->get("use_inches") == "1"; const std::string units = use_inches ? " " + _u8L("in") : " " + _u8L("mm"); - //const Measure::SurfaceFeatureType feature_type = m_curr_feature.has_value() ? m_curr_feature->get_type() : Measure::SurfaceFeatureType::Undef; - //bool data_text_set = false; - //ImGui::Separator(); - //if (feature_type != Measure::SurfaceFeatureType::Undef) { - // if (m_mode == EMode::FeatureSelection) { - // m_imgui->text(surface_feature_type_as_string(feature_type)); - // data_text_set = true; - // } - // else if (m_mode == EMode::PointSelection) { - // if (m_hover_id != -1 && m_curr_point_on_feature_position.has_value()) { - // m_imgui->text(point_on_feature_type_as_string(feature_type, m_hover_id)); - // data_text_set = true; - // } - // } - // else if (m_mode == EMode::CenterSelection) { - // if (m_hover_id != -1 && m_curr_point_on_feature_position.has_value()) { - // m_imgui->text(center_on_feature_type_as_string(feature_type)); - // data_text_set = true; - // } - // } - //} - //if (!data_text_set) - // m_imgui->text(_u8L("No feature")); - - //const unsigned int max_data_row_count = 3; - //unsigned int data_row_count = 0; - //if (ImGui::BeginTable("Data", 2)) { - // if (m_mode == EMode::FeatureSelection) { - // switch (feature_type) - // { - // default: { break; } - // case Measure::SurfaceFeatureType::Point: - // { - // Vec3d position = m_volume_matrix * m_curr_feature->get_point(); - // if (use_inches) - // position = ObjectManipulation::mm_to_in * position; - // add_strings_row_to_table(*m_imgui, _u8L("Position"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(position), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - // data_row_count = 1; - // break; - // } - // case Measure::SurfaceFeatureType::Edge: - // { - // auto [from, to] = m_curr_feature->get_edge(); - // from = m_volume_matrix * from; - // to = m_volume_matrix * to; - // if (use_inches) { - // from = ObjectManipulation::mm_to_in * from; - // to = ObjectManipulation::mm_to_in * to; - // } - // add_strings_row_to_table(*m_imgui, _u8L("From"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(from), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - // add_strings_row_to_table(*m_imgui, _u8L("To"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(to), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - // add_strings_row_to_table(*m_imgui, _u8L("Length"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double((to - from).norm()) + units, ImGui::GetStyleColorVec4(ImGuiCol_Text)); - // data_row_count = 3; - // break; - // } - // case Measure::SurfaceFeatureType::Circle: - // { - // auto [center, radius, normal] = m_curr_feature->get_circle(); - // // generic point on circle, used to recalculate radius after transformation - // const Vec3d on_circle = m_volume_matrix * (center + radius * Measure::get_orthogonal(normal, true)); - // center = m_volume_matrix * center; - // normal = (m_volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal).normalized(); - // radius = (on_circle - center).norm(); - // if (use_inches) { - // center = ObjectManipulation::mm_to_in * center; - // radius = ObjectManipulation::mm_to_in * radius; - // } - // add_strings_row_to_table(*m_imgui, _u8L("Center"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(center), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - // add_strings_row_to_table(*m_imgui, _u8L("Radius"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(radius) + units, ImGui::GetStyleColorVec4(ImGuiCol_Text)); - // add_strings_row_to_table(*m_imgui, _u8L("Normal"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(normal), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - // data_row_count = 3; - // break; - // } - // case Measure::SurfaceFeatureType::Plane: - // { - // auto [idx, normal, origin] = m_curr_feature->get_plane(); - // origin = m_volume_matrix * origin; - // normal = m_volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal; - // if (use_inches) - // origin = ObjectManipulation::mm_to_in * origin; - // add_strings_row_to_table(*m_imgui, _u8L("Origin"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(origin), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - // add_strings_row_to_table(*m_imgui, _u8L("Normal"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(normal), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - // data_row_count = 2; - // break; - // } - // } - // } - // else { - // if (m_hover_id != -1 && m_curr_point_on_feature_position.has_value()) { - // Vec3d position = m_volume_matrix * *m_curr_point_on_feature_position; - // if (use_inches) - // position = ObjectManipulation::mm_to_in * position; - // add_strings_row_to_table(*m_imgui, _u8L("Position"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(position), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - // data_row_count = 1; - // } - // } - - // // add dummy rows to keep dialog size fixed - // for (unsigned int i = data_row_count; i < max_data_row_count; ++i) { - // add_strings_row_to_table(*m_imgui, " ", ImGuiWrapper::COL_ORANGE_LIGHT, " ", ImGui::GetStyleColorVec4(ImGuiCol_Text)); - // } - // ImGui::EndTable(); - //} - ImGui::Separator(); const ImGuiTableFlags flags = ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersH; if (ImGui::BeginTable("Selection", 2, flags)) { From 3485db4f1b82495e34f33be1d3769466a1b6805b Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 18 Nov 2022 14:53:19 +0100 Subject: [PATCH 15/89] Gizmo measure - Render dimensioning thicker main lines --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 72 +++++++++++++++++++++++- 1 file changed, 69 insertions(+), 3 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 0b7a43c746..ed83ae7ca9 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -1003,7 +1003,7 @@ void GLGizmoMeasure::render_dimensioning() if (shader == nullptr) return; - auto point_point = [this, shader](const Vec3d& v1, const Vec3d& v2, float distance) { + auto point_point = [this, &shader](const Vec3d& v1, const Vec3d& v2, float distance) { if ((v2 - v1).squaredNorm() < 0.000001 || distance < 0.001f) return; @@ -1033,6 +1033,25 @@ void GLGizmoMeasure::render_dimensioning() const Transform3d ss_to_ndc_matrix = TransformHelper::ndc_to_ss_matrix_inverse(viewport); +#if ENABLE_GL_CORE_PROFILE + if (OpenGLManager::get_gl_info().is_core_profile()) { + shader->stop_using(); + + shader = wxGetApp().get_shader("dashed_thick_lines"); + if (shader == nullptr) + return; + + shader->start_using(); + shader->set_uniform("projection_matrix", Transform3d::Identity()); + const std::array& viewport = camera.get_viewport(); + shader->set_uniform("viewport_size", Vec2d(double(viewport[2]), double(viewport[3]))); + shader->set_uniform("width", 1.0f); + shader->set_uniform("gap_size", 0.0f); + } + else +#endif // ENABLE_GL_CORE_PROFILE + glsafe(::glLineWidth(2.0f)); + // stem shader->set_uniform("view_model_matrix", overlap ? ss_to_ndc_matrix * Geometry::translation_transform(v1ss_3) * q12ss * Geometry::translation_transform(-2.0 * TRIANGLE_HEIGHT * Vec3d::UnitX()) * Geometry::scale_transform({ v12ss_len + 4.0 * TRIANGLE_HEIGHT, 1.0f, 1.0f }) : @@ -1040,6 +1059,20 @@ void GLGizmoMeasure::render_dimensioning() m_dimensioning.line.set_color(ColorRGBA::WHITE()); m_dimensioning.line.render(); +#if ENABLE_GL_CORE_PROFILE + if (OpenGLManager::get_gl_info().is_core_profile()) { + shader->stop_using(); + + shader = wxGetApp().get_shader("flat"); + if (shader == nullptr) + return; + + shader->start_using(); + } + else +#endif // ENABLE_GL_CORE_PROFILE + glsafe(::glLineWidth(1.0f)); + // arrow 1 shader->set_uniform("view_model_matrix", overlap ? ss_to_ndc_matrix * Geometry::translation_transform(v1ss_3) * q12ss : @@ -1248,7 +1281,7 @@ void GLGizmoMeasure::render_dimensioning() } }; - auto arc_edge_edge = [this, shader](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2, double radius = 0.0) { + auto arc_edge_edge = [this, &shader](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2, double radius = 0.0) { assert(f1.get_type() == Measure::SurfaceFeatureType::Edge && f2.get_type() == Measure::SurfaceFeatureType::Edge); if (!m_measurement_result.angle.has_value()) return; @@ -1290,12 +1323,45 @@ void GLGizmoMeasure::render_dimensioning() m_dimensioning.arc.init_from(std::move(init_data)); } - // arc const Camera& camera = wxGetApp().plater()->get_camera(); +#if ENABLE_GL_CORE_PROFILE + if (OpenGLManager::get_gl_info().is_core_profile()) { + shader->stop_using(); + + shader = wxGetApp().get_shader("dashed_thick_lines"); + if (shader == nullptr) + return; + + shader->start_using(); + shader->set_uniform("projection_matrix", Transform3d::Identity()); + const std::array& viewport = camera.get_viewport(); + shader->set_uniform("viewport_size", Vec2d(double(viewport[2]), double(viewport[3]))); + shader->set_uniform("width", 1.0f); + shader->set_uniform("gap_size", 0.0f); + } + else +#endif // ENABLE_GL_CORE_PROFILE + glsafe(::glLineWidth(2.0f)); + + // arc shader->set_uniform("projection_matrix", camera.get_projection_matrix()); shader->set_uniform("view_model_matrix", camera.get_view_matrix() * Geometry::translation_transform(center)); m_dimensioning.arc.render(); +#if ENABLE_GL_CORE_PROFILE + if (OpenGLManager::get_gl_info().is_core_profile()) { + shader->stop_using(); + + shader = wxGetApp().get_shader("flat"); + if (shader == nullptr) + return; + + shader->start_using(); + } + else +#endif // ENABLE_GL_CORE_PROFILE + glsafe(::glLineWidth(1.0f)); + // arrows auto render_arrow = [this, shader, &camera, &normal, ¢er, &e1_unit, draw_radius, step, resolution](unsigned int endpoint_id) { const double angle = (endpoint_id == 1) ? 0.0 : step * double(resolution); From fdc9c73340060cea7d8335e1211836681e18cae0 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 21 Nov 2022 08:37:58 +0100 Subject: [PATCH 16/89] Gizmo Measure - When CTRL+dragging to pan/rotate the scene, do not select the hovered feature, if any --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index ed83ae7ca9..179e8c5d2d 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -254,6 +254,7 @@ GLGizmoMeasure::GLGizmoMeasure(GLCanvas3D& parent, const std::string& icon_filen bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) { m_mouse_pos = { double(mouse_event.GetX()), double(mouse_event.GetY()) }; + m_dragging = false; if (mouse_event.Moving()) { // only for sure @@ -261,6 +262,8 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) return false; } else if (mouse_event.Dragging()) { + m_dragging = true; + // Enable/Disable panning/rotating the 3D scene // Ctrl is pressed or the mouse is not hovering a selected volume bool unlock_dragging = mouse_event.CmdDown() || (m_hover_id == -1 && !m_parent.get_selection().contains_volume(m_parent.get_first_hover_volume_idx())); @@ -578,7 +581,9 @@ void GLGizmoMeasure::on_render() m_curr_point_on_feature_position.reset(); } else { - std::optional curr_feature = mouse_on_object ? m_measuring->get_feature(model_facet_idx, position_on_model.cast()) : std::nullopt; + std::optional curr_feature = m_dragging ? m_curr_feature : + mouse_on_object ? m_measuring->get_feature(model_facet_idx, position_on_model.cast()) : std::nullopt; + if (m_curr_feature != curr_feature || (curr_feature.has_value() && curr_feature->get_type() == Measure::SurfaceFeatureType::Circle && (m_curr_feature != curr_feature || m_last_inv_zoom != inv_zoom))) { m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, POINT_ID); From 4660527dda6881c1dfb51b115a75f8cfddf17cbd Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 21 Nov 2022 09:13:28 +0100 Subject: [PATCH 17/89] Gizmo Measure - Use [Delete] key in place of Shift+Right mouse to restart selection --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 13 ++++++------- src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 2 +- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 179e8c5d2d..153ffaf8df 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -401,12 +401,6 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) if ((m_mode != EMode::CenterSelection && mouse_event.CmdDown()) || (m_mode == EMode::CenterSelection && m_hover_id != SELECTION_1_ID && m_hover_id != SELECTION_2_ID)) { return false; } - - if (mouse_event.ShiftDown()) { - m_selected_features.reset(); - m_selection_raycasters.clear(); - m_parent.request_extra_frame(); - } } else if (mouse_event.Leaving()) m_mouse_left_down = false; @@ -477,6 +471,11 @@ bool GLGizmoMeasure::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_po m_mode = control_down ? EMode::PointSelection : EMode::FeatureSelection; restore_scene_raycasters_state(); } + else if (action == SLAGizmoEventType::Delete) { + m_selected_features.reset(); + m_selection_raycasters.clear(); + m_parent.request_extra_frame(); + } return true; } @@ -1735,7 +1734,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit } if (m_selected_features.first.feature.has_value()) { - add_strings_row_to_table(*m_imgui, _u8L("Shift") + "+" + _u8L("Right mouse button"), ImGuiWrapper::COL_ORANGE_LIGHT, _u8L("Restart selection"), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, _u8L("Delete"), ImGuiWrapper::COL_ORANGE_LIGHT, _u8L("Restart selection"), ImGui::GetStyleColorVec4(ImGuiCol_Text)); ++row_count; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index 07b4baa350..a97dce346d 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -552,7 +552,7 @@ bool GLGizmosManager::on_char(wxKeyEvent& evt) case WXK_BACK: case WXK_DELETE: { - if ((m_current == SlaSupports || m_current == Hollow || m_current == Cut) && gizmo_event(SLAGizmoEventType::Delete)) + if ((m_current == SlaSupports || m_current == Hollow || m_current == Cut || m_current == Measure) && gizmo_event(SLAGizmoEventType::Delete)) processed = true; break; From 5cbe5c9d73e83f39469d62c8e1614898fb58e734 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 21 Nov 2022 09:46:30 +0100 Subject: [PATCH 18/89] Gizmo Measure - Added [Restart selection] button to imgui dialog --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 153ffaf8df..ae1f90a258 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -1772,13 +1772,13 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit ImGui::EndTable(); } - //if (m_selected_features.first.feature.has_value()) { - // if (m_imgui->button(_u8L("Restart"))) { - // m_selected_features.reset(); - // m_selection_raycasters.clear(); - // m_imgui->set_requires_extra_frame(); - // } - //} + m_imgui->disabled_begin(!m_selected_features.first.feature.has_value()); + if (m_imgui->button(_u8L("Restart selection"))) { + m_selected_features.reset(); + m_selection_raycasters.clear(); + m_imgui->set_requires_extra_frame(); + } + m_imgui->disabled_end(); auto add_measure_row_to_table = [this](const std::string& col_1, const ImVec4& col_1_color, const std::string& col_2, const ImVec4& col_2_color) { ImGui::TableNextRow(); From f0e8a22504da74e8ddc3867a0cf14b821a32d736 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 21 Nov 2022 10:26:53 +0100 Subject: [PATCH 19/89] Gizmo Measure - Clicking on 1st selected let second selected to be promoted as first selected --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 27 +++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index ae1f90a258..1ec7cc5c1c 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -354,6 +354,10 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) else { if (!m_selected_features.second.feature.has_value()) m_selected_features.first.reset(); + else { + m_selected_features.first = m_selected_features.second; + m_selected_features.second.reset(); + } } } else { @@ -850,7 +854,7 @@ void GLGizmoMeasure::on_render() }; auto hover_selection_color = [this]() { - return !m_selected_features.first.feature.has_value() ? SELECTED_1ST_COLOR : SELECTED_2ND_COLOR; + return (!m_selected_features.first.feature.has_value() || *m_curr_feature == *m_selected_features.first.feature) ? SELECTED_1ST_COLOR : SELECTED_2ND_COLOR; }; auto hovering_color = [this, hover_selection_color, &selection]() { @@ -1690,14 +1694,27 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit std::string text; ColorRGBA color; if (m_selected_features.second.feature.has_value()) { - if (m_selected_features.second.feature == m_curr_feature && m_mode == EMode::FeatureSelection) + if (m_selected_features.first.feature == m_curr_feature && m_mode == EMode::FeatureSelection) { text = _u8L("Unselect feature"); - else if (m_hover_id == SELECTION_2_ID) + color = SELECTED_1ST_COLOR; + } + else if (m_selected_features.second.feature == m_curr_feature && m_mode == EMode::FeatureSelection) { + text = _u8L("Unselect feature"); + color = SELECTED_2ND_COLOR; + } + else if (m_hover_id == SELECTION_1_ID) { text = (m_mode == EMode::CenterSelection) ? _u8L("Unselect center") : _u8L("Unselect point"); - else + color = SELECTED_1ST_COLOR; + } + else if (m_hover_id == SELECTION_2_ID) { + text = (m_mode == EMode::CenterSelection) ? _u8L("Unselect center") : _u8L("Unselect point"); + color = SELECTED_2ND_COLOR; + } + else { text = (m_mode == EMode::PointSelection) ? _u8L("Select point") : (m_mode == EMode::CenterSelection) ? _u8L("Select center") : _u8L("Select feature"); - color = SELECTED_2ND_COLOR; + color = SELECTED_2ND_COLOR; + } } else { if (m_selected_features.first.feature.has_value()) { From 621a43c3a2b5eca5373206eee9798ee2bb33a7f7 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 21 Nov 2022 11:20:14 +0100 Subject: [PATCH 20/89] Gizmo Measure - Handling of [ESC] key When two features are selected -> unselected second feature When one feature is selected -> unselect first feature When no feature is selected -> close gizmo --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 31 ++++++++++++++++++++++- src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp | 1 + src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 5 +++- 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 1ec7cc5c1c..d50ef9e269 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -480,6 +480,16 @@ bool GLGizmoMeasure::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_po m_selection_raycasters.clear(); m_parent.request_extra_frame(); } + else if (action == SLAGizmoEventType::Escape) { + if (!m_selected_features.first.feature.has_value()) + return false; + else { + if (m_selected_features.second.feature.has_value()) + m_selected_features.second.feature.reset(); + else + m_selected_features.first.feature.reset(); + } + } return true; } @@ -1755,8 +1765,27 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit ++row_count; } + if (m_selected_features.first.feature.has_value() || m_selected_features.second.feature.has_value()) { + add_row_to_table( + [this]() { + m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, _u8L("Esc")); + }, + [this]() { + m_imgui->text_colored(ImGui::GetStyleColorVec4(ImGuiCol_Text), _u8L("Unselect")); + ImGui::SameLine(); + const ImVec2 pos = ImGui::GetCursorScreenPos(); + const float rect_size = ImGui::GetTextLineHeight(); + const ColorRGBA color = m_selected_features.second.feature.has_value() ? SELECTED_2ND_COLOR : SELECTED_1ST_COLOR; + ImGui::GetWindowDrawList()->AddRectFilled(ImVec2(pos.x + 1.0f, pos.y + 1.0f), ImVec2(pos.x + rect_size, pos.y + rect_size), ImGuiWrapper::to_ImU32(color)); + ImGui::Dummy(ImVec2(rect_size, rect_size)); + } + ); + + ++row_count; + } + // add dummy rows to keep dialog size fixed - for (unsigned int i = row_count; i < 4; ++i) { + for (unsigned int i = row_count; i < 5; ++i) { add_strings_row_to_table(*m_imgui, " ", ImGuiWrapper::COL_ORANGE_LIGHT, " ", ImGui::GetStyleColorVec4(ImGuiCol_Text)); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp index 3878c6b25a..c1b605726c 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp @@ -29,6 +29,7 @@ enum class SLAGizmoEventType : unsigned char { ShiftDown, ShiftUp, AltUp, + Escape, ApplyChanges, DiscardChanges, AutomaticGeneration, diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index a97dce346d..62ccce73e4 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -524,7 +524,10 @@ bool GLGizmosManager::on_char(wxKeyEvent& evt) case WXK_ESCAPE: { if (m_current != Undefined) { - if ((m_current != SlaSupports) || !gizmo_event(SLAGizmoEventType::DiscardChanges)) + if (m_current == Measure && gizmo_event(SLAGizmoEventType::Escape)) { + // do nothing + } + else if (m_current != SlaSupports || !gizmo_event(SLAGizmoEventType::DiscardChanges)) reset_all_states(); processed = true; From e6ea462ae63d6ae38e1cf174b32c2cfb6d1baaf5 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 21 Nov 2022 12:01:22 +0100 Subject: [PATCH 21/89] Gizmo Measure - Fixed point color and hint in dialog when adding a point on a selected feature --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index d50ef9e269..428ce5617e 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -864,7 +864,9 @@ void GLGizmoMeasure::on_render() }; auto hover_selection_color = [this]() { - return (!m_selected_features.first.feature.has_value() || *m_curr_feature == *m_selected_features.first.feature) ? SELECTED_1ST_COLOR : SELECTED_2ND_COLOR; + return ((m_mode == EMode::PointSelection && !m_selected_features.first.feature.has_value()) || + (m_mode != EMode::PointSelection && (!m_selected_features.first.feature.has_value() || *m_curr_feature == *m_selected_features.first.feature))) ? + SELECTED_1ST_COLOR : SELECTED_2ND_COLOR; }; auto hovering_color = [this, hover_selection_color, &selection]() { @@ -1728,11 +1730,14 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit } else { if (m_selected_features.first.feature.has_value()) { - if (m_selected_features.first.feature == m_curr_feature) + if (m_selected_features.first.feature == m_curr_feature && m_mode == EMode::FeatureSelection) { text = _u8L("Unselect feature"); - else if (m_hover_id == SELECTION_1_ID) + color = SELECTED_1ST_COLOR; + } + else if (m_hover_id == SELECTION_1_ID) { text = (m_mode == EMode::CenterSelection) ? _u8L("Unselect center") : _u8L("Unselect point"); - color = SELECTED_1ST_COLOR; + color = SELECTED_1ST_COLOR; + } } if (text.empty()) { text = (m_mode == EMode::PointSelection) ? _u8L("Select point") : From 42e78720f98fc36bc9e5cb74bbc5582290bcf839 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 21 Nov 2022 14:44:31 +0100 Subject: [PATCH 22/89] Fixed crash when opening Measure Gizmo after slicing in SLA mode --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 428ce5617e..2b6e1dcd3e 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -965,7 +965,7 @@ void GLGizmoMeasure::update_if_needed() // continue; TriangleMesh volume_mesh = vol.volume->mesh(); - volume_mesh.transform(vol.instance->get_transformation().get_matrix() * vol.volume->get_transformation().get_matrix()); + volume_mesh.transform(vol.world_trafo); composite_mesh.merge(volume_mesh); } @@ -984,10 +984,17 @@ void GLGizmoMeasure::update_if_needed() volumes_cache.reserve(idxs.size()); for (unsigned int idx : idxs) { const GLVolume* v = selection.get_volume(idx); + const int volume_idx = v->volume_idx(); + if (volume_idx < 0) + continue; + const ModelObject* obj = selection.get_model()->objects[v->object_idx()]; const ModelInstance* inst = obj->instances[v->instance_idx()]; - const ModelVolume* vol = obj->volumes[v->volume_idx()]; - const VolumeCacheItem item = { obj, inst, vol, inst->get_matrix() * vol->get_matrix() }; + const ModelVolume* vol = obj->volumes[volume_idx]; + const VolumeCacheItem item = { + obj, inst, vol, + Geometry::translation_transform(selection.get_first_volume()->get_sla_shift_z() * Vec3d::UnitZ()) * inst->get_matrix() * vol->get_matrix() + }; volumes_cache.emplace_back(item); } From b75e403d147eef901d13b15a1cb64a9e5cd6482b Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 22 Nov 2022 08:34:12 +0100 Subject: [PATCH 23/89] Gizmo measure - Fixed dimensioning after scaling a part of a multipart object --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 2b6e1dcd3e..1395847994 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -1171,16 +1171,14 @@ void GLGizmoMeasure::render_dimensioning() Vec3d new_pivot; Transform3d scale_matrix; - TrafoData(double ratio, const Vec3d& pivot) { + TrafoData(double ratio, const Vec3d& old_pivot, const Vec3d& new_pivot) { this->ratio = ratio; this->scale_matrix = Geometry::scale_transform(ratio); - this->old_pivot = pivot; - this->new_pivot = { pivot.x(), pivot.y(), (this->scale_matrix * pivot).z() }; + this->old_pivot = old_pivot; + this->new_pivot = new_pivot; } - Vec3d transform(const Vec3d& point) const { - return this->scale_matrix * (point - this->old_pivot) + this->new_pivot; - } + Vec3d transform(const Vec3d& point) const { return this->scale_matrix * (point - this->old_pivot) + this->new_pivot; } }; auto scale_feature = [](Measure::SurfaceFeature& feature, const TrafoData& trafo_data) { @@ -1215,22 +1213,26 @@ void GLGizmoMeasure::render_dimensioning() } }; - const TrafoData trafo_data(ratio, m_parent.get_selection().get_bounding_box().center()); - scale_feature(*m_selected_features.first.feature, trafo_data); - scale_feature(*m_selected_features.second.feature, trafo_data); - + // apply scale TransformationType type; type.set_world(); type.set_relative(); type.set_joint(); - // apply scale + // scale selection Selection& selection = m_parent.get_selection(); + const Vec3d old_center = selection.get_bounding_box().center(); selection.setup_cache(); selection.scale(ratio * Vec3d::Ones(), type); wxGetApp().plater()->canvas3D()->do_scale(""); // avoid storing another snapshot wxGetApp().obj_manipul()->set_dirty(); + // scale dimensioning + const Vec3d new_center = selection.get_bounding_box().center(); + const TrafoData trafo_data(ratio, old_center, new_center); + scale_feature(*m_selected_features.first.feature, trafo_data); + scale_feature(*m_selected_features.second.feature, trafo_data); + // update measure on next call to data_changed() m_pending_scale = true; }; From 9bdaf0bae2ba857204e3ed95c7683ab9baa4df8b Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 22 Nov 2022 12:36:51 +0100 Subject: [PATCH 24/89] Gizmo measure - Fixed incorrect point on feature detection --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 1395847994..1e4ba61c70 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -666,7 +666,7 @@ void GLGizmoMeasure::on_render() return trafo * p.cast(); } } - return Vec3d::Zero(); + return Vec3d(DBL_MAX, DBL_MAX, DBL_MAX); }; if (m_curr_feature.has_value()) { @@ -683,8 +683,11 @@ void GLGizmoMeasure::on_render() const std::optional extra = m_curr_feature->get_extra_point(); if (extra.has_value() && m_hover_id == POINT_ID) m_curr_point_on_feature_position = *extra; - else - m_curr_point_on_feature_position = position_on_feature(EDGE_ID, camera, [](const Vec3f& v) { return Vec3f(0.0f, 0.0f, v.z()); }); + else { + const Vec3d pos = position_on_feature(EDGE_ID, camera, [](const Vec3f& v) { return Vec3f(0.0f, 0.0f, v.z()); }); + if (!pos.isApprox(Vec3d(DBL_MAX, DBL_MAX, DBL_MAX))) + m_curr_point_on_feature_position = pos; + } break; } case Measure::SurfaceFeatureType::Plane: @@ -715,6 +718,7 @@ void GLGizmoMeasure::on_render() } } else { + m_curr_point_on_feature_position.reset(); if (m_curr_feature.has_value() && m_curr_feature->get_type() == Measure::SurfaceFeatureType::Circle) { if (update_circle()) { m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_ID); From d1146ae67a74ef441efbeac0bc55c951f70d028c Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 22 Nov 2022 13:13:25 +0100 Subject: [PATCH 25/89] Gizmo measure - Fixed calculation of angle edge-plane --- src/libslic3r/Measure.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index 535b898cf4..17689063c3 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -32,7 +32,7 @@ static std::array orthonormal_basis(const Vec3d& v) std::array ret; ret[2] = v.normalized(); int index; - ret[2].maxCoeff(&index); + ret[2].cwiseAbs().maxCoeff(&index); switch (index) { case 0: { ret[0] = Vec3d(ret[2].y(), -ret[2].x(), 0.0).normalized(); break; } From 456837d54159765592a749176fb27c5ab943af19 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 22 Nov 2022 14:40:35 +0100 Subject: [PATCH 26/89] Follow-up of fdc9c73340060cea7d8335e1211836681e18cae0 - Alternate implementation of 'When panning/rotating the scene, do not select the hovered feature, if any' --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 1e4ba61c70..0255bd1e3b 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -254,7 +254,6 @@ GLGizmoMeasure::GLGizmoMeasure(GLCanvas3D& parent, const std::string& icon_filen bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) { m_mouse_pos = { double(mouse_event.GetX()), double(mouse_event.GetY()) }; - m_dragging = false; if (mouse_event.Moving()) { // only for sure @@ -262,8 +261,6 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) return false; } else if (mouse_event.Dragging()) { - m_dragging = true; - // Enable/Disable panning/rotating the 3D scene // Ctrl is pressed or the mouse is not hovering a selected volume bool unlock_dragging = mouse_event.CmdDown() || (m_hover_id == -1 && !m_parent.get_selection().contains_volume(m_parent.get_first_hover_volume_idx())); @@ -594,7 +591,7 @@ void GLGizmoMeasure::on_render() m_curr_point_on_feature_position.reset(); } else { - std::optional curr_feature = m_dragging ? m_curr_feature : + std::optional curr_feature = wxGetMouseState().LeftIsDown() ? m_curr_feature : mouse_on_object ? m_measuring->get_feature(model_facet_idx, position_on_model.cast()) : std::nullopt; if (m_curr_feature != curr_feature || From d437d1bebf83df16c88340b8ffeb5d8d3f59dd64 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 23 Nov 2022 08:24:08 +0100 Subject: [PATCH 27/89] Gizmo measure - Fixed color of hovered features when part of the object is outside the printbed --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 0255bd1e3b..55f1027529 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -752,7 +752,7 @@ void GLGizmoMeasure::on_render() }; auto set_emission_uniform = [this, shader](const ColorRGBA& color, bool hover) { - shader->set_uniform("emission_factor", (color == m_parent.get_selection().get_first_volume()->render_color) ? 0.0f : + shader->set_uniform("emission_factor", (color == GLVolume::SELECTED_COLOR) ? 0.0f : hover ? 0.5f : 0.25f); }; @@ -871,7 +871,7 @@ void GLGizmoMeasure::on_render() }; auto hovering_color = [this, hover_selection_color, &selection]() { - return (m_mode == EMode::PointSelection) ? selection.get_first_volume()->render_color : hover_selection_color(); + return (m_mode == EMode::PointSelection) ? GLVolume::SELECTED_COLOR : hover_selection_color(); }; if (m_curr_feature.has_value()) { From 2a944d4cdeb616dfa5def543bf2fd19a88709a90 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 23 Nov 2022 09:10:56 +0100 Subject: [PATCH 28/89] Fixed warnings --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 55f1027529..6489340b89 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -751,7 +751,7 @@ void GLGizmoMeasure::on_render() shader->set_uniform("view_normal_matrix", view_normal_matrix); }; - auto set_emission_uniform = [this, shader](const ColorRGBA& color, bool hover) { + auto set_emission_uniform = [shader](const ColorRGBA& color, bool hover) { shader->set_uniform("emission_factor", (color == GLVolume::SELECTED_COLOR) ? 0.0f : hover ? 0.5f : 0.25f); }; @@ -870,7 +870,7 @@ void GLGizmoMeasure::on_render() SELECTED_1ST_COLOR : SELECTED_2ND_COLOR; }; - auto hovering_color = [this, hover_selection_color, &selection]() { + auto hovering_color = [this, hover_selection_color]() { return (m_mode == EMode::PointSelection) ? GLVolume::SELECTED_COLOR : hover_selection_color(); }; From cc13e8a44f3cc4711e9e0a03af45dd5cdb6df981 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 23 Nov 2022 12:03:36 +0100 Subject: [PATCH 29/89] Gizmo measure - Hide SLA supports and pad when opening the gizmo --- src/slic3r/GUI/GLCanvas3D.cpp | 19 +++++++++++++++++-- src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp | 5 +++++ src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 3 +++ 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index e631643aec..b64a982b8f 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1346,11 +1346,26 @@ void GLCanvas3D::toggle_sla_auxiliaries_visibility(bool visible, const ModelObje m_render_sla_auxiliaries = visible; +#if ENABLE_RAYCAST_PICKING + std::vector>* raycasters = get_raycasters_for_picking(SceneRaycaster::EType::Volume); +#endif // ENABLE_RAYCAST_PICKING + for (GLVolume* vol : m_volumes.volumes) { +#if ENABLE_RAYCAST_PICKING if ((mo == nullptr || m_model->objects[vol->composite_id.object_id] == mo) - && (instance_idx == -1 || vol->composite_id.instance_id == instance_idx) - && vol->composite_id.volume_id < 0) + && (instance_idx == -1 || vol->composite_id.instance_id == instance_idx) + && vol->composite_id.volume_id < 0) { vol->is_active = visible; + auto it = std::find_if(raycasters->begin(), raycasters->end(), [vol](std::shared_ptr item) { return item->get_raycaster() == vol->mesh_raycaster.get(); }); + if (it != raycasters->end()) + (*it)->set_active(vol->is_active); + } +#else + if ((mo == nullptr || m_model->objects[vol->composite_id.object_id] == mo) + && (instance_idx == -1 || vol->composite_id.instance_id == instance_idx) + && vol->composite_id.volume_id < 0) + vol->is_active = visible; +#endif // ENABLE_RAYCAST_PICKING } } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp index 1ce118d71d..51ea56c821 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp @@ -900,6 +900,11 @@ RENDER_AGAIN: bool show_sups = m_c->instances_hider()->are_supports_shown(); if (m_imgui->checkbox(m_desc["show_supports"], show_sups)) { m_c->instances_hider()->show_supports(show_sups); +#if ENABLE_RAYCAST_PICKING + if (show_sups) + // ensure supports and pad are disabled from picking even when they are visible + set_sla_auxiliary_volumes_picking_state(false); +#endif // ENABLE_RAYCAST_PICKING force_refresh = true; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 6489340b89..38dd4686e4 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -411,6 +411,8 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) void GLGizmoMeasure::data_changed() { + m_parent.toggle_sla_auxiliaries_visibility(false, nullptr, -1); + update_if_needed(); m_last_inv_zoom = 0.0f; @@ -500,6 +502,7 @@ bool GLGizmoMeasure::on_init() void GLGizmoMeasure::on_set_state() { if (m_state == Off) { + m_parent.toggle_sla_auxiliaries_visibility(true, nullptr, -1); m_ctrl_kar_filter.reset_count(); m_shift_kar_filter.reset_count(); m_curr_feature.reset(); From 3c1ec473a741939baee83d475040acfdaa71d41d Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 23 Nov 2022 12:37:54 +0100 Subject: [PATCH 30/89] Gizmo measure - Undo/Redo related fix --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 9699d73cc8..1672e8b74e 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -159,6 +159,11 @@ public: 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() override { return _u8L("Measure gizmo editing"); } + protected: bool on_init() override; std::string on_get_name() const override; From 9952003f61c9a9b12613b40846f8cd2af014a523 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Tue, 22 Nov 2022 09:49:10 +0100 Subject: [PATCH 31/89] Measurement: Fixed and refactored circle detection: - first/last segment of a circular segment was sometimes separated - circles were sometimes shown where they shouldn't be --- src/libslic3r/Measure.cpp | 236 +++++++++++++++++++------------------- 1 file changed, 120 insertions(+), 116 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index 17689063c3..e80ff50195 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -12,17 +12,17 @@ namespace Measure { constexpr double feature_hover_limit = 0.5; // how close to a feature the mouse must be to highlight it -static std::pair get_center_and_radius(const std::vector& border, int start_idx, int end_idx, const Transform3d& trafo) +static std::pair get_center_and_radius(const std::vector& points, const Transform3d& trafo) { - Vec2ds pts; + Vec2ds out; double z = 0.; - for (int i=start_idx; i<=end_idx; ++i) { - Vec3d pt_transformed = trafo * border[i]; + for (const Vec3d pt : points) { + Vec3d pt_transformed = trafo * pt; z = pt_transformed.z(); - pts.emplace_back(pt_transformed.x(), pt_transformed.y()); + out.emplace_back(pt_transformed.x(), pt_transformed.y()); } - auto circle = Geometry::circle_ransac(pts, 20); // FIXME: iterations? + auto circle = Geometry::circle_ransac(out, 20); // FIXME: iterations? return std::make_pair(trafo.inverse() * Vec3d(circle.center.x(), circle.center.y(), z), circle.radius); } @@ -214,6 +214,7 @@ void MeasuringImpl::update_planes() m_planes[plane_id].borders.pop_back(); else { assert(last_border.front() == last_border.back()); + last_border.pop_back(); } } } @@ -231,6 +232,9 @@ void MeasuringImpl::update_planes() void MeasuringImpl::extract_features() { + auto are_angles_same = [](double a, double b) { return Slic3r::is_approx(a,b); }; + auto are_lengths_same = [](double a, double b) { return Slic3r::is_approx(a,b); }; + std::vector angles; std::vector lengths; @@ -244,152 +248,152 @@ void MeasuringImpl::extract_features() q.setFromTwoVectors(plane.normal, Vec3d::UnitZ()); Transform3d trafo = Transform3d::Identity(); trafo.rotate(q); - + for (const std::vector& border : plane.borders) { if (border.size() <= 1) continue; - assert(border.front() == border.back()); - int start_idx = -1; - std::vector edges; + // Given an idx into border, return the index that is idx+offset position, + // while taking into account the need for warp-around and the fact that + // the first and last point are the same. + auto offset_to_index = [border_size = int(border.size())](int idx, int offset) -> int { + assert(std::abs(offset) < border_size); + int out = idx+offset; + if (out >= border_size) + out = out - border_size; + else if (out < 0) + out = border_size + out; + + return out; + }; // First calculate angles at all the vertices. angles.clear(); lengths.clear(); - for (int i=0; i M_PI) angle = 2*M_PI - angle; angles.push_back(angle); lengths.push_back(v2.norm()); + if (first_different_angle_idx == 0 && angles.size() > 1) { + if (! are_angles_same(angles.back(), angles[angles.size()-2])) + first_different_angle_idx = angles.size()-1; + } } assert(border.size() == angles.size()); assert(border.size() == lengths.size()); - // First go around the border and pick what might be circular segments. // Save pair of indices to where such potential segments start and end. // Also remember the length of these segments. + int start_idx = -1; bool circle = false; + bool first_iter = true; std::vector circles; + std::vector edges; std::vector> circles_idxs; - std::vector circles_lengths; - for (int i=1; i<(int)angles.size(); ++i) { - if (Slic3r::is_approx(lengths[i], lengths[i-1]) - && Slic3r::is_approx(angles[i], angles[i-1]) - && i != (int)angles.size()-1 ) { + //std::vector circles_lengths; + std::vector single_circle; // could be in loop-scope, but reallocations + double single_circle_length = 0.; + int first_pt_idx = offset_to_index(first_different_angle_idx, 1); + int i = first_pt_idx; + while (i != first_pt_idx || first_iter) { + if (are_angles_same(angles[i], angles[offset_to_index(i,-1)]) + && i != offset_to_index(first_pt_idx, -1) // not the last point + && i != start_idx ) { // circle if (! circle) { circle = true; - start_idx = std::max(0, i-2); + single_circle.clear(); + single_circle_length = 0.; + start_idx = offset_to_index(i, -2); + single_circle = { border[start_idx], border[offset_to_index(start_idx,1)] }; + single_circle_length += lengths[offset_to_index(i, -1)]; } + single_circle.emplace_back(border[i]); + single_circle_length += lengths[i]; } else { - if (circle) { - const auto& [center, radius] = get_center_and_radius(border, start_idx, i, trafo); - // Add the circle and remember indices into borders. - circles_idxs.emplace_back(start_idx, i); - circles.emplace_back(SurfaceFeature(SurfaceFeatureType::Circle, center, plane.normal, std::nullopt, radius)); - circles_lengths.emplace_back(std::accumulate(lengths.begin() + start_idx + 1, lengths.begin() + i + 1, 0.)); - circle = false; - } - } - } + if (circle && single_circle.size() >= 5) { // Less than 5 vertices? Not a circle. + single_circle.emplace_back(border[i]); + single_circle_length += lengths[i]; - // At this point we might need to merge the first and last segment, if the starting - // point happened to be inside the segment. The discrimination of too small segments - // will follow, so we need a complete picture before that. - if (circles_idxs.size() > 1 - && circles_idxs.back().second == (int)angles.size()-1 - && circles_idxs.front().first == 0) { - // Possibly the same circle. Check that the angle and length criterion holds along the combined segment. - bool same = true; - double last_len = -1.; - double last_angle = 0.; - for (int i=circles_idxs.back().first + 1; i != circles_idxs.front().second; ++i) { - if (i == (int)angles.size()) - i = 1; - if (last_len == -1.) { - last_len = lengths[i]; - last_angle = angles[i]; - } else { - if (! Slic3r::is_approx(lengths[i], last_len) || ! Slic3r::is_approx(angles[i], last_angle)) { - same = false; - break; + bool accept_circle = true; + { + // Check that lengths of internal (!!!) edges match. + int j = offset_to_index(start_idx, 3); + while (j != i) { + if (! are_lengths_same(lengths[offset_to_index(j,-1)], lengths[j])) { + accept_circle = false; + break; + } + j = offset_to_index(j, 1); + } + } + + if (accept_circle) { + const auto& [center, radius] = get_center_and_radius(single_circle, trafo); + + // Check that the fit went well. The tolerance is high, only to + // reject complete failures. + for (const Vec3d& pt : single_circle) { + if (std::abs((pt - center).norm() - radius) > 0.5) { + accept_circle = false; + break; + } + } + + // If the segment subtends less than 90 degrees, throw it away. + accept_circle &= single_circle_length / radius > 0.9*M_PI/2.; + + // If this is all-around and 5 to 8 vertices, consider it a polygon. + bool is_polygon = start_idx == i && single_circle.size() <= 9 && single_circle.size() >= 6; + + if (accept_circle) { + // Add the circle and remember indices into borders. + circles_idxs.emplace_back(start_idx, i); + if (is_polygon) { + for (int j=0; j<=i; ++j) // No wrap-around handling needed here. + edges.emplace_back(SurfaceFeature(SurfaceFeatureType::Edge, + border[j==0 ? border.size()-1 : j-1], border[j], + std::make_optional(center))); + } + else + circles.emplace_back(SurfaceFeature(SurfaceFeatureType::Circle, center, plane.normal, std::nullopt, radius)); + } } } + circle = false; } - if (same) { - // This seems to really be the same circle. Better apply ransac again. The parts can be small and inexact. - std::vector points(border.begin() + circles_idxs.back().first, border.end()); - points.insert(points.end(), border.begin(), border.begin() + circles_idxs.front().second+1); - auto [c, radius] = get_center_and_radius(points, 0, points.size()-1, trafo); - - // Now replace the first circle with the combined one, remove the last circle. - // First index of the first circle is saved negative - we are going to pick edges - // from the border later, we will need to know where the merged in segment was. - // The sign simplifies the algorithm that picks the remaining edges - see below. - circles.front() = SurfaceFeature(SurfaceFeatureType::Circle, c, plane.normal, std::nullopt, radius); - circles_idxs.front().first = - circles_idxs.back().first; - circles_lengths.front() += circles_lengths.back(); - circles.pop_back(); - circles_idxs.pop_back(); - circles_lengths.pop_back(); - } - } - - // Now throw away all circles that subtend less than 90 deg. - assert(circles.size() == circles_lengths.size()); - for (int i=0; i(circles[i].get_circle()); - if (circles_lengths[i] / r < 0.9*M_PI/2.) { - circles_lengths.erase(circles_lengths.begin() + i); - circles.erase(circles.begin() + i); - circles_idxs.erase(circles_idxs.begin() + i); - --i; - } + // Take care of the wrap around. + first_iter = false; + i = offset_to_index(i, 1); } - circles_lengths.clear(); // no longer needed, make it obvious - - // Anything under 5 vertices shall not be considered a circle. - assert(circles_idxs.size() == circles.size()); - for (int i=int(circles_idxs.size())-1; i>=0; --i) { - const auto& [start, end] = circles_idxs[i]; - int N = start >= 0 - ? end - start + (start == 0 && end == (int)border.size()-1 ? 0 : 1) // last point is the same as first - : end + (border.size() + start); - if (N < 5) { - circles.erase(circles.begin() + i); - circles_idxs.erase(circles_idxs.begin() + i); - } else if (N <= 8 && start == 0 && end == (int)border.size()-1) { - // This is a regular 5-8 polygon. Add the edges as edges with a special - // point and remove the circle. Leave the indices in circles_idxs, so - // the edges are not picked up again later. - const Vec3d center = std::get<0>(circles[i].get_circle()); - for (int j=1; j<=end; ++j) - edges.emplace_back(SurfaceFeature(SurfaceFeatureType::Edge, - border[j - 1], border[j], std::make_optional(center))); - circles.erase(circles.begin() + i); - } - } - // We have the circles. Now go around again and pick edges, while jumping over circles. - // If the first index of the first circle is negative, it means that it was merged - // with a segment that was originally at the back and is no longer there. Ressurect - // its pair of indices so that edges are not picked again. - if (! circles_idxs.empty() && circles_idxs.front().first < 0) - circles_idxs.emplace_back(-circles_idxs.front().first, int(border.size())); - int cidx = 0; // index of next circle to jump over - for (int i=1; i (int)circles_idxs[cidx].first) - i = circles_idxs[cidx++].second; - else - edges.emplace_back(SurfaceFeature(SurfaceFeatureType::Edge, border[i - 1], border[i])); + if (circles_idxs.empty()) { + // Just add all edges. + for (int i=1; i Date: Fri, 25 Nov 2022 13:45:23 +0100 Subject: [PATCH 32/89] Measurement: prevent ending up in an infinite loop with broken models --- src/libslic3r/Measure.cpp | 16 ++++++++++++++-- src/libslic3r/SurfaceMesh.hpp | 9 +++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index e80ff50195..5b9a75c045 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -187,10 +187,16 @@ void MeasuringImpl::update_planes() he = sm.next_around_target(he); if (he.is_invalid()) goto PLANE_FAILURE; + + // For broken meshes, the iteration might never get back to he_orig. + // Remember all halfedges we saw to break out of such infinite loops. + boost::container::small_vector he_seen; + while ( (int)m_face_to_plane[sm.face(he)] == plane_id && he != he_orig) { + he_seen.emplace_back(he); he = sm.next_around_target(he); - if (he.is_invalid()) - goto PLANE_FAILURE; + if (he.is_invalid() || std::find(he_seen.begin(), he_seen.end(), he) != he_seen.end()) + goto PLANE_FAILURE; } he = sm.opposite(he); if (he.is_invalid()) @@ -208,6 +214,12 @@ void MeasuringImpl::update_planes() visited[face_it - facets.begin()][he.side()] = true; last_border.emplace_back(sm.point(sm.source(he)).cast()); + + // In case of broken meshes, this loop might be infinite. Break + // out in case it is clearly going bad. + if (last_border.size() > 3*facets.size()) + goto PLANE_FAILURE; + } while (he != he_start); if (last_border.size() == 1) diff --git a/src/libslic3r/SurfaceMesh.hpp b/src/libslic3r/SurfaceMesh.hpp index 9e547eec49..93eb9fdaa6 100644 --- a/src/libslic3r/SurfaceMesh.hpp +++ b/src/libslic3r/SurfaceMesh.hpp @@ -4,6 +4,8 @@ #include #include +#include "boost/container/small_vector.hpp" + namespace Slic3r { class TriangleMesh; @@ -115,11 +117,18 @@ public: size_t degree(Vertex_index v) const { + // In case the mesh is broken badly, the loop might end up to be infinite, + // never getting back to the first halfedge. Remember list of all half-edges + // and trip if any is encountered for the second time. Halfedge_index h_first = halfedge(v); + boost::container::small_vector he_visited; Halfedge_index h = next_around_target(h_first); size_t degree = 2; while (! h.is_invalid() && h != h_first) { + he_visited.emplace_back(h); h = next_around_target(h); + if (std::find(he_visited.begin(), he_visited.end(), h) == he_visited.end()) + return 0; ++degree; } return h.is_invalid() ? 0 : degree - 1; From 5a3f36da0106a03ded52a066dc45507bae763b4b Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 29 Nov 2022 11:13:09 +0100 Subject: [PATCH 33/89] Tech ENABLE_RAYCAST_PICKING_DEBUG - Extended data shown into debug imgui dialog --- src/slic3r/GUI/GLCanvas3D.cpp | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index b64a982b8f..0261501d50 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -5508,12 +5508,17 @@ void GLCanvas3D::_picking_pass() default: { break; } } - auto add_strings_row_to_table = [&imgui](const std::string& col_1, const ImVec4& col_1_color, const std::string& col_2, const ImVec4& col_2_color) { + auto add_strings_row_to_table = [&imgui](const std::string& col_1, const ImVec4& col_1_color, const std::string& col_2, const ImVec4& col_2_color, + const std::string& col_3 = "", const ImVec4& col_3_color = ImGui::GetStyleColorVec4(ImGuiCol_Text)) { ImGui::TableNextRow(); ImGui::TableSetColumnIndex(0); imgui.text_colored(col_1_color, col_1.c_str()); ImGui::TableSetColumnIndex(1); imgui.text_colored(col_2_color, col_2.c_str()); + if (!col_3.empty()) { + ImGui::TableSetColumnIndex(2); + imgui.text_colored(col_3_color, col_3.c_str()); + } }; char buf[1024]; @@ -5542,6 +5547,21 @@ void GLCanvas3D::_picking_pass() add_strings_row_to_table("Gizmo elements", ImGuiWrapper::COL_ORANGE_LIGHT, std::string(buf), ImGui::GetStyleColorVec4(ImGuiCol_Text)); ImGui::EndTable(); } + + std::vector>* gizmo_raycasters = m_scene_raycaster.get_raycasters(SceneRaycaster::EType::Gizmo); + if (gizmo_raycasters != nullptr && !gizmo_raycasters->empty()) { + ImGui::Separator(); + imgui.text("Gizmo raycasters IDs:"); + if (ImGui::BeginTable("GizmoRaycasters", 3)) { + for (size_t i = 0; i < gizmo_raycasters->size(); ++i) { + add_strings_row_to_table(std::to_string(i), ImGuiWrapper::COL_ORANGE_LIGHT, + std::to_string(SceneRaycaster::decode_id(SceneRaycaster::EType::Gizmo, (*gizmo_raycasters)[i]->get_id())), ImGui::GetStyleColorVec4(ImGuiCol_Text), + to_string(Geometry::Transformation((*gizmo_raycasters)[i]->get_transform()).get_offset()), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + } + ImGui::EndTable(); + } + } + imgui.end(); #endif // ENABLE_RAYCAST_PICKING_DEBUG } From 2a82f1d39689e5fffbe1d1dc3fee085489d4733e Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 30 Nov 2022 11:58:02 +0100 Subject: [PATCH 34/89] Gizmo measure - Modified circle and edge with extra point selection --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 510 ++++++++++++++--------- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 18 +- 2 files changed, 320 insertions(+), 208 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 38dd4686e4..eb1a7162eb 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -20,15 +20,16 @@ namespace Slic3r { namespace GUI { -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 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 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 SELECTION_1_ID = 501; -static const int SELECTION_2_ID = 502; +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; @@ -164,6 +165,41 @@ static GLModel::Geometry init_torus_data(unsigned int primary_resolution, unsign return data; } +static bool is_feature_with_center(const Measure::SurfaceFeature& feature) +{ + const Measure::SurfaceFeatureType type = feature.get_type(); + return (type == Measure::SurfaceFeatureType::Circle || (type == Measure::SurfaceFeatureType::Edge && feature.get_extra_point().has_value())); +} + +static Vec3d get_feature_offset(const Measure::SurfaceFeature& feature) +{ + Vec3d ret; + switch (feature.get_type()) + { + case Measure::SurfaceFeatureType::Circle: + { + const auto [center, radius, normal] = feature.get_circle(); + ret = center; + break; + } + case Measure::SurfaceFeatureType::Edge: + { + std::optional p = feature.get_extra_point(); + assert(p.has_value()); + ret = *p; + break; + } + case Measure::SurfaceFeatureType::Point: + { + ret = feature.get_point(); + break; + } + default: { assert(false); } + } + + return ret; +} + class TransformHelper { struct Cache @@ -265,109 +301,125 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) // Ctrl is pressed or the mouse is not hovering a selected volume bool unlock_dragging = mouse_event.CmdDown() || (m_hover_id == -1 && !m_parent.get_selection().contains_volume(m_parent.get_first_hover_volume_idx())); // mode is not center selection or mouse is not hovering a center - unlock_dragging &= !mouse_event.ShiftDown() || (m_hover_id != SELECTION_1_ID && m_hover_id != SELECTION_2_ID && m_hover_id != POINT_ID); + unlock_dragging &= !mouse_event.ShiftDown() || (m_hover_id != SEL_SPHERE_1_ID && m_hover_id != SEL_SPHERE_2_ID && m_hover_id != POINT_ID); return !unlock_dragging; } else if (mouse_event.LeftDown()) { // let the event pass through to allow panning/rotating the 3D scene - if ((m_mode != EMode::CenterSelection && mouse_event.CmdDown()) || - (m_mode == EMode::CenterSelection && m_hover_id != SELECTION_1_ID && m_hover_id != SELECTION_2_ID && m_hover_id != POINT_ID)) { + if (mouse_event.CmdDown()) return false; - } if (m_hover_id != -1) { SelectedFeatures selected_features_old = m_selected_features; m_mouse_left_down = true; - auto item_from_feature = [this]() { + auto detect_current_item = [this]() { SelectedFeatures::Item item; - if (m_hover_id == SELECTION_1_ID && m_selected_features.first.feature.has_value()) - item = m_selected_features.first; - else if (m_hover_id == SELECTION_2_ID && m_selected_features.second.feature.has_value()) - item = m_selected_features.second; + if (m_hover_id == SEL_SPHERE_1_ID) { + if (m_selected_features.first.is_center) + // mouse is hovering over a selected center + item = { true, m_selected_features.first.source, { Measure::SurfaceFeature(get_feature_offset(*m_selected_features.first.source)) } }; + else if (is_feature_with_center(*m_selected_features.first.feature)) + // mouse is hovering over a unselected center + item = { true, m_selected_features.first.feature, { Measure::SurfaceFeature(get_feature_offset(*m_selected_features.first.feature)) } }; + else + // mouse is hovering over a point + item = m_selected_features.first; + } + else if (m_hover_id == SEL_SPHERE_2_ID) { + if (m_selected_features.second.is_center) + // mouse is hovering over a selected center + item = { true, m_selected_features.second.source, { Measure::SurfaceFeature(get_feature_offset(*m_selected_features.second.source)) } }; + else if (is_feature_with_center(*m_selected_features.second.feature)) + // mouse is hovering over a center + item = { true, m_selected_features.second.feature, { Measure::SurfaceFeature(get_feature_offset(*m_selected_features.second.feature)) } }; + else + // mouse is hovering over a point + item = m_selected_features.second; + } else { switch (m_mode) { - case EMode::FeatureSelection: - { - item = { surface_feature_type_as_string(m_curr_feature->get_type()), m_curr_feature }; - break; - } - case EMode::PointSelection: - { - item = { point_on_feature_type_as_string(m_curr_feature->get_type(), m_hover_id), Measure::SurfaceFeature(*m_curr_point_on_feature_position) }; - break; - } - case EMode::CenterSelection: - { - Vec3d position; - switch (m_curr_feature->get_type()) - { - case Measure::SurfaceFeatureType::Circle: - { - position = std::get<0>(m_curr_feature->get_circle()); - break; - } - case Measure::SurfaceFeatureType::Edge: - { - assert(m_curr_feature->get_extra_point().has_value()); - position = *m_curr_feature->get_extra_point(); - break; - } - default: { assert(false); break; } - } - - item = { center_on_feature_type_as_string(m_curr_feature->get_type()), Measure::SurfaceFeature(position) }; - break; - } + case EMode::FeatureSelection: { item = { false, m_curr_feature, m_curr_feature }; break; } + case EMode::PointSelection: { item = { false, m_curr_feature, Measure::SurfaceFeature(*m_curr_point_on_feature_position) }; break; } } } return item; }; - if (m_selected_features.first.feature.has_value()) { - auto it = std::find_if(m_selection_raycasters.begin(), m_selection_raycasters.end(), - [](std::shared_ptr item) { return SceneRaycaster::decode_id(SceneRaycaster::EType::Gizmo, item->get_id()) == SELECTION_2_ID; }); - if (it != m_selection_raycasters.end()) - m_selection_raycasters.erase(it); - m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, SELECTION_2_ID); + auto requires_sphere_raycaster_for_picking = [this](const SelectedFeatures::Item& item) { + if (m_mode == EMode::PointSelection) + return true; + else if (m_mode == EMode::FeatureSelection) { + if (is_feature_with_center(*item.feature)) + return true; + } + return false; + }; - const SelectedFeatures::Item item = item_from_feature(); + if (m_selected_features.first.feature.has_value()) { + const SelectedFeatures::Item item = detect_current_item(); if (m_selected_features.first != item) { - if (m_selected_features.second == item) - m_selected_features.second.reset(); - else { - m_selected_features.second = item; - if (m_mode == EMode::PointSelection || m_mode == EMode::CenterSelection) - m_selection_raycasters.push_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, SELECTION_2_ID, *m_sphere.mesh_raycaster)); - if (m_mode == EMode::CenterSelection) { - // Fake ctrl up event to exit the center selection mode - gizmo_event(SLAGizmoEventType::CtrlUp, Vec2d::Zero(), true, false, false); - // increase counter to avoid that keeping the ctrl key pressed triggers a ctrl down event - m_ctrl_kar_filter.increase_count(); + bool processed = false; + if (item.is_center) { + if (item.source == m_selected_features.first.feature) { + // switch 1st selection from feature to its center + m_selected_features.first = item; + processed = true; + } + else if (item.source == m_selected_features.second.feature) { + // switch 2nd selection from feature to its center + m_selected_features.second = item; + processed = true; + } + } + else if (is_feature_with_center(*item.feature)) { + if (m_selected_features.first.is_center && m_selected_features.first.source == item.feature) { + // switch 1st selection from center to its feature + m_selected_features.first = item; + processed = true; + } + else if (m_selected_features.second.is_center && m_selected_features.second.source == item.feature) { + // switch 2nd selection from center to its feature + m_selected_features.second = item; + processed = true; + } + } + + if (!processed) { + remove_selected_sphere_raycaster(SEL_SPHERE_2_ID); + if (m_selected_features.second == item) + // 2nd feature deselection + m_selected_features.second.reset(); + else { + // 2nd feature selection + m_selected_features.second = item; + if (requires_sphere_raycaster_for_picking(item)) + m_selected_sphere_raycasters.push_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, SEL_SPHERE_2_ID, *m_sphere.mesh_raycaster)); } } } else { - if (!m_selected_features.second.feature.has_value()) - m_selected_features.first.reset(); - else { + remove_selected_sphere_raycaster(SEL_SPHERE_1_ID); + if (m_selected_features.second.feature.has_value()) { + // promote 2nd feature to 1st feature + remove_selected_sphere_raycaster(SEL_SPHERE_2_ID); m_selected_features.first = m_selected_features.second; + if (requires_sphere_raycaster_for_picking(m_selected_features.first)) + m_selected_sphere_raycasters.push_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, SEL_SPHERE_1_ID, *m_sphere.mesh_raycaster)); m_selected_features.second.reset(); } + else + // 1st feature deselection + m_selected_features.first.reset(); } } else { - const SelectedFeatures::Item item = item_from_feature(); + // 1st feature selection + const SelectedFeatures::Item item = detect_current_item(); m_selected_features.first = item; - if (m_mode == EMode::PointSelection || m_mode == EMode::CenterSelection) - m_selection_raycasters.push_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, SELECTION_1_ID, *m_sphere.mesh_raycaster)); - if (m_mode == EMode::CenterSelection) { - // Fake ctrl up event to exit the center selection mode - gizmo_event(SLAGizmoEventType::CtrlUp, Vec2d::Zero(), true, false, false); - // increase counter to avoid that keeping the ctrl key pressed triggers a ctrl down event - m_ctrl_kar_filter.increase_count(); - } + if (requires_sphere_raycaster_for_picking(item)) + m_selected_sphere_raycasters.push_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, SEL_SPHERE_1_ID, *m_sphere.mesh_raycaster)); } if (m_selected_features != selected_features_old && m_selected_features.second.feature.has_value()) @@ -399,9 +451,8 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) } else if (mouse_event.RightDown()) { // let the event pass through to allow panning/rotating the 3D scene - if ((m_mode != EMode::CenterSelection && mouse_event.CmdDown()) || (m_mode == EMode::CenterSelection && m_hover_id != SELECTION_1_ID && m_hover_id != SELECTION_2_ID)) { + if (mouse_event.CmdDown()) return false; - } } else if (mouse_event.Leaving()) m_mouse_left_down = false; @@ -423,7 +474,7 @@ void GLGizmoMeasure::data_changed() } else m_selected_features.reset(); - m_selection_raycasters.clear(); + m_selected_sphere_raycasters.clear(); m_editing_distance = false; m_is_editing_distance_first_frame = true; } @@ -450,7 +501,7 @@ bool GLGizmoMeasure::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_po if (action == SLAGizmoEventType::ShiftDown) { if (m_shift_kar_filter.is_first()) { - m_mode = activate_center_selection(SLAGizmoEventType::ShiftDown) ? EMode::CenterSelection : EMode::PointSelection; + m_mode = EMode::PointSelection; disable_scene_raycasters(); } m_shift_kar_filter.increase_count(); @@ -460,33 +511,23 @@ bool GLGizmoMeasure::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_po m_mode = EMode::FeatureSelection; restore_scene_raycasters_state(); } - else if (action == SLAGizmoEventType::CtrlDown) { - if (m_ctrl_kar_filter.is_first()) { - if (activate_center_selection(SLAGizmoEventType::CtrlDown)) { - m_mode = EMode::CenterSelection; - disable_scene_raycasters(); - } - } - m_ctrl_kar_filter.increase_count(); - } - else if (action == SLAGizmoEventType::CtrlUp) { - m_ctrl_kar_filter.reset_count(); - m_mode = control_down ? EMode::PointSelection : EMode::FeatureSelection; - restore_scene_raycasters_state(); - } else if (action == SLAGizmoEventType::Delete) { m_selected_features.reset(); - m_selection_raycasters.clear(); + m_selected_sphere_raycasters.clear(); m_parent.request_extra_frame(); } else if (action == SLAGizmoEventType::Escape) { if (!m_selected_features.first.feature.has_value()) return false; else { - if (m_selected_features.second.feature.has_value()) - m_selected_features.second.feature.reset(); - else - m_selected_features.first.feature.reset(); + if (m_selected_features.second.feature.has_value()) { + remove_selected_sphere_raycaster(SEL_SPHERE_2_ID); + m_selected_features.second.feature.reset(); + } + else { + remove_selected_sphere_raycaster(SEL_SPHERE_1_ID); + m_selected_features.first.feature.reset(); + } } } @@ -503,7 +544,6 @@ void GLGizmoMeasure::on_set_state() { if (m_state == Off) { m_parent.toggle_sla_auxiliaries_visibility(true, nullptr, -1); - m_ctrl_kar_filter.reset_count(); m_shift_kar_filter.reset_count(); m_curr_feature.reset(); m_curr_point_on_feature_position.reset(); @@ -566,7 +606,7 @@ void GLGizmoMeasure::on_render() Vec3f normal_on_model; size_t model_facet_idx; const bool mouse_on_object = m_raycaster->unproject_on_mesh(m_mouse_pos, Transform3d::Identity(), camera, position_on_model, normal_on_model, nullptr, &model_facet_idx); - const bool is_hovering_on_feature = (m_mode == EMode::PointSelection || m_mode == EMode::CenterSelection) && m_hover_id != -1; + const bool is_hovering_on_feature = m_mode == EMode::PointSelection && m_hover_id != -1; auto update_circle = [this, inv_zoom]() { if (m_last_inv_zoom != inv_zoom || m_last_circle != m_curr_feature) { @@ -583,14 +623,13 @@ void GLGizmoMeasure::on_render() }; if (m_mode == EMode::FeatureSelection || m_mode == EMode::PointSelection) { - if ((m_hover_id == SELECTION_1_ID && boost::algorithm::istarts_with(m_selected_features.first.source, _u8L("Center"))) || - (m_hover_id == SELECTION_2_ID && boost::algorithm::istarts_with(m_selected_features.second.source, _u8L("Center")))) { - // Skip feature detection if hovering on a selected center - m_curr_feature.reset(); + if (m_hover_id == SEL_SPHERE_1_ID || m_hover_id == SEL_SPHERE_2_ID) { + // Skip feature detection if hovering on a selected point/center m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, POINT_ID); m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, EDGE_ID); m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, PLANE_ID); m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_ID); + m_curr_feature.reset(); m_curr_point_on_feature_position.reset(); } else { @@ -618,15 +657,12 @@ void GLGizmoMeasure::on_render() case Measure::SurfaceFeatureType::Edge: { m_raycasters.insert({ EDGE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, EDGE_ID, *m_cylinder.mesh_raycaster) }); - if (m_curr_feature->get_extra_point().has_value()) - m_raycasters.insert({ POINT_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, POINT_ID, *m_sphere.mesh_raycaster) }); break; } case Measure::SurfaceFeatureType::Circle: { update_circle(); m_raycasters.insert({ CIRCLE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_ID, *m_circle.mesh_raycaster) }); - m_raycasters.insert({ POINT_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, POINT_ID, *m_sphere.mesh_raycaster) }); break; } case Measure::SurfaceFeatureType::Plane: @@ -781,72 +817,69 @@ void GLGizmoMeasure::on_render() case Measure::SurfaceFeatureType::Circle: { const auto& [center, radius, normal] = feature.get_circle(); - // render center + // render circle + const Transform3d circle_matrix = Transform3d::Identity(); + set_matrix_uniforms(circle_matrix); if (update_raycasters_transform) { + set_emission_uniform(colors.front(), hover); + m_circle.model.set_color(colors.front()); + m_circle.model.render(); + auto it = m_raycasters.find(CIRCLE_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(circle_matrix); + } + else { + GLModel circle; + GLModel::Geometry circle_geometry = init_torus_data(64, 16, center.cast(), float(radius), 5.0f * inv_zoom, normal.cast(), Transform3f::Identity()); + circle.init_from(std::move(circle_geometry)); + set_emission_uniform(colors.front(), hover); + circle.set_color(colors.front()); + circle.render(); + } + // render center + if (colors.size() > 1) { const Transform3d center_matrix = Geometry::translation_transform(center) * Geometry::scale_transform(inv_zoom); set_matrix_uniforms(center_matrix); - set_emission_uniform(colors.front(), hover); - m_sphere.model.set_color(colors.front()); + set_emission_uniform(colors.back(), hover); + m_sphere.model.set_color(colors.back()); m_sphere.model.render(); auto it = m_raycasters.find(POINT_ID); if (it != m_raycasters.end() && it->second != nullptr) it->second->set_transform(center_matrix); } - // render circle - if (m_mode != EMode::CenterSelection) { - const Transform3d circle_matrix = Transform3d::Identity(); - set_matrix_uniforms(circle_matrix); - if (update_raycasters_transform) { - set_emission_uniform(colors.back(), hover); - m_circle.model.set_color(colors.back()); - m_circle.model.render(); - auto it = m_raycasters.find(CIRCLE_ID); - if (it != m_raycasters.end() && it->second != nullptr) - it->second->set_transform(circle_matrix); - } - else { - GLModel circle; - GLModel::Geometry circle_geometry = init_torus_data(64, 16, center.cast(), float(radius), 5.0f * inv_zoom, normal.cast(), Transform3f::Identity()); - circle.init_from(std::move(circle_geometry)); - set_emission_uniform(colors.back(), hover); - circle.set_color(colors.back()); - circle.render(); - } - } break; } case Measure::SurfaceFeatureType::Edge: { const auto& [from, to] = feature.get_edge(); - // render extra point + // render edge + const Transform3d edge_matrix = Geometry::translation_transform(from) * + Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), to - from) * + Geometry::scale_transform({ (double)inv_zoom, (double)inv_zoom, (to - from).norm() }); + set_matrix_uniforms(edge_matrix); + set_emission_uniform(colors.front(), hover); + m_cylinder.model.set_color(colors.front()); + m_cylinder.model.render(); if (update_raycasters_transform) { + auto it = m_raycasters.find(EDGE_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(edge_matrix); + } + + // render extra point + if (colors.size() > 1) { const std::optional extra = feature.get_extra_point(); if (extra.has_value()) { const Transform3d point_matrix = Geometry::translation_transform(*extra) * Geometry::scale_transform(inv_zoom); set_matrix_uniforms(point_matrix); - set_emission_uniform(colors.front(), hover); - m_sphere.model.set_color(colors.front()); + set_emission_uniform(colors.back(), hover); + m_sphere.model.set_color(colors.back()); m_sphere.model.render(); auto it = m_raycasters.find(POINT_ID); if (it != m_raycasters.end() && it->second != nullptr) it->second->set_transform(point_matrix); } } - // render edge - if (m_mode != EMode::CenterSelection) { - const Transform3d edge_matrix = Geometry::translation_transform(from) * - Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), to - from) * - Geometry::scale_transform({ (double)inv_zoom, (double)inv_zoom, (to - from).norm() }); - set_matrix_uniforms(edge_matrix); - set_emission_uniform(colors.back(), hover); - m_cylinder.model.set_color(colors.back()); - m_cylinder.model.render(); - if (update_raycasters_transform) { - auto it = m_raycasters.find(EDGE_ID); - if (it != m_raycasters.end() && it->second != nullptr) - it->second->set_transform(edge_matrix); - } - } break; } case Measure::SurfaceFeatureType::Plane: @@ -878,11 +911,31 @@ void GLGizmoMeasure::on_render() }; if (m_curr_feature.has_value()) { + // render hovered feature + std::vector colors; - if (m_selected_features.first.feature.has_value() && *m_curr_feature == *m_selected_features.first.feature) - colors.emplace_back(hovering_color()); - else if (m_selected_features.second.feature.has_value() && *m_curr_feature == *m_selected_features.second.feature) - colors.emplace_back(hovering_color()); + if (m_selected_features.first.feature.has_value() && *m_curr_feature == *m_selected_features.first.feature) { + // hovering over the 1st selected feature + if (m_selected_features.first.is_center) + // hovering over a center + colors = { NEUTRAL_COLOR, hovering_color() }; + else if (is_feature_with_center(*m_selected_features.first.feature)) + // hovering over a feature with center + colors = { hovering_color(), NEUTRAL_COLOR }; + else + colors = { hovering_color() }; + } + else if (m_selected_features.second.feature.has_value() && *m_curr_feature == *m_selected_features.second.feature) { + // hovering over the 2nd selected feature + if (m_selected_features.second.is_center) + // hovering over a center + colors = { NEUTRAL_COLOR, hovering_color() }; + else if (is_feature_with_center(*m_selected_features.second.feature)) + // hovering over a feature with center + colors = { hovering_color(), NEUTRAL_COLOR }; + else + colors = { hovering_color() }; + } else { switch (m_curr_feature->get_type()) { @@ -895,8 +948,12 @@ void GLGizmoMeasure::on_render() case Measure::SurfaceFeatureType::Edge: case Measure::SurfaceFeatureType::Circle: { - colors.emplace_back((m_hover_id == POINT_ID) ? hover_selection_color() : hovering_color()); - colors.emplace_back(hovering_color()); + if (m_selected_features.first.is_center && m_curr_feature == m_selected_features.first.source) + colors = { SELECTED_1ST_COLOR, NEUTRAL_COLOR }; + else if (m_selected_features.second.is_center && m_curr_feature == m_selected_features.second.source) + colors = { SELECTED_2ND_COLOR, NEUTRAL_COLOR }; + else + colors = { hovering_color(), hovering_color() }; break; } case Measure::SurfaceFeatureType::Plane: @@ -911,28 +968,76 @@ void GLGizmoMeasure::on_render() } if (m_selected_features.first.feature.has_value() && (!m_curr_feature.has_value() || *m_curr_feature != *m_selected_features.first.feature)) { - const std::vector colors = { SELECTED_1ST_COLOR }; - render_feature(*m_selected_features.first.feature, colors, inv_zoom, m_hover_id == SELECTION_1_ID, false); - if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Point) { - auto it = std::find_if(m_selection_raycasters.begin(), m_selection_raycasters.end(), - [](std::shared_ptr item) { return SceneRaycaster::decode_id(SceneRaycaster::EType::Gizmo, item->get_id()) == SELECTION_1_ID; }); - if (it != m_selection_raycasters.end()) - (*it)->set_transform(Geometry::translation_transform(m_selected_features.first.feature->get_point()) * Geometry::scale_transform(inv_zoom)); + // render 1st selected feature + + std::optional feature_to_render; + std::vector colors; + bool requires_raycaster_update = false; + if (m_hover_id == SEL_SPHERE_1_ID && (m_selected_features.first.is_center || is_feature_with_center(*m_selected_features.first.feature))) { + // hovering over a center + feature_to_render = m_selected_features.first.source; + colors = { NEUTRAL_COLOR, SELECTED_1ST_COLOR }; + requires_raycaster_update = true; + } + else if (is_feature_with_center(*m_selected_features.first.feature)) { + // hovering over a feature with center + feature_to_render = m_selected_features.first.feature; + colors = { SELECTED_1ST_COLOR, NEUTRAL_COLOR }; + requires_raycaster_update = true; + } + else { + feature_to_render = m_selected_features.first.feature; + colors = { SELECTED_1ST_COLOR }; + requires_raycaster_update = m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Point; + } + + render_feature(*feature_to_render, colors, inv_zoom, m_hover_id == SEL_SPHERE_1_ID, false); + + if (requires_raycaster_update) { + auto it = std::find_if(m_selected_sphere_raycasters.begin(), m_selected_sphere_raycasters.end(), + [](std::shared_ptr item) { return SceneRaycaster::decode_id(SceneRaycaster::EType::Gizmo, item->get_id()) == SEL_SPHERE_1_ID; }); + if (it != m_selected_sphere_raycasters.end()) + (*it)->set_transform(Geometry::translation_transform(get_feature_offset(*m_selected_features.first.feature)) * Geometry::scale_transform(inv_zoom)); } } + if (m_selected_features.second.feature.has_value() && (!m_curr_feature.has_value() || *m_curr_feature != *m_selected_features.second.feature)) { - const std::vector colors = { SELECTED_2ND_COLOR }; - render_feature(*m_selected_features.second.feature, colors, inv_zoom, m_hover_id == SELECTION_2_ID, false); - if (m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Point) { - auto it = std::find_if(m_selection_raycasters.begin(), m_selection_raycasters.end(), - [](std::shared_ptr item) { return SceneRaycaster::decode_id(SceneRaycaster::EType::Gizmo, item->get_id()) == SELECTION_2_ID; }); - if (it != m_selection_raycasters.end()) - (*it)->set_transform(Geometry::translation_transform(m_selected_features.second.feature->get_point()) * Geometry::scale_transform(inv_zoom)); + // render 2nd selected feature + + std::optional feature_to_render; + std::vector colors; + bool requires_raycaster_update = false; + if (m_hover_id == SEL_SPHERE_2_ID && (m_selected_features.second.is_center || is_feature_with_center(*m_selected_features.second.feature))) { + // hovering over a center + feature_to_render = m_selected_features.second.source; + colors = { NEUTRAL_COLOR, SELECTED_2ND_COLOR }; + requires_raycaster_update = true; + } + else if (is_feature_with_center(*m_selected_features.second.feature)) { + // hovering over a feature with center + feature_to_render = m_selected_features.second.feature; + colors = { SELECTED_2ND_COLOR, NEUTRAL_COLOR }; + requires_raycaster_update = true; + } + else { + feature_to_render = m_selected_features.second.feature; + colors = { SELECTED_2ND_COLOR }; + requires_raycaster_update = m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Point; + } + + render_feature(*feature_to_render, colors, inv_zoom, m_hover_id == SEL_SPHERE_2_ID, false); + + if (requires_raycaster_update) { + auto it = std::find_if(m_selected_sphere_raycasters.begin(), m_selected_sphere_raycasters.end(), + [](std::shared_ptr item) { return SceneRaycaster::decode_id(SceneRaycaster::EType::Gizmo, item->get_id()) == SEL_SPHERE_2_ID; }); + if (it != m_selected_sphere_raycasters.end()) + (*it)->set_transform(Geometry::translation_transform(get_feature_offset(*m_selected_features.second.feature)) * Geometry::scale_transform(inv_zoom)); } } if (is_hovering_on_feature && m_curr_point_on_feature_position.has_value()) { if (m_hover_id != POINT_ID) { + // render point on feature while SHIFT is pressed const Transform3d matrix = Geometry::translation_transform(*m_curr_point_on_feature_position) * Geometry::scale_transform(inv_zoom); set_matrix_uniforms(matrix); const ColorRGBA color = hover_selection_color(); @@ -1597,7 +1702,8 @@ static void add_strings_row_to_table(ImGuiWrapper& imgui, const std::string& col void GLGizmoMeasure::render_debug_dialog() { auto add_feature_data = [this](const SelectedFeatures::Item& item) { - add_strings_row_to_table(*m_imgui, "Type", ImGuiWrapper::COL_ORANGE_LIGHT, item.source, ImGui::GetStyleColorVec4(ImGuiCol_Text)); + const std::string text = (item.source == item.feature) ? surface_feature_type_as_string(item.feature->get_type()) : point_on_feature_type_as_string(item.source->get_type(), m_hover_id); + add_strings_row_to_table(*m_imgui, "Type", ImGuiWrapper::COL_ORANGE_LIGHT, text, ImGui::GetStyleColorVec4(ImGuiCol_Text)); switch (item.feature->get_type()) { case Measure::SurfaceFeatureType::Point: @@ -1643,7 +1749,6 @@ void GLGizmoMeasure::render_debug_dialog() { case EMode::FeatureSelection: { txt = "Feature selection"; break; } case EMode::PointSelection: { txt = "Point selection"; break; } - case EMode::CenterSelection: { txt = "Center selection"; break; } default: { assert(false); break; } } add_strings_row_to_table(*m_imgui, "Mode", ImGuiWrapper::COL_ORANGE_LIGHT, txt, ImGui::GetStyleColorVec4(ImGuiCol_Text)); @@ -1727,17 +1832,16 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit text = _u8L("Unselect feature"); color = SELECTED_2ND_COLOR; } - else if (m_hover_id == SELECTION_1_ID) { - text = (m_mode == EMode::CenterSelection) ? _u8L("Unselect center") : _u8L("Unselect point"); + else if (m_hover_id == SEL_SPHERE_1_ID) { + text = _u8L("Unselect point"); color = SELECTED_1ST_COLOR; } - else if (m_hover_id == SELECTION_2_ID) { - text = (m_mode == EMode::CenterSelection) ? _u8L("Unselect center") : _u8L("Unselect point"); + else if (m_hover_id == SEL_SPHERE_2_ID) { + text = _u8L("Unselect point"); color = SELECTED_2ND_COLOR; } else { - text = (m_mode == EMode::PointSelection) ? _u8L("Select point") : - (m_mode == EMode::CenterSelection) ? _u8L("Select center") : _u8L("Select feature"); + text = (m_mode == EMode::PointSelection) ? _u8L("Select point") : _u8L("Select feature"); color = SELECTED_2ND_COLOR; } } @@ -1747,14 +1851,13 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit text = _u8L("Unselect feature"); color = SELECTED_1ST_COLOR; } - else if (m_hover_id == SELECTION_1_ID) { - text = (m_mode == EMode::CenterSelection) ? _u8L("Unselect center") : _u8L("Unselect point"); + else if (m_hover_id == SEL_SPHERE_1_ID) { + text = _u8L("Unselect point"); color = SELECTED_1ST_COLOR; } } if (text.empty()) { - text = (m_mode == EMode::PointSelection) ? _u8L("Select point") : - (m_mode == EMode::CenterSelection) ? _u8L("Select center") : _u8L("Select feature"); + text = (m_mode == EMode::PointSelection) ? _u8L("Select point") : _u8L("Select feature"); color = m_selected_features.first.feature.has_value() ? SELECTED_2ND_COLOR : SELECTED_1ST_COLOR; } } @@ -1773,11 +1876,6 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit ++row_count; } - if (m_mode != EMode::CenterSelection && feature_has_center(m_curr_feature)) { - add_strings_row_to_table(*m_imgui, _u8L("Shift") + "+" + CTRL_STR, ImGuiWrapper::COL_ORANGE_LIGHT, _u8L("Enable center selection"), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - ++row_count; - } - if (m_selected_features.first.feature.has_value()) { add_strings_row_to_table(*m_imgui, _u8L("Delete"), ImGuiWrapper::COL_ORANGE_LIGHT, _u8L("Restart selection"), ImGui::GetStyleColorVec4(ImGuiCol_Text)); ++row_count; @@ -1803,7 +1901,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit } // add dummy rows to keep dialog size fixed - for (unsigned int i = row_count; i < 5; ++i) { + for (unsigned int i = row_count; i < 4; ++i) { add_strings_row_to_table(*m_imgui, " ", ImGuiWrapper::COL_ORANGE_LIGHT, " ", ImGui::GetStyleColorVec4(ImGuiCol_Text)); } @@ -1816,17 +1914,20 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit ImGui::Separator(); const ImGuiTableFlags flags = ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersH; if (ImGui::BeginTable("Selection", 2, flags)) { - auto format_item_text = [use_inches, &units](const SelectedFeatures::Item& item) { - std::string txt = item.feature.has_value() ? item.source : _u8L("None"); - if (item.feature.has_value() && item.feature->get_type() == Measure::SurfaceFeatureType::Circle) { - auto [center, radius, normal] = item.feature->get_circle(); - const Vec3d on_circle = center + radius * Measure::get_orthogonal(normal, true); - radius = (on_circle - center).norm(); - if (use_inches) - radius = ObjectManipulation::mm_to_in * radius; - txt += " (" + _u8L("Diameter:") + " " + format_double(2.0 * radius) + units + ")"; - } - return txt; + auto format_item_text = [this, use_inches, &units](const SelectedFeatures::Item& item) { + if (!item.feature.has_value()) + return _u8L("None"); + + std::string text = (item.source == item.feature) ? surface_feature_type_as_string(item.feature->get_type()) : point_on_feature_type_as_string(item.source->get_type(), m_hover_id); + if (item.feature.has_value() && item.feature->get_type() == Measure::SurfaceFeatureType::Circle) { + auto [center, radius, normal] = item.feature->get_circle(); + const Vec3d on_circle = center + radius * Measure::get_orthogonal(normal, true); + radius = (on_circle - center).norm(); + if (use_inches) + radius = ObjectManipulation::mm_to_in * radius; + text += " (" + _u8L("Diameter:") + " " + format_double(2.0 * radius) + units + ")"; + } + return text; }; add_strings_row_to_table(*m_imgui, _u8L("Selection") + " 1:", ImGuiWrapper::to_ImVec4(SELECTED_1ST_COLOR), format_item_text(m_selected_features.first), @@ -1839,7 +1940,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit m_imgui->disabled_begin(!m_selected_features.first.feature.has_value()); if (m_imgui->button(_u8L("Restart selection"))) { m_selected_features.reset(); - m_selection_raycasters.clear(); + m_selected_sphere_raycasters.clear(); m_imgui->set_requires_extra_frame(); } m_imgui->disabled_end(); @@ -1935,7 +2036,16 @@ void GLGizmoMeasure::on_unregister_raycasters_for_picking() m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo); m_parent.set_raycaster_gizmos_on_top(false); m_raycasters.clear(); - m_selection_raycasters.clear(); + m_selected_sphere_raycasters.clear(); +} + +void GLGizmoMeasure::remove_selected_sphere_raycaster(int id) +{ + auto it = std::find_if(m_selected_sphere_raycasters.begin(), m_selected_sphere_raycasters.end(), + [id](std::shared_ptr item) { return SceneRaycaster::decode_id(SceneRaycaster::EType::Gizmo, item->get_id()) == id; }); + if (it != m_selected_sphere_raycasters.end()) + m_selected_sphere_raycasters.erase(it); + m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, id); } } // namespace GUI diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 1672e8b74e..1e4330e955 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -24,20 +24,19 @@ class GLGizmoMeasure : public GLGizmoBase enum class EMode : unsigned char { FeatureSelection, - PointSelection, - CenterSelection + PointSelection }; struct SelectedFeatures { struct Item { - std::string source; + bool is_center{ false }; + std::optional source; std::optional feature; bool operator == (const Item& other) const { - if (this->source != other.source) return false; - return this->feature == other.feature; + return this->is_center == other.is_center && this->source == other.source && this->feature == other.feature; } bool operator != (const Item& other) const { @@ -45,7 +44,8 @@ class GLGizmoMeasure : public GLGizmoBase } void reset() { - source.clear(); + is_center = false; + source.reset(); feature.reset(); } }; @@ -106,7 +106,8 @@ class GLGizmoMeasure : public GLGizmoBase std::vector m_plane_models_cache; std::map> m_raycasters; - std::vector> m_selection_raycasters; + // 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; struct SceneRaycasterState @@ -126,7 +127,6 @@ class GLGizmoMeasure : public GLGizmoBase Vec2d m_mouse_pos{ Vec2d::Zero() }; - KeyAutoRepeatFilter m_ctrl_kar_filter; KeyAutoRepeatFilter m_shift_kar_filter; SelectedFeatures m_selected_features; @@ -174,6 +174,8 @@ protected: virtual void on_render_input_window(float x, float y, float bottom_limit) override; virtual void on_register_raycasters_for_picking() override; virtual void on_unregister_raycasters_for_picking() override; + + void remove_selected_sphere_raycaster(int id); }; } // namespace GUI From b3db407327ba5318ad5665de00489f93b20bff1a Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 30 Nov 2022 12:51:37 +0100 Subject: [PATCH 35/89] Gizmo measure - Show radius of single selected circle, to allow for object scaling --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 105 ++++++++++++++--------- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 1 + 2 files changed, 67 insertions(+), 39 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index eb1a7162eb..04c257e78a 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -422,8 +422,7 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) m_selected_sphere_raycasters.push_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, SEL_SPHERE_1_ID, *m_sphere.mesh_raycaster)); } - if (m_selected_features != selected_features_old && m_selected_features.second.feature.has_value()) - m_measurement_result = Measure::get_measurement(*m_selected_features.first.feature, *m_selected_features.second.feature, m_measuring.get()); + update_measurement_result(); m_imgui->set_requires_extra_frame(); @@ -469,7 +468,7 @@ void GLGizmoMeasure::data_changed() m_last_inv_zoom = 0.0f; m_last_plane_idx = -1; if (m_pending_scale) { - m_measurement_result = Measure::get_measurement(*m_selected_features.first.feature, *m_selected_features.second.feature, m_measuring.get()); + update_measurement_result(); m_pending_scale = false; } else @@ -517,8 +516,10 @@ bool GLGizmoMeasure::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_po m_parent.request_extra_frame(); } else if (action == SLAGizmoEventType::Escape) { - if (!m_selected_features.first.feature.has_value()) + if (!m_selected_features.first.feature.has_value()) { + update_measurement_result(); return false; + } else { if (m_selected_features.second.feature.has_value()) { remove_selected_sphere_raycaster(SEL_SPHERE_2_ID); @@ -528,6 +529,8 @@ bool GLGizmoMeasure::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_po remove_selected_sphere_raycaster(SEL_SPHERE_1_ID); m_selected_features.first.feature.reset(); } + + update_measurement_result(); } } @@ -1132,7 +1135,10 @@ void GLGizmoMeasure::render_dimensioning() { static SelectedFeatures last_selected_features; - if (!m_selected_features.first.feature.has_value() || !m_selected_features.second.feature.has_value()) + if (!m_selected_features.first.feature.has_value()) + return; + + if (!m_selected_features.second.feature.has_value() && m_selected_features.first.feature->get_type() != Measure::SurfaceFeatureType::Circle) return; GLShaderProgram* shader = wxGetApp().get_shader("flat"); @@ -1340,7 +1346,8 @@ void GLGizmoMeasure::render_dimensioning() const Vec3d new_center = selection.get_bounding_box().center(); const TrafoData trafo_data(ratio, old_center, new_center); scale_feature(*m_selected_features.first.feature, trafo_data); - scale_feature(*m_selected_features.second.feature, trafo_data); + if (m_selected_features.second.feature.has_value()) + scale_feature(*m_selected_features.second.feature, trafo_data); // update measure on next call to data_changed() m_pending_scale = true; @@ -1643,41 +1650,51 @@ void GLGizmoMeasure::render_dimensioning() glsafe(::glDisable(GL_DEPTH_TEST)); - if (m_selected_features.second.feature.has_value()) { - const bool has_distance = m_measurement_result.has_distance_data(); + const bool has_distance = m_measurement_result.has_distance_data(); - const Measure::SurfaceFeature* f1 = &(*m_selected_features.first.feature); - const Measure::SurfaceFeature* f2 = &(*m_selected_features.second.feature); - Measure::SurfaceFeatureType ft1 = f1->get_type(); - Measure::SurfaceFeatureType ft2 = f2->get_type(); - - // Order features by type so following conditions are simple. - if (ft1 > ft2) { - std::swap(ft1, ft2); - std::swap(f1, f2); - } - - // If there is an angle to show, draw the arc: - if (ft1 == Measure::SurfaceFeatureType::Edge && ft2 == Measure::SurfaceFeatureType::Edge) - arc_edge_edge(*f1, *f2); - else if (ft1 == Measure::SurfaceFeatureType::Edge && ft2 == Measure::SurfaceFeatureType::Plane) - arc_edge_plane(*f1, *f2); - else if (ft1 == Measure::SurfaceFeatureType::Plane && ft2 == Measure::SurfaceFeatureType::Plane) - arc_plane_plane(*f1, *f2); - - if (has_distance){ - // Where needed, draw the extension of the edge to where the dist is measured: - if (ft1 == Measure::SurfaceFeatureType::Point && ft2 == Measure::SurfaceFeatureType::Edge) - point_edge(*f1, *f2); - - // Render the arrow between the points that the backend passed: - const Measure::DistAndPoints& dap = m_measurement_result.distance_infinite.has_value() - ? *m_measurement_result.distance_infinite - : *m_measurement_result.distance_strict; - point_point(dap.from, dap.to, dap.dist); - } + const Measure::SurfaceFeature* f1 = &(*m_selected_features.first.feature); + const Measure::SurfaceFeature* f2 = nullptr; + std::unique_ptr temp_feature; + if (m_selected_features.second.feature.has_value()) + f2 = &(*m_selected_features.second.feature); + else { + assert(m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Circle); + temp_feature = std::make_unique(std::get<0>(m_selected_features.first.feature->get_circle())); + f2 = temp_feature.get(); } - + + if (!m_selected_features.second.feature.has_value() && m_selected_features.first.feature->get_type() != Measure::SurfaceFeatureType::Circle) + return; + + Measure::SurfaceFeatureType ft1 = f1->get_type(); + Measure::SurfaceFeatureType ft2 = f2->get_type(); + + // Order features by type so following conditions are simple. + if (ft1 > ft2) { + std::swap(ft1, ft2); + std::swap(f1, f2); + } + + // If there is an angle to show, draw the arc: + if (ft1 == Measure::SurfaceFeatureType::Edge && ft2 == Measure::SurfaceFeatureType::Edge) + arc_edge_edge(*f1, *f2); + else if (ft1 == Measure::SurfaceFeatureType::Edge && ft2 == Measure::SurfaceFeatureType::Plane) + arc_edge_plane(*f1, *f2); + else if (ft1 == Measure::SurfaceFeatureType::Plane && ft2 == Measure::SurfaceFeatureType::Plane) + arc_plane_plane(*f1, *f2); + + if (has_distance){ + // Where needed, draw the extension of the edge to where the dist is measured: + if (ft1 == Measure::SurfaceFeatureType::Point && ft2 == Measure::SurfaceFeatureType::Edge) + point_edge(*f1, *f2); + + // Render the arrow between the points that the backend passed: + const Measure::DistAndPoints& dap = m_measurement_result.distance_infinite.has_value() + ? *m_measurement_result.distance_infinite + : *m_measurement_result.distance_strict; + point_point(dap.from, dap.to, dap.dist); + } + glsafe(::glEnable(GL_DEPTH_TEST)); shader->stop_using(); @@ -2048,5 +2065,15 @@ void GLGizmoMeasure::remove_selected_sphere_raycaster(int id) m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, id); } +void GLGizmoMeasure::update_measurement_result() +{ + if (!m_selected_features.first.feature.has_value()) + m_measurement_result = Measure::MeasurementResult(); + else if (m_selected_features.second.feature.has_value()) + m_measurement_result = Measure::get_measurement(*m_selected_features.first.feature, *m_selected_features.second.feature, m_measuring.get()); + else if (!m_selected_features.second.feature.has_value() && m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Circle) + m_measurement_result = Measure::get_measurement(*m_selected_features.first.feature, Measure::SurfaceFeature(std::get<0>(m_selected_features.first.feature->get_circle())), m_measuring.get()); +} + } // namespace GUI } // namespace Slic3r diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 1e4330e955..4652a171b7 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -176,6 +176,7 @@ protected: virtual void on_unregister_raycasters_for_picking() override; void remove_selected_sphere_raycaster(int id); + void update_measurement_result(); }; } // namespace GUI From e6cbf3a215ff6f69e2e8b9060d182c06d180257d Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 30 Nov 2022 13:04:48 +0100 Subject: [PATCH 36/89] Fixed warnings --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 04c257e78a..6782d47f19 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -487,17 +487,6 @@ static bool feature_has_center(std::optional feature) bool GLGizmoMeasure::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down) { - auto activate_center_selection = [this, shift_down, control_down](SLAGizmoEventType action) { - bool ret = false; - switch (action) - { - case SLAGizmoEventType::CtrlDown: { ret = shift_down && feature_has_center(m_curr_feature); break; } - case SLAGizmoEventType::ShiftDown: { ret = control_down && feature_has_center(m_curr_feature); break; } - default: { break; } - } - return ret; - }; - if (action == SLAGizmoEventType::ShiftDown) { if (m_shift_kar_filter.is_first()) { m_mode = EMode::PointSelection; @@ -598,8 +587,6 @@ void GLGizmoMeasure::on_render() // if (m_parent.is_mouse_dragging()) // return; - const Selection& selection = m_parent.get_selection(); - update_if_needed(); const Camera& camera = wxGetApp().plater()->get_camera(); From 681216447fbe9d7fa6182e4c2cdf4427eb3a23ec Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 30 Nov 2022 13:07:49 +0100 Subject: [PATCH 37/89] Fixed warning --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 6782d47f19..4ce33f7cfe 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -310,7 +310,6 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) return false; if (m_hover_id != -1) { - SelectedFeatures selected_features_old = m_selected_features; m_mouse_left_down = true; auto detect_current_item = [this]() { From 85195ac79fb2b7016b05ffff5eb33a483a4d06c2 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Thu, 1 Dec 2022 12:47:06 +0100 Subject: [PATCH 38/89] Measure gizmo - Fixed sychronization of imgui dialog with current hovering/selection state --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 94 +++++++++++++++++++++--- 1 file changed, 82 insertions(+), 12 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 4ce33f7cfe..2b848bd985 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -1828,22 +1828,61 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit ColorRGBA color; if (m_selected_features.second.feature.has_value()) { if (m_selected_features.first.feature == m_curr_feature && m_mode == EMode::FeatureSelection) { + // hovering over 1st selected feature text = _u8L("Unselect feature"); color = SELECTED_1ST_COLOR; } + else if (m_hover_id == SEL_SPHERE_1_ID) { + if (m_selected_features.first.is_center) { + // hovering over center selected as 1st feature + text = _u8L("Unselect center"); + color = SELECTED_1ST_COLOR; + } + else if (is_feature_with_center(*m_selected_features.first.feature)) { + // hovering over center of 1st selected feature + text = _u8L("Select center"); + color = SELECTED_1ST_COLOR; + } + else { + // hovering over point selected as 1st feature + text = _u8L("Unselect point"); + color = SELECTED_1ST_COLOR; + } + } + else if (m_selected_features.first.is_center && m_selected_features.first.source == m_curr_feature) { + // hovering over feature whose center is selected as 1st feature + text = _u8L("Select feature"); + color = SELECTED_1ST_COLOR; + } else if (m_selected_features.second.feature == m_curr_feature && m_mode == EMode::FeatureSelection) { + // hovering over 2nd selected feature text = _u8L("Unselect feature"); color = SELECTED_2ND_COLOR; } - else if (m_hover_id == SEL_SPHERE_1_ID) { - text = _u8L("Unselect point"); - color = SELECTED_1ST_COLOR; - } else if (m_hover_id == SEL_SPHERE_2_ID) { - text = _u8L("Unselect point"); + if (m_selected_features.second.is_center) { + // hovering over center selected as 2nd feature + text = _u8L("Unselect feature"); + color = SELECTED_2ND_COLOR; + } + else if (is_feature_with_center(*m_selected_features.second.feature)) { + // hovering over center of 2nd selected feature + text = _u8L("Select center"); + color = SELECTED_2ND_COLOR; + } + else { + // hovering over point selected as 2nd feature + text = _u8L("Unselect point"); + color = SELECTED_2ND_COLOR; + } + } + else if (m_selected_features.second.is_center && m_selected_features.second.source == m_curr_feature) { + // hovering over feature whose center is selected as 2nd feature + text = _u8L("Select feature"); color = SELECTED_2ND_COLOR; } else { + // 1st feature selected text = (m_mode == EMode::PointSelection) ? _u8L("Select point") : _u8L("Select feature"); color = SELECTED_2ND_COLOR; } @@ -1851,20 +1890,51 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit else { if (m_selected_features.first.feature.has_value()) { if (m_selected_features.first.feature == m_curr_feature && m_mode == EMode::FeatureSelection) { + // hovering over 1st selected feature text = _u8L("Unselect feature"); color = SELECTED_1ST_COLOR; } - else if (m_hover_id == SEL_SPHERE_1_ID) { - text = _u8L("Unselect point"); - color = SELECTED_1ST_COLOR; + else { + if (m_hover_id == SEL_SPHERE_1_ID) { + if (m_selected_features.first.is_center) { + // hovering over center selected as 1st feature + text = _u8L("Unselect feature"); + color = SELECTED_1ST_COLOR; + } + else if (is_feature_with_center(*m_selected_features.first.feature)) { + // hovering over center of 1st selected feature + text = _u8L("Select center"); + color = SELECTED_1ST_COLOR; + } + else { + // hovering over point selected as 1st feature + text = _u8L("Unselect point"); + color = SELECTED_1ST_COLOR; + } + } + else { + if (m_selected_features.first.is_center && m_selected_features.first.source == m_curr_feature) { + // hovering over feature whose center is selected as 1st feature + text = _u8L("Select feature"); + color = SELECTED_1ST_COLOR; + } + else { + // 1st feature selected + text = (m_mode == EMode::PointSelection) ? _u8L("Select point") : _u8L("Select feature"); + color = SELECTED_2ND_COLOR; + } + } } } - if (text.empty()) { + else { + // nothing is selected text = (m_mode == EMode::PointSelection) ? _u8L("Select point") : _u8L("Select feature"); - color = m_selected_features.first.feature.has_value() ? SELECTED_2ND_COLOR : SELECTED_1ST_COLOR; + color = SELECTED_1ST_COLOR; } } + assert(!text.empty()); + m_imgui->text_colored(ImGui::GetStyleColorVec4(ImGuiCol_Text), text); ImGui::SameLine(); const ImVec2 pos = ImGui::GetCursorScreenPos(); @@ -1982,7 +2052,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit if (use_inches) distance = ObjectManipulation::mm_to_in * distance; ImGui::PushID("ClipboardDistanceInfinite"); - add_measure_row_to_table(_u8L("Distance Infinite"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(distance) + units, + add_measure_row_to_table(_u8L("Distance"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(distance) + units, ImGui::GetStyleColorVec4(ImGuiCol_Text)); ++measure_row_count; ImGui::PopID(); @@ -1993,7 +2063,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit if (use_inches) distance = ObjectManipulation::mm_to_in * distance; ImGui::PushID("ClipboardDistanceStrict"); - add_measure_row_to_table(_u8L("Distance Strict"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(distance) + units, + add_measure_row_to_table(_u8L("Distance"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(distance) + units, ImGui::GetStyleColorVec4(ImGuiCol_Text)); ++measure_row_count; ImGui::PopID(); From 1974a56fab76357a6752b106a8e0554b8de1a844 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Thu, 1 Dec 2022 13:31:22 +0100 Subject: [PATCH 39/89] Measurement: tweaking of the tolerances, ransacing the whole border --- src/libslic3r/Measure.cpp | 324 ++++++++++++++++++++------------------ 1 file changed, 175 insertions(+), 149 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index 5b9a75c045..76accc1f37 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -16,7 +16,7 @@ static std::pair get_center_and_radius(const std::vector& { Vec2ds out; double z = 0.; - for (const Vec3d pt : points) { + for (const Vec3d& pt : points) { Vec3d pt_transformed = trafo * pt; z = pt_transformed.z(); out.emplace_back(pt_transformed.x(), pt_transformed.y()); @@ -27,6 +27,14 @@ static std::pair get_center_and_radius(const std::vector& return std::make_pair(trafo.inverse() * Vec3d(circle.center.x(), circle.center.y(), z), circle.radius); } +static bool circle_fit_is_ok(const std::vector& pts, const Vec3d& center, double radius) +{ + for (const Vec3d& pt : pts) + if (std::abs((pt - center).norm() - radius) > 0.05) + return false; + return true; +} + static std::array orthonormal_basis(const Vec3d& v) { std::array ret; @@ -244,10 +252,7 @@ void MeasuringImpl::update_planes() void MeasuringImpl::extract_features() { - auto are_angles_same = [](double a, double b) { return Slic3r::is_approx(a,b); }; - auto are_lengths_same = [](double a, double b) { return Slic3r::is_approx(a,b); }; - - std::vector angles; + std::vector angles; // placed in outer scope to prevent reallocations std::vector lengths; @@ -265,175 +270,196 @@ void MeasuringImpl::extract_features() if (border.size() <= 1) continue; - // Given an idx into border, return the index that is idx+offset position, - // while taking into account the need for warp-around and the fact that - // the first and last point are the same. - auto offset_to_index = [border_size = int(border.size())](int idx, int offset) -> int { - assert(std::abs(offset) < border_size); - int out = idx+offset; - if (out >= border_size) - out = out - border_size; - else if (out < 0) - out = border_size + out; + bool done = false; - return out; - }; + if (const auto& [center, radius] = get_center_and_radius(border, trafo); + (border.size()>4) && circle_fit_is_ok(border, center, radius)) { + // The whole border is one circle. Just add it into the list of features + // and we are done. - // First calculate angles at all the vertices. - angles.clear(); - lengths.clear(); - int first_different_angle_idx = 0; - for (int i=0; i M_PI) - angle = 2*M_PI - angle; + bool is_polygon = border.size()>4 && border.size()<=8; + bool lengths_match = std::all_of(border.begin()+2, border.end(), [is_polygon](const Vec3d& pt) { + return Slic3r::is_approx((pt - *((&pt)-1)).squaredNorm(), (*((&pt)-1) - *((&pt)-2)).squaredNorm(), is_polygon ? 0.01 : 0.01); + }); - angles.push_back(angle); - lengths.push_back(v2.norm()); - if (first_different_angle_idx == 0 && angles.size() > 1) { - if (! are_angles_same(angles.back(), angles[angles.size()-2])) - first_different_angle_idx = angles.size()-1; + if (lengths_match && (is_polygon || border.size() > 8)) { + if (is_polygon) { + // This is a polygon, add the separate edges with the center. + for (int j=0; j circles; - std::vector edges; - std::vector> circles_idxs; - //std::vector circles_lengths; - std::vector single_circle; // could be in loop-scope, but reallocations - double single_circle_length = 0.; - int first_pt_idx = offset_to_index(first_different_angle_idx, 1); - int i = first_pt_idx; - while (i != first_pt_idx || first_iter) { - if (are_angles_same(angles[i], angles[offset_to_index(i,-1)]) - && i != offset_to_index(first_pt_idx, -1) // not the last point - && i != start_idx ) { - // circle - if (! circle) { - circle = true; - single_circle.clear(); - single_circle_length = 0.; - start_idx = offset_to_index(i, -2); - single_circle = { border[start_idx], border[offset_to_index(start_idx,1)] }; - single_circle_length += lengths[offset_to_index(i, -1)]; + if (! done) { + // In this case, the border is not a circle and may contain circular + // segments. Try to find them and then add all remaining edges as edges. + + auto are_angles_same = [](double a, double b) { return Slic3r::is_approx(a,b,0.01); }; + auto are_lengths_same = [](double a, double b) { return Slic3r::is_approx(a,b,0.01); }; + + + // Given an idx into border, return the index that is idx+offset position, + // while taking into account the need for wrap-around and the fact that + // the first and last point are the same. + auto offset_to_index = [border_size = int(border.size())](int idx, int offset) -> int { + assert(std::abs(offset) < border_size); + int out = idx+offset; + if (out >= border_size) + out = out - border_size; + else if (out < 0) + out = border_size + out; + + return out; + }; + + // First calculate angles at all the vertices. + angles.clear(); + lengths.clear(); + int first_different_angle_idx = 0; + for (int i=0; i M_PI) + angle = 2*M_PI - angle; + + angles.push_back(angle); + lengths.push_back(v2.norm()); + if (first_different_angle_idx == 0 && angles.size() > 1) { + if (! are_angles_same(angles.back(), angles[angles.size()-2])) + first_different_angle_idx = angles.size()-1; } - single_circle.emplace_back(border[i]); - single_circle_length += lengths[i]; - } else { - if (circle && single_circle.size() >= 5) { // Less than 5 vertices? Not a circle. + } + assert(border.size() == angles.size()); + assert(border.size() == lengths.size()); + + // First go around the border and pick what might be circular segments. + // Save pair of indices to where such potential segments start and end. + // Also remember the length of these segments. + int start_idx = -1; + bool circle = false; + bool first_iter = true; + std::vector circles; + std::vector edges; + std::vector> circles_idxs; + //std::vector circles_lengths; + std::vector single_circle; // could be in loop-scope, but reallocations + double single_circle_length = 0.; + int first_pt_idx = offset_to_index(first_different_angle_idx, 1); + int i = first_pt_idx; + while (i != first_pt_idx || first_iter) { + if (are_angles_same(angles[i], angles[offset_to_index(i,-1)]) + && i != offset_to_index(first_pt_idx, -1) // not the last point + && i != start_idx ) { + // circle + if (! circle) { + circle = true; + single_circle.clear(); + single_circle_length = 0.; + start_idx = offset_to_index(i, -2); + single_circle = { border[start_idx], border[offset_to_index(start_idx,1)] }; + single_circle_length += lengths[offset_to_index(i, -1)]; + } single_circle.emplace_back(border[i]); single_circle_length += lengths[i]; + } else { + if (circle && single_circle.size() >= 5) { // Less than 5 vertices? Not a circle. + single_circle.emplace_back(border[i]); + single_circle_length += lengths[i]; - bool accept_circle = true; - { - // Check that lengths of internal (!!!) edges match. - int j = offset_to_index(start_idx, 3); - while (j != i) { - if (! are_lengths_same(lengths[offset_to_index(j,-1)], lengths[j])) { - accept_circle = false; - break; - } - j = offset_to_index(j, 1); - } - } - - if (accept_circle) { - const auto& [center, radius] = get_center_and_radius(single_circle, trafo); - - // Check that the fit went well. The tolerance is high, only to - // reject complete failures. - for (const Vec3d& pt : single_circle) { - if (std::abs((pt - center).norm() - radius) > 0.5) { - accept_circle = false; - break; + bool accept_circle = true; + { + // Check that lengths of internal (!!!) edges match. + int j = offset_to_index(start_idx, 3); + while (j != i) { + if (! are_lengths_same(lengths[offset_to_index(j,-1)], lengths[j])) { + accept_circle = false; + break; + } + j = offset_to_index(j, 1); } } - // If the segment subtends less than 90 degrees, throw it away. - accept_circle &= single_circle_length / radius > 0.9*M_PI/2.; - - // If this is all-around and 5 to 8 vertices, consider it a polygon. - bool is_polygon = start_idx == i && single_circle.size() <= 9 && single_circle.size() >= 6; - if (accept_circle) { - // Add the circle and remember indices into borders. - circles_idxs.emplace_back(start_idx, i); - if (is_polygon) { - for (int j=0; j<=i; ++j) // No wrap-around handling needed here. - edges.emplace_back(SurfaceFeature(SurfaceFeatureType::Edge, - border[j==0 ? border.size()-1 : j-1], border[j], - std::make_optional(center))); - } - else + const auto& [center, radius] = get_center_and_radius(single_circle, trafo); + + // Check that the fit went well. The tolerance is high, only to + // reject complete failures. + accept_circle &= circle_fit_is_ok(single_circle, center, radius); + + // If the segment subtends less than 90 degrees, throw it away. + accept_circle &= single_circle_length / radius > 0.9*M_PI/2.; + + if (accept_circle) { + // Add the circle and remember indices into borders. + circles_idxs.emplace_back(start_idx, i); circles.emplace_back(SurfaceFeature(SurfaceFeatureType::Circle, center, plane.normal, std::nullopt, radius)); + } } } + circle = false; } - circle = false; - } - // Take care of the wrap around. - first_iter = false; - i = offset_to_index(i, 1); - } - - // We have the circles. Now go around again and pick edges, while jumping over circles. - if (circles_idxs.empty()) { - // Just add all edges. - for (int i=1; i 1 || circles_idxs.front().first != circles_idxs.front().second) { + // There is at least one circular segment. Start at its end and add edges until the start of the next one. + int i = circles_idxs.front().second; + int circle_idx = 1; + while (true) { + i = offset_to_index(i, 1); + edges.emplace_back(SurfaceFeature(SurfaceFeatureType::Edge, border[offset_to_index(i,-1)], border[i])); + if (circle_idx < int(circles_idxs.size()) && i == circles_idxs[circle_idx].first) { + i = circles_idxs[circle_idx].second; + ++circle_idx; + } + if (i == circles_idxs.front().first) + break; } - if (i == circles_idxs.front().first) - break; } - } - // Merge adjacent edges where needed. - assert(std::all_of(edges.begin(), edges.end(), - [](const SurfaceFeature& f) { return f.get_type() == SurfaceFeatureType::Edge; })); - for (int i=edges.size()-1; i>=0; --i) { - const auto& [first_start, first_end] = edges[i==0 ? edges.size()-1 : i-1].get_edge(); - const auto& [second_start, second_end] = edges[i].get_edge(); + // Merge adjacent edges where needed. + assert(std::all_of(edges.begin(), edges.end(), + [](const SurfaceFeature& f) { return f.get_type() == SurfaceFeatureType::Edge; })); + for (int i=edges.size()-1; i>=0; --i) { + const auto& [first_start, first_end] = edges[i==0 ? edges.size()-1 : i-1].get_edge(); + const auto& [second_start, second_end] = edges[i].get_edge(); - if (Slic3r::is_approx(first_end, second_start) - && Slic3r::is_approx((first_end-first_start).normalized().dot((second_end-second_start).normalized()), 1.)) { - // The edges have the same direction and share a point. Merge them. - edges[i==0 ? edges.size()-1 : i-1] = SurfaceFeature(SurfaceFeatureType::Edge, first_start, second_end); - edges.erase(edges.begin() + i); + if (Slic3r::is_approx(first_end, second_start) + && Slic3r::is_approx((first_end-first_start).normalized().dot((second_end-second_start).normalized()), 1.)) { + // The edges have the same direction and share a point. Merge them. + edges[i==0 ? edges.size()-1 : i-1] = SurfaceFeature(SurfaceFeatureType::Edge, first_start, second_end); + edges.erase(edges.begin() + i); + } } - } - // Now move the circles and edges into the feature list for the plane. - assert(std::all_of(circles.begin(), circles.end(), [](const SurfaceFeature& f) { - return f.get_type() == SurfaceFeatureType::Circle; - })); - assert(std::all_of(edges.begin(), edges.end(), [](const SurfaceFeature& f) { - return f.get_type() == SurfaceFeatureType::Edge; - })); - plane.surface_features.insert(plane.surface_features.end(), std::make_move_iterator(circles.begin()), - std::make_move_iterator(circles.end())); - plane.surface_features.insert(plane.surface_features.end(), std::make_move_iterator(edges.begin()), - std::make_move_iterator(edges.end())); + // Now move the circles and edges into the feature list for the plane. + assert(std::all_of(circles.begin(), circles.end(), [](const SurfaceFeature& f) { + return f.get_type() == SurfaceFeatureType::Circle; + })); + assert(std::all_of(edges.begin(), edges.end(), [](const SurfaceFeature& f) { + return f.get_type() == SurfaceFeatureType::Edge; + })); + plane.surface_features.insert(plane.surface_features.end(), std::make_move_iterator(circles.begin()), + std::make_move_iterator(circles.end())); + plane.surface_features.insert(plane.surface_features.end(), std::make_move_iterator(edges.begin()), + std::make_move_iterator(edges.end())); + } } // The last surface feature is the plane itself. From e0ba6c69f4a959e6e04cc1bfe1a0d6f81f46242c Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Thu, 1 Dec 2022 13:34:29 +0100 Subject: [PATCH 40/89] Fixed warnings --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 2b848bd985..a0ebc832c7 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -82,17 +82,6 @@ static std::string point_on_feature_type_as_string(Measure::SurfaceFeatureType t return ret; } -static std::string center_on_feature_type_as_string(Measure::SurfaceFeatureType type) -{ - std::string ret; - switch (type) { - case Measure::SurfaceFeatureType::Edge: { ret = _u8L("Center of edge"); break; } - case Measure::SurfaceFeatureType::Circle: { ret = _u8L("Center of circle"); break; } - default: { assert(false); break; } - } - return ret; -} - static GLModel::Geometry init_plane_data(const indexed_triangle_set& its, const std::vector>& planes_triangles, int idx) { assert(0 <= idx && idx < (int)planes_triangles.size()); @@ -477,13 +466,6 @@ void GLGizmoMeasure::data_changed() m_is_editing_distance_first_frame = true; } -static bool feature_has_center(std::optional feature) -{ - return feature.has_value() ? - (feature->get_type() == Measure::SurfaceFeatureType::Circle || (feature->get_type() == Measure::SurfaceFeatureType::Edge && feature->get_extra_point().has_value())) - : false; -} - bool GLGizmoMeasure::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down) { if (action == SLAGizmoEventType::ShiftDown) { From 048fb10c311e2492f8275ad7261fc9d4f5bbd197 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Thu, 1 Dec 2022 14:56:33 +0100 Subject: [PATCH 41/89] Measure gizmo - Fixed missing raycaster when promoting a point as 1st selected feature --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index a0ebc832c7..21955d5ccd 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -336,7 +336,7 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) }; auto requires_sphere_raycaster_for_picking = [this](const SelectedFeatures::Item& item) { - if (m_mode == EMode::PointSelection) + if (m_mode == EMode::PointSelection || item.feature->get_type() == Measure::SurfaceFeatureType::Point) return true; else if (m_mode == EMode::FeatureSelection) { if (is_feature_with_center(*item.feature)) From 8aa62b88f641b1e5b1ede0930f4ce298f654ab7e Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Fri, 2 Dec 2022 07:42:02 +0100 Subject: [PATCH 42/89] Measurement: Fixed edge detection on single-triangle planes --- src/libslic3r/Measure.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index 76accc1f37..919c55503e 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -225,7 +225,7 @@ void MeasuringImpl::update_planes() // In case of broken meshes, this loop might be infinite. Break // out in case it is clearly going bad. - if (last_border.size() > 3*facets.size()) + if (last_border.size() > 3*facets.size()+1) goto PLANE_FAILURE; } while (he != he_start); From 9964c47fbdd86a584a2c15998b73e9740f1abe07 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 2 Dec 2022 07:56:11 +0100 Subject: [PATCH 43/89] Follow-up of 85195ac79fb2b7016b05ffff5eb33a483a4d06c2 - Fixed synch of selected features in imgui dialog --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 21955d5ccd..a2d2518d6a 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -82,6 +82,17 @@ static std::string point_on_feature_type_as_string(Measure::SurfaceFeatureType t return ret; } +static std::string center_on_feature_type_as_string(Measure::SurfaceFeatureType type) +{ + std::string ret; + switch (type) { + case Measure::SurfaceFeatureType::Edge: { ret = _u8L("Center of edge"); break; } + case Measure::SurfaceFeatureType::Circle: { ret = _u8L("Center of circle"); break; } + default: { assert(false); break; } + } + return ret; +} + static GLModel::Geometry init_plane_data(const indexed_triangle_set& its, const std::vector>& planes_triangles, int idx) { assert(0 <= idx && idx < (int)planes_triangles.size()); @@ -1973,7 +1984,8 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit if (!item.feature.has_value()) return _u8L("None"); - std::string text = (item.source == item.feature) ? surface_feature_type_as_string(item.feature->get_type()) : point_on_feature_type_as_string(item.source->get_type(), m_hover_id); + std::string text = (item.source == item.feature) ? surface_feature_type_as_string(item.feature->get_type()) : + item.is_center ? center_on_feature_type_as_string(item.source->get_type()) : point_on_feature_type_as_string(item.source->get_type(), m_hover_id); if (item.feature.has_value() && item.feature->get_type() == Measure::SurfaceFeatureType::Circle) { auto [center, radius, normal] = item.feature->get_circle(); const Vec3d on_circle = center + radius * Measure::get_orthogonal(normal, true); From 33949734e330f9a2942d805d5c2c7c951faf0cb9 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 2 Dec 2022 09:11:50 +0100 Subject: [PATCH 44/89] Latest techs definition retargeted to 2.6 --- src/libslic3r/Technologies.hpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index c80689f48b..f707b0f21d 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -37,12 +37,12 @@ //==================== -// 2.5.0.alpha1 techs +// 2.6.0.alpha1 techs //==================== -#define ENABLE_2_5_0_ALPHA1 1 +#define ENABLE_2_6_0_ALPHA1 1 // Enable removal of legacy OpenGL calls -#define ENABLE_LEGACY_OPENGL_REMOVAL (1 && ENABLE_2_5_0_ALPHA1) +#define ENABLE_LEGACY_OPENGL_REMOVAL (1 && ENABLE_2_6_0_ALPHA1) // Enable OpenGL ES #define ENABLE_OPENGL_ES (0 && ENABLE_LEGACY_OPENGL_REMOVAL) // Enable OpenGL core profile context (tested against Mesa 20.1.8 on Windows) @@ -52,15 +52,15 @@ // Shows an imgui dialog with GLModel statistics data #define ENABLE_GLMODEL_STATISTICS (0 && ENABLE_LEGACY_OPENGL_REMOVAL) // Enable rework of Reload from disk command -#define ENABLE_RELOAD_FROM_DISK_REWORK (1 && ENABLE_2_5_0_ALPHA1) +#define ENABLE_RELOAD_FROM_DISK_REWORK (1 && ENABLE_2_6_0_ALPHA1) // Enable editing volumes transformation in world coordinates and instances in local coordinates -#define ENABLE_WORLD_COORDINATE (1 && ENABLE_2_5_0_ALPHA1) +#define ENABLE_WORLD_COORDINATE (1 && ENABLE_2_6_0_ALPHA1) // Enable alternative version of file_wildcards() -#define ENABLE_ALTERNATIVE_FILE_WILDCARDS_GENERATOR (1 && ENABLE_2_5_0_ALPHA1) +#define ENABLE_ALTERNATIVE_FILE_WILDCARDS_GENERATOR (1 && ENABLE_2_6_0_ALPHA1) // Enable processing of gcode G2 and G3 lines -#define ENABLE_PROCESS_G2_G3_LINES (1 && ENABLE_2_5_0_ALPHA1) +#define ENABLE_PROCESS_G2_G3_LINES (1 && ENABLE_2_6_0_ALPHA1) // Enable fix of used filament data exported to gcode file -#define ENABLE_USED_FILAMENT_POST_PROCESS (1 && ENABLE_2_5_0_ALPHA1) +#define ENABLE_USED_FILAMENT_POST_PROCESS (1 && ENABLE_2_6_0_ALPHA1) // Enable picking using raytracing #define ENABLE_RAYCAST_PICKING (1 && ENABLE_LEGACY_OPENGL_REMOVAL) #define ENABLE_RAYCAST_PICKING_DEBUG (0 && ENABLE_RAYCAST_PICKING) From fc2f0bad6e3e9ba08c65aacd52396cf6136e1df4 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 15 Nov 2022 12:17:18 +0100 Subject: [PATCH 45/89] Gizmo measure modified to accept single full instance selection, to combine the volumes meshes into a single mesh and pass it to the back end after transform it in world coordinates Changes embedded into tech ENABLE_GIZMO_MEASURE_WORLD_COORDINATES Fixed conflicts during rebase to master --- src/libslic3r/Measure.cpp | 37 ++++ src/libslic3r/Measure.hpp | 19 +- src/libslic3r/Technologies.hpp | 2 + src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 230 ++++++++++++++++++++++- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 35 ++++ src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp | 13 ++ src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp | 7 + src/slic3r/GUI/Selection.cpp | 13 ++ src/slic3r/GUI/Selection.hpp | 4 + 9 files changed, 347 insertions(+), 13 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index badb3b2c5f..9b930df9aa 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -47,6 +47,9 @@ public: std::optional get_feature(size_t face_idx, const Vec3d& point) const; std::vector> get_planes_triangle_indices() const; const std::vector& get_plane_features(unsigned int plane_id) const; +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + const TriangleMesh& get_mesh() const; +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES private: void update_planes(); @@ -54,7 +57,11 @@ private: std::vector m_planes; std::vector m_face_to_plane; +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + TriangleMesh m_mesh; +#else const indexed_triangle_set& m_its; +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES }; @@ -63,7 +70,11 @@ private: MeasuringImpl::MeasuringImpl(const indexed_triangle_set& its) +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES +: m_mesh(its) +#else : m_its{its} +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES { update_planes(); extract_features(); @@ -76,10 +87,17 @@ void MeasuringImpl::update_planes() // Now we'll go through all the facets and append Points of facets sharing the same normal. // This part is still performed in mesh coordinate system. +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + const size_t num_of_facets = m_mesh.its.indices.size(); + m_face_to_plane.resize(num_of_facets, size_t(-1)); + const std::vector face_normals = its_face_normals(m_mesh.its); + const std::vector face_neighbors = its_face_neighbors(m_mesh.its); +#else const size_t num_of_facets = m_its.indices.size(); m_face_to_plane.resize(num_of_facets, size_t(-1)); const std::vector face_normals = its_face_normals(m_its); const std::vector face_neighbors = its_face_neighbors(m_its); +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES std::vector facet_queue(num_of_facets, 0); int facet_queue_cnt = 0; const stl_normal* normal_ptr = nullptr; @@ -128,7 +146,11 @@ void MeasuringImpl::update_planes() assert(std::none_of(m_face_to_plane.begin(), m_face_to_plane.end(), [](size_t val) { return val == size_t(-1); })); // Now we will walk around each of the planes and save vertices which form the border. +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + SurfaceMesh sm(m_mesh.its); +#else SurfaceMesh sm(m_its); +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES for (int plane_id=0; plane_id < int(m_planes.size()); ++plane_id) { const auto& facets = m_planes[plane_id].facets; m_planes[plane_id].borders.clear(); @@ -510,6 +532,12 @@ const std::vector& MeasuringImpl::get_plane_features(unsigned in return m_planes[plane_id].surface_features; } +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES +const TriangleMesh& MeasuringImpl::get_mesh() const +{ + return this->m_mesh; +} +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES @@ -551,6 +579,13 @@ const std::vector& Measuring::get_plane_features(unsigned int pl return priv->get_plane_features(plane_id); } +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES +const TriangleMesh& Measuring::get_mesh() const +{ + return priv->get_mesh(); +} +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + const AngleAndEdges AngleAndEdges::Dummy = { 0.0, Vec3d::Zero(), { Vec3d::Zero(), Vec3d::Zero() }, { Vec3d::Zero(), Vec3d::Zero() }, 0.0, true }; static AngleAndEdges angle_edge_edge(const std::pair& e1, const std::pair& e2) @@ -1149,6 +1184,7 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& return result; } +#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES void DistAndPoints::transform(const Transform3d& trafo) { from = trafo * from; to = trafo * to; @@ -1169,6 +1205,7 @@ void AngleAndEdges::transform(const Transform3d& trafo) { const double average_scale = 0.5 * (new_e1.norm() / old_e1.norm() + new_e2.norm() / old_e2.norm()); radius = average_scale * radius; } +#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES diff --git a/src/libslic3r/Measure.hpp b/src/libslic3r/Measure.hpp index ede8c634ee..b2e2008d15 100644 --- a/src/libslic3r/Measure.hpp +++ b/src/libslic3r/Measure.hpp @@ -87,9 +87,11 @@ class MeasuringImpl; class Measuring { public: - // Construct the measurement object on a given its. The its must remain - // valid and unchanged during the whole lifetime of the object. - explicit Measuring(const indexed_triangle_set& its); + // Construct the measurement object on a given its. +#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + // The its must remain valid and unchanged during the whole lifetime of the object. +#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + explicit Measuring(const indexed_triangle_set& its); ~Measuring(); // Return a reference to a list of all features identified on the its. @@ -108,6 +110,11 @@ public: // Returns the surface features of the plane with the given index const std::vector& get_plane_features(unsigned int plane_id) const; +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + // Returns the mesh used for measuring + const TriangleMesh& get_mesh() const; +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + private: std::unique_ptr priv; }; @@ -119,7 +126,9 @@ struct DistAndPoints { Vec3d from; Vec3d to; +#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES void transform(const Transform3d& trafo); +#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES }; struct AngleAndEdges { @@ -132,7 +141,9 @@ struct AngleAndEdges { double radius; bool coplanar; +#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES void transform(const Transform3d& trafo); +#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES static const AngleAndEdges Dummy; }; @@ -151,6 +162,7 @@ struct MeasurementResult { return angle.has_value() || distance_infinite.has_value() || distance_strict.has_value() || distance_xyz.has_value(); } +#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES void transform(const Transform3d& trafo) { if (angle.has_value()) angle->transform(trafo); @@ -161,6 +173,7 @@ struct MeasurementResult { distance_xyz = (distance_strict->to - distance_strict->from).cwiseAbs(); } } +#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES }; // Returns distance/angle between two SurfaceFeatures. diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index f707b0f21d..759871c60d 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -64,6 +64,8 @@ // Enable picking using raytracing #define ENABLE_RAYCAST_PICKING (1 && ENABLE_LEGACY_OPENGL_REMOVAL) #define ENABLE_RAYCAST_PICKING_DEBUG (0 && ENABLE_RAYCAST_PICKING) +// Enable gizmo measure combining volumes meshes and passing them to the backend in world coordinates +#define ENABLE_GIZMO_MEASURE_WORLD_COORDINATES (1 && ENABLE_2_5_0_ALPHA1) #endif // _prusaslicer_technologies_h_ diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index a026ae2552..5ae906eac9 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -5,9 +5,11 @@ #include "slic3r/GUI/Plater.hpp" #include "slic3r/GUI/GUI_ObjectManipulation.hpp" -#include "slic3r/GUI/Gizmos/GLGizmosCommon.hpp" +#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES +#include "slic3r/GUI/Gizmos/GLGizmosCommon.hpp" #include "libslic3r/Model.hpp" +#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES #include "libslic3r/PresetBundle.hpp" #include "libslic3r/MeasureUtils.hpp" @@ -242,7 +244,10 @@ private: TransformHelper::Cache TransformHelper::s_cache = { { 0, 0, 0, 0 }, Matrix4d::Identity(), Transform3d::Identity() }; GLGizmoMeasure::GLGizmoMeasure(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) - : GLGizmoBase(parent, icon_filename, sprite_id) +: GLGizmoBase(parent, icon_filename, sprite_id) +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES +, m_raycaster(nullptr) +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES { GLModel::Geometry sphere_geometry = smooth_sphere(16, 7.5f); m_sphere.mesh_raycaster = std::make_unique(std::make_shared(sphere_geometry.get_as_indexed_triangle_set())); @@ -370,8 +375,10 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) if (m_selected_features != selected_features_old && m_selected_features.second.feature.has_value()) { m_measurement_result = Measure::get_measurement(*m_selected_features.first.feature, *m_selected_features.second.feature, m_measuring.get()); +#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES // transform to world coordinates m_measurement_result.transform(m_volume_matrix); +#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES } m_imgui->set_requires_extra_frame(); @@ -419,6 +426,9 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) void GLGizmoMeasure::data_changed() { +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + update_if_needed(); +#else const Selection& selection = m_parent.get_selection(); const ModelObject* model_object = nullptr; const ModelVolume* model_volume = nullptr; @@ -429,13 +439,16 @@ void GLGizmoMeasure::data_changed() } if (model_object != m_old_model_object || model_volume != m_old_model_volume) update_if_needed(); +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES m_last_inv_zoom = 0.0f; m_last_plane_idx = -1; if (m_pending_scale) { m_measurement_result = Measure::get_measurement(*m_selected_features.first.feature, *m_selected_features.second.feature, m_measuring.get()); +#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES // transform to world coordinates m_measurement_result.transform(m_volume_matrix); +#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES m_pending_scale = false; } else @@ -512,6 +525,9 @@ void GLGizmoMeasure::on_set_state() m_editing_distance = false; m_is_editing_distance_first_frame = true; m_measuring.reset(); +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + m_raycaster.release(); +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES } else { m_mode = EMode::FeatureSelection; @@ -528,10 +544,12 @@ void GLGizmoMeasure::on_set_state() } } +#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES CommonGizmosDataID GLGizmoMeasure::on_get_requirements() const { return CommonGizmosDataID(int(CommonGizmosDataID::SelectionInfo) | int(CommonGizmosDataID::Raycaster)); } +#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES std::string GLGizmoMeasure::on_get_name() const { @@ -543,9 +561,15 @@ bool GLGizmoMeasure::on_is_activable() const const Selection& selection = m_parent.get_selection(); bool res = (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA) ? selection.is_single_full_instance() : +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + selection.is_single_full_instance() || selection.is_single_volume() || selection.is_single_modifier(); + if (res) + res &= !selection.contains_sinking_volumes(); +#else selection.is_single_volume() || selection.is_single_volume_instance(); if (res) res &= !selection.get_first_volume()->is_sinking(); +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES return res; } @@ -562,8 +586,10 @@ void GLGizmoMeasure::on_render() const Selection& selection = m_parent.get_selection(); +#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES if ((wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA && selection.is_single_full_instance()) || (selection.is_single_volume() || selection.is_single_volume_instance())) { +#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES update_if_needed(); const Camera& camera = wxGetApp().plater()->get_camera(); @@ -572,7 +598,11 @@ void GLGizmoMeasure::on_render() Vec3f position_on_model; Vec3f normal_on_model; size_t model_facet_idx; +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + const bool mouse_on_object = m_raycaster.raycaster()->unproject_on_mesh(m_mouse_pos, Transform3d::Identity(), camera, position_on_model, normal_on_model, nullptr, &model_facet_idx); +#else const bool mouse_on_object = m_c->raycaster()->raycasters().front()->unproject_on_mesh(m_mouse_pos, m_volume_matrix, camera, position_on_model, normal_on_model, nullptr, &model_facet_idx); +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES const bool is_hovering_on_feature = (m_mode == EMode::PointSelection || m_mode == EMode::CenterSelection) && m_hover_id != -1; auto update_circle = [this, inv_zoom]() { @@ -581,7 +611,11 @@ void GLGizmoMeasure::on_render() m_last_circle = m_curr_feature; m_circle.reset(); const auto [center, radius, normal] = m_curr_feature->get_circle(); +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + GLModel::Geometry circle_geometry = init_torus_data(64, 16, center.cast(), float(radius), 5.0f * inv_zoom, normal.cast(), Transform3f::Identity()); +#else GLModel::Geometry circle_geometry = init_torus_data(64, 16, center.cast(), float(radius), 5.0f * inv_zoom, normal.cast(), m_volume_matrix.cast()); +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES m_circle.mesh_raycaster = std::make_unique(std::make_shared(circle_geometry.get_as_indexed_triangle_set())); m_circle.model.init_from(std::move(circle_geometry)); return true; @@ -639,7 +673,11 @@ void GLGizmoMeasure::on_render() const auto [idx, normal, point] = m_curr_feature->get_plane(); if (m_last_plane_idx != idx) { m_last_plane_idx = idx; +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + const indexed_triangle_set& its = m_measuring->get_mesh().its; +#else const indexed_triangle_set its = (m_old_model_volume != nullptr) ? m_old_model_volume->mesh().its : m_old_model_object->volumes.front()->mesh().its; +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES const std::vector> planes_triangles = m_measuring->get_planes_triangle_indices(); GLModel::Geometry init_data = init_plane_data(its, planes_triangles, idx); m_plane.reset(); @@ -689,12 +727,20 @@ void GLGizmoMeasure::on_render() if (extra.has_value() && m_hover_id == POINT_ID) m_curr_point_on_feature_position = *extra; else +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + m_curr_point_on_feature_position = position_on_feature(EDGE_ID, camera, [](const Vec3f& v) { return Vec3f(0.0f, 0.0f, v.z()); }); +#else m_curr_point_on_feature_position = m_volume_matrix.inverse() * position_on_feature(EDGE_ID, camera, [](const Vec3f& v) { return Vec3f(0.0f, 0.0f, v.z()); }); +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES break; } case Measure::SurfaceFeatureType::Plane: { +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + m_curr_point_on_feature_position = position_on_feature(PLANE_ID, camera); +#else m_curr_point_on_feature_position = m_volume_matrix.inverse() * position_on_feature(PLANE_ID, camera); +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES break; } case Measure::SurfaceFeatureType::Circle: @@ -704,9 +750,17 @@ void GLGizmoMeasure::on_render() m_curr_point_on_feature_position = center; else { const Vec3d world_pof = position_on_feature(CIRCLE_ID, camera, [](const Vec3f& v) { return v; }); +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + const Eigen::Hyperplane plane(normal, center); +#else const Eigen::Hyperplane plane(m_volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal, m_volume_matrix * center); +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES const Transform3d local_to_model_matrix = Geometry::translation_transform(center) * Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), normal); +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + const Vec3d local_proj = local_to_model_matrix.inverse() * plane.projection(world_pof); +#else const Vec3d local_proj = local_to_model_matrix.inverse() * m_volume_matrix.inverse() * plane.projection(world_pof); +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES double angle = std::atan2(local_proj.y(), local_proj.x()); if (angle < 0.0) angle += 2.0 * double(M_PI); @@ -767,8 +821,12 @@ void GLGizmoMeasure::on_render() default: { assert(false); break; } case Measure::SurfaceFeatureType::Point: { +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + const Transform3d feature_matrix = Geometry::translation_transform(feature.get_point()) * Geometry::scale_transform(inv_zoom); +#else const Vec3d position = TransformHelper::model_to_world(feature.get_point(), m_volume_matrix); const Transform3d feature_matrix = Geometry::translation_transform(position) * Geometry::scale_transform(inv_zoom); +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES set_matrix_uniforms(feature_matrix); set_emission_uniform(colors.front(), hover); m_sphere.model.set_color(colors.front()); @@ -785,8 +843,12 @@ void GLGizmoMeasure::on_render() const auto& [center, radius, normal] = feature.get_circle(); // render center if (update_raycasters_transform) { +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + const Transform3d center_matrix = Geometry::translation_transform(center) * Geometry::scale_transform(inv_zoom); +#else const Vec3d center_world = TransformHelper::model_to_world(center, m_volume_matrix); const Transform3d center_matrix = Geometry::translation_transform(center_world) * Geometry::scale_transform(inv_zoom); +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES set_matrix_uniforms(center_matrix); set_emission_uniform(colors.front(), hover); m_sphere.model.set_color(colors.front()); @@ -809,7 +871,11 @@ void GLGizmoMeasure::on_render() } else { GLModel circle; +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + GLModel::Geometry circle_geometry = init_torus_data(64, 16, center.cast(), float(radius), 5.0f * inv_zoom, normal.cast(), Transform3f::Identity()); +#else GLModel::Geometry circle_geometry = init_torus_data(64, 16, center.cast(), float(radius), 5.0f * inv_zoom, normal.cast(), m_volume_matrix.cast()); +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES circle.init_from(std::move(circle_geometry)); set_emission_uniform(colors.back(), hover); circle.set_color(colors.back()); @@ -825,8 +891,12 @@ void GLGizmoMeasure::on_render() if (update_raycasters_transform) { const std::optional extra = feature.get_extra_point(); if (extra.has_value()) { +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + const Transform3d point_matrix = Geometry::translation_transform(*extra) * Geometry::scale_transform(inv_zoom); +#else const Vec3d extra_world = TransformHelper::model_to_world(*extra, m_volume_matrix); const Transform3d point_matrix = Geometry::translation_transform(extra_world) * Geometry::scale_transform(inv_zoom); +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES set_matrix_uniforms(point_matrix); set_emission_uniform(colors.front(), hover); m_sphere.model.set_color(colors.front()); @@ -838,11 +908,17 @@ void GLGizmoMeasure::on_render() } // render edge if (m_mode != EMode::CenterSelection) { +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + const Transform3d edge_matrix = Geometry::translation_transform(from) * + Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), to - from) * + Geometry::scale_transform({ (double)inv_zoom, (double)inv_zoom, (to - from).norm() }); +#else const Vec3d from_world = TransformHelper::model_to_world(from, m_volume_matrix); const Vec3d to_world = TransformHelper::model_to_world(to, m_volume_matrix); const Transform3d edge_matrix = Geometry::translation_transform(from_world) * Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), to_world - from_world) * Geometry::scale_transform({ (double)inv_zoom, (double)inv_zoom, (to_world - from_world).norm() }); +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES set_matrix_uniforms(edge_matrix); set_emission_uniform(colors.back(), hover); m_cylinder.model.set_color(colors.back()); @@ -857,16 +933,27 @@ void GLGizmoMeasure::on_render() } case Measure::SurfaceFeatureType::Plane: { - const auto& [idx, normal, pt] = feature.get_plane(); - assert(idx < m_plane_models_cache.size()); - set_matrix_uniforms(m_volume_matrix); - set_emission_uniform(colors.front(), hover); - m_plane_models_cache[idx].set_color(colors.front()); - m_plane_models_cache[idx].render(); + // no need to render the plane in case it is rendered with the same color as the volume in the 3D scene + if (colors.front() != m_parent.get_selection().get_first_volume()->render_color) { + const auto& [idx, normal, pt] = feature.get_plane(); + assert(idx < m_plane_models_cache.size()); +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + set_matrix_uniforms(Transform3d::Identity()); +#else + set_matrix_uniforms(m_volume_matrix); +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + set_emission_uniform(colors.front(), hover); + m_plane_models_cache[idx].set_color(colors.front()); + m_plane_models_cache[idx].render(); + } if (update_raycasters_transform) { auto it = m_raycasters.find(PLANE_ID); if (it != m_raycasters.end() && it->second != nullptr) +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + it->second->set_transform(Transform3d::Identity()); +#else it->second->set_transform(m_volume_matrix); +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES } break; } @@ -921,7 +1008,11 @@ void GLGizmoMeasure::on_render() auto it = std::find_if(m_selection_raycasters.begin(), m_selection_raycasters.end(), [](std::shared_ptr item) { return SceneRaycaster::decode_id(SceneRaycaster::EType::Gizmo, item->get_id()) == SELECTION_1_ID; }); if (it != m_selection_raycasters.end()) +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + (*it)->set_transform(Geometry::translation_transform(m_selected_features.first.feature->get_point()) * Geometry::scale_transform(inv_zoom)); +#else (*it)->set_transform(m_volume_matrix * Geometry::translation_transform(m_selected_features.first.feature->get_point()) * Geometry::scale_transform(inv_zoom)); +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES } } if (m_selected_features.second.feature.has_value() && (!m_curr_feature.has_value() || *m_curr_feature != *m_selected_features.second.feature)) { @@ -931,14 +1022,22 @@ void GLGizmoMeasure::on_render() auto it = std::find_if(m_selection_raycasters.begin(), m_selection_raycasters.end(), [](std::shared_ptr item) { return SceneRaycaster::decode_id(SceneRaycaster::EType::Gizmo, item->get_id()) == SELECTION_2_ID; }); if (it != m_selection_raycasters.end()) +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + (*it)->set_transform(Geometry::translation_transform(m_selected_features.second.feature->get_point()) * Geometry::scale_transform(inv_zoom)); +#else (*it)->set_transform(m_volume_matrix * Geometry::translation_transform(m_selected_features.second.feature->get_point()) * Geometry::scale_transform(inv_zoom)); +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES } } if (is_hovering_on_feature && m_curr_point_on_feature_position.has_value()) { if (m_hover_id != POINT_ID) { +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + const Transform3d matrix = Geometry::translation_transform(*m_curr_point_on_feature_position) * Geometry::scale_transform(inv_zoom); +#else const Vec3d position = TransformHelper::model_to_world(*m_curr_point_on_feature_position, m_volume_matrix); const Transform3d matrix = Geometry::translation_transform(position) * Geometry::scale_transform(inv_zoom); +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES set_matrix_uniforms(matrix); const ColorRGBA color = hover_selection_color(); set_emission_uniform(color, true); @@ -951,7 +1050,9 @@ void GLGizmoMeasure::on_render() if (old_cullface) glsafe(::glEnable(GL_CULL_FACE)); +#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES } +#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES render_dimensioning(); } @@ -968,6 +1069,24 @@ void GLGizmoMeasure::update_if_needed() } }; +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + auto do_update = [this, update_plane_models_cache](const std::vector& volumes_cache, const Selection& selection) { + TriangleMesh composite_mesh; + for (const auto& vol : volumes_cache) { +// if (selection.is_single_full_instance() && vol.volume->is_modifier()) +// continue; + + TriangleMesh volume_mesh = vol.volume->mesh(); + volume_mesh.transform(vol.instance->get_transformation().get_matrix() * vol.volume->get_transformation().get_matrix()); + composite_mesh.merge(volume_mesh); + } + + m_measuring.reset(new Measure::Measuring(composite_mesh.its)); + update_plane_models_cache(m_measuring->get_mesh().its); + m_raycaster.update_from(m_measuring->get_mesh()); + m_volumes_cache = volumes_cache; + }; +#else auto do_update = [this, update_plane_models_cache](const ModelObject* object, const ModelVolume* volume) { const indexed_triangle_set& its = (volume != nullptr) ? volume->mesh().its : object->volumes.front()->mesh().its; m_measuring.reset(new Measure::Measuring(its)); @@ -977,24 +1096,44 @@ void GLGizmoMeasure::update_if_needed() // Let's save what we calculated it from: m_volumes_matrices.clear(); m_volumes_types.clear(); - m_first_instance_scale = Vec3d::Ones(); + m_first_instance_scale = Vec3d::Ones(); m_first_instance_mirror = Vec3d::Ones(); if (object != nullptr) { for (const ModelVolume* vol : object->volumes) { m_volumes_matrices.push_back(vol->get_matrix()); m_volumes_types.push_back(vol->type()); } - m_first_instance_scale = object->instances.front()->get_scaling_factor(); + m_first_instance_scale = object->instances.front()->get_scaling_factor(); m_first_instance_mirror = object->instances.front()->get_mirror(); } m_old_model_object = object; m_old_model_volume = volume; }; +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES const Selection& selection = m_parent.get_selection(); if (selection.is_empty()) return; +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + const Selection::IndicesList& idxs = selection.get_volume_idxs(); + std::vector volumes_cache; + volumes_cache.reserve(idxs.size()); + for (unsigned int idx : idxs) { + const GLVolume* v = selection.get_volume(idx); + const ModelObject* obj = selection.get_model()->objects[v->object_idx()]; + const ModelInstance* inst = obj->instances[v->instance_idx()]; + const ModelVolume* vol = obj->volumes[v->volume_idx()]; + const VolumeCacheItem item = { obj, inst, vol, inst->get_matrix() * vol->get_matrix() }; + volumes_cache.emplace_back(item); + } + + if (m_state != On || volumes_cache.empty()) + return; + + if (m_measuring == nullptr || m_volumes_cache != volumes_cache) + do_update(volumes_cache, selection); +#else m_volume_matrix = selection.get_first_volume()->world_matrix(); const ModelObject* mo = m_c->selection_info()->model_object(); @@ -1023,6 +1162,7 @@ void GLGizmoMeasure::update_if_needed() break; } } +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES } void GLGizmoMeasure::disable_scene_raycasters() @@ -1142,6 +1282,62 @@ void GLGizmoMeasure::render_dimensioning() const double ratio = new_value / old_value; wxGetApp().plater()->take_snapshot(_L("Scale")); +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + struct TrafoData + { + double ratio; + Vec3d old_pivot; + Vec3d new_pivot; + Transform3d scale_matrix; + + TrafoData(double ratio, const Vec3d& pivot) { + this->ratio = ratio; + this->scale_matrix = Geometry::scale_transform(ratio); + this->old_pivot = pivot; + this->new_pivot = { pivot.x(), pivot.y(), (this->scale_matrix * pivot).z() }; + } + + Vec3d transform(const Vec3d& point) const { + return this->scale_matrix * (point - this->old_pivot) + this->new_pivot; + } + }; + + auto scale_feature = [this](Measure::SurfaceFeature& feature, const TrafoData& trafo_data) { + switch (feature.get_type()) + { + case Measure::SurfaceFeatureType::Point: + { + feature = Measure::SurfaceFeature(trafo_data.transform(feature.get_point())); + break; + } + case Measure::SurfaceFeatureType::Edge: + { + const auto [from, to] = feature.get_edge(); + const std::optional extra = feature.get_extra_point(); + const std::optional new_extra = extra.has_value() ? trafo_data.transform(*extra) : extra; + feature = Measure::SurfaceFeature(Measure::SurfaceFeatureType::Edge, trafo_data.transform(from), trafo_data.transform(to), new_extra); + break; + } + case Measure::SurfaceFeatureType::Circle: + { + const auto [center, radius, normal] = feature.get_circle(); + feature = Measure::SurfaceFeature(Measure::SurfaceFeatureType::Circle, trafo_data.transform(center), normal, std::nullopt, trafo_data.ratio * radius); + break; + } + case Measure::SurfaceFeatureType::Plane: + { + const auto [idx, normal, origin] = feature.get_plane(); + feature = Measure::SurfaceFeature(Measure::SurfaceFeatureType::Plane, normal, trafo_data.transform(origin), std::nullopt, idx); + break; + } + } + }; + + const TrafoData trafo_data(ratio, m_parent.get_selection().get_bounding_box().center()); + scale_feature(*m_selected_features.first.feature, trafo_data); + scale_feature(*m_selected_features.second.feature, trafo_data); +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + TransformationType type; type.set_world(); type.set_relative(); @@ -1200,8 +1396,10 @@ void GLGizmoMeasure::render_dimensioning() assert(f1.get_type() == Measure::SurfaceFeatureType::Point && f2.get_type() == Measure::SurfaceFeatureType::Edge); std::pair e = f2.get_edge(); // Transform to world coordinates +#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES e.first = TransformHelper::model_to_world(e.first, m_volume_matrix); e.second = TransformHelper::model_to_world(e.second, m_volume_matrix); +#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES const Vec3d v_proj = m_measurement_result.distance_infinite->to; @@ -1482,15 +1680,21 @@ void GLGizmoMeasure::render_debug_dialog() { case Measure::SurfaceFeatureType::Point: { +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + add_strings_row_to_table(*m_imgui, "m_pt1", ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(item.feature->get_point()), ImGui::GetStyleColorVec4(ImGuiCol_Text)); +#else const Vec3d position = m_volume_matrix * item.feature->get_point(); add_strings_row_to_table(*m_imgui, "m_pt1", ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(position), ImGui::GetStyleColorVec4(ImGuiCol_Text)); +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES break; } case Measure::SurfaceFeatureType::Edge: { auto [from, to] = item.feature->get_edge(); +#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES from = m_volume_matrix * from; to = m_volume_matrix * to; +#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES add_strings_row_to_table(*m_imgui, "m_pt1", ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(from), ImGui::GetStyleColorVec4(ImGuiCol_Text)); add_strings_row_to_table(*m_imgui, "m_pt2", ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(to), ImGui::GetStyleColorVec4(ImGuiCol_Text)); break; @@ -1498,8 +1702,10 @@ void GLGizmoMeasure::render_debug_dialog() case Measure::SurfaceFeatureType::Plane: { auto [idx, normal, origin] = item.feature->get_plane(); +#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES origin = m_volume_matrix * origin; normal = m_volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal; +#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES add_strings_row_to_table(*m_imgui, "m_pt1", ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(normal), ImGui::GetStyleColorVec4(ImGuiCol_Text)); add_strings_row_to_table(*m_imgui, "m_pt2", ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(origin), ImGui::GetStyleColorVec4(ImGuiCol_Text)); add_strings_row_to_table(*m_imgui, "m_value", ImGuiWrapper::COL_ORANGE_LIGHT, format_double(idx), ImGui::GetStyleColorVec4(ImGuiCol_Text)); @@ -1508,9 +1714,13 @@ void GLGizmoMeasure::render_debug_dialog() case Measure::SurfaceFeatureType::Circle: { auto [center, radius, normal] = item.feature->get_circle(); +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + const Vec3d on_circle = center + radius * Measure::get_orthogonal(normal, true); +#else const Vec3d on_circle = m_volume_matrix * (center + radius * Measure::get_orthogonal(normal, true)); center = m_volume_matrix * center; normal = (m_volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal).normalized(); +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES radius = (on_circle - center).norm(); add_strings_row_to_table(*m_imgui, "m_pt1", ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(center), ImGui::GetStyleColorVec4(ImGuiCol_Text)); add_strings_row_to_table(*m_imgui, "m_pt2", ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(normal), ImGui::GetStyleColorVec4(ImGuiCol_Text)); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 7bfc2e8c93..606012f7c4 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -5,10 +5,16 @@ #include "slic3r/GUI/GLModel.hpp" #include "slic3r/GUI/GUI_Utils.hpp" #include "libslic3r/Measure.hpp" +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES +#include "slic3r/GUI/Gizmos/GLGizmosCommon.hpp" +#include "libslic3r/Model.hpp" +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES namespace Slic3r { +#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES class ModelVolume; +#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES enum class ModelVolumeType : int; @@ -68,6 +74,23 @@ class GLGizmoMeasure : public GLGizmoBase } }; +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + 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; +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + EMode m_mode{ EMode::FeatureSelection }; Measure::MeasurementResult m_measurement_result; @@ -85,7 +108,13 @@ class GLGizmoMeasure : public GLGizmoBase }; Dimensioning m_dimensioning; +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + // Uses a standalone raycaster and not the shared one because of the + // difference in how the mesh is updated + CommonGizmosDataObjects::Raycaster m_raycaster; +#else Transform3d m_volume_matrix{ Transform3d::Identity() }; +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES std::vector m_plane_models_cache; std::map> m_raycasters; std::vector> m_selection_raycasters; @@ -100,17 +129,21 @@ class GLGizmoMeasure : public GLGizmoBase std::vector m_scene_raycasters; // These hold information to decide whether recalculation is necessary: +#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES std::vector m_volumes_matrices; std::vector m_volumes_types; Vec3d m_first_instance_scale{ Vec3d::Ones() }; Vec3d m_first_instance_mirror{ Vec3d::Ones() }; +#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES float m_last_inv_zoom{ 0.0f }; std::optional m_last_circle; int m_last_plane_idx{ -1 }; bool m_mouse_left_down{ false }; // for detection left_up of this gizmo +#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES const ModelObject* m_old_model_object{ nullptr }; const ModelVolume* m_old_model_volume{ nullptr }; +#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES Vec2d m_mouse_pos{ Vec2d::Zero() }; @@ -153,7 +186,9 @@ protected: bool on_is_activable() const override; void on_render() override; void on_set_state() override; +#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES CommonGizmosDataID on_get_requirements() const override; +#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES virtual void on_render_input_window(float x, float y, float bottom_limit) override; virtual void on_register_raycasters_for_picking() override; diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp index 394e879b7c..dca64a5266 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp @@ -327,6 +327,19 @@ const TriangleMesh* HollowedMesh::get_hollowed_interior() const } +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES +void Raycaster::update_from(const TriangleMesh& mesh) +{ + std::vector meshes = { &mesh }; + if (meshes != m_old_meshes) { + wxBusyCursor wait; + m_raycasters.clear(); + m_raycasters.emplace_back(new MeshRaycaster(std::make_shared(mesh))); + m_old_meshes = meshes; + } + validate(); +} +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES void Raycaster::on_update() diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp index 42faa25f84..b02e3a920c 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp @@ -137,6 +137,9 @@ protected: virtual void on_update() = 0; CommonGizmosDataPool* get_pool() const { return m_common; } +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + void validate() { m_is_valid = true; } +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES private: bool m_is_valid = false; @@ -242,6 +245,10 @@ public: const MeshRaycaster* raycaster() const { assert(m_raycasters.size() == 1); return m_raycasters.front().get(); } std::vector raycasters() const; +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + void update_from(const TriangleMesh& mesh); +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + protected: void on_update() override; void on_release() override; diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index b27f7a7381..0e893fb16c 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -613,6 +613,19 @@ bool Selection::contains_any_volume(const std::vector& volume_idxs return false; } +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES +bool Selection::contains_sinking_volumes(bool ignore_modifiers) const +{ + for (const GLVolume* v : *m_volumes) { + if (!ignore_modifiers || !v->is_modifier) { + if (v->is_sinking()) + return true; + } + } + return false; +} +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + bool Selection::matches(const std::vector& volume_idxs) const { unsigned int count = 0; diff --git a/src/slic3r/GUI/Selection.hpp b/src/slic3r/GUI/Selection.hpp index 34b88f1606..cf9d26fc7d 100644 --- a/src/slic3r/GUI/Selection.hpp +++ b/src/slic3r/GUI/Selection.hpp @@ -338,6 +338,10 @@ public: bool contains_all_volumes(const std::vector& volume_idxs) const; // returns true if the selection contains at least one of the given indices bool contains_any_volume(const std::vector& volume_idxs) const; +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + // returns true if the selection contains any sinking volume + bool contains_sinking_volumes(bool ignore_modifiers = true) const; +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES // returns true if the selection contains all and only the given indices bool matches(const std::vector& volume_idxs) const; From 4606d8266a87e92c75701adfb4ece322534555d6 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 15 Nov 2022 12:42:22 +0100 Subject: [PATCH 46/89] Added missing declaration --- src/libslic3r/Measure.hpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/libslic3r/Measure.hpp b/src/libslic3r/Measure.hpp index b2e2008d15..9cc380dd2b 100644 --- a/src/libslic3r/Measure.hpp +++ b/src/libslic3r/Measure.hpp @@ -12,6 +12,11 @@ struct indexed_triangle_set; namespace Slic3r { + +#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES +class TriangleMesh; +#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + namespace Measure { From 268365b92db90084f9b142c7bd46ebf3b708ec1d Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Tue, 15 Nov 2022 16:07:38 +0100 Subject: [PATCH 47/89] Measurement: refactoring - do not touch common raycaster interface when there is no need --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 9 +++------ src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 4 ++-- src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp | 15 --------------- src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp | 8 -------- 4 files changed, 5 insertions(+), 31 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 5ae906eac9..8cfbf634eb 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -245,9 +245,6 @@ TransformHelper::Cache TransformHelper::s_cache = { { 0, 0, 0, 0 }, Matrix4d::Id GLGizmoMeasure::GLGizmoMeasure(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) : GLGizmoBase(parent, icon_filename, sprite_id) -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES -, m_raycaster(nullptr) -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES { GLModel::Geometry sphere_geometry = smooth_sphere(16, 7.5f); m_sphere.mesh_raycaster = std::make_unique(std::make_shared(sphere_geometry.get_as_indexed_triangle_set())); @@ -526,7 +523,7 @@ void GLGizmoMeasure::on_set_state() m_is_editing_distance_first_frame = true; m_measuring.reset(); #if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - m_raycaster.release(); + m_raycaster.reset(); #endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES } else { @@ -599,7 +596,7 @@ void GLGizmoMeasure::on_render() Vec3f normal_on_model; size_t model_facet_idx; #if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - const bool mouse_on_object = m_raycaster.raycaster()->unproject_on_mesh(m_mouse_pos, Transform3d::Identity(), camera, position_on_model, normal_on_model, nullptr, &model_facet_idx); + const bool mouse_on_object = m_raycaster->unproject_on_mesh(m_mouse_pos, Transform3d::Identity(), camera, position_on_model, normal_on_model, nullptr, &model_facet_idx); #else const bool mouse_on_object = m_c->raycaster()->raycasters().front()->unproject_on_mesh(m_mouse_pos, m_volume_matrix, camera, position_on_model, normal_on_model, nullptr, &model_facet_idx); #endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES @@ -1083,7 +1080,7 @@ void GLGizmoMeasure::update_if_needed() m_measuring.reset(new Measure::Measuring(composite_mesh.its)); update_plane_models_cache(m_measuring->get_mesh().its); - m_raycaster.update_from(m_measuring->get_mesh()); + m_raycaster.reset(new MeshRaycaster(std::make_shared(m_measuring->get_mesh()))); m_volumes_cache = volumes_cache; }; #else diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 606012f7c4..fbbf30da78 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -4,9 +4,9 @@ #include "GLGizmoBase.hpp" #include "slic3r/GUI/GLModel.hpp" #include "slic3r/GUI/GUI_Utils.hpp" +#include "slic3r/GUI/MeshUtils.hpp" #include "libslic3r/Measure.hpp" #if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES -#include "slic3r/GUI/Gizmos/GLGizmosCommon.hpp" #include "libslic3r/Model.hpp" #endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES @@ -111,7 +111,7 @@ class GLGizmoMeasure : public GLGizmoBase #if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES // Uses a standalone raycaster and not the shared one because of the // difference in how the mesh is updated - CommonGizmosDataObjects::Raycaster m_raycaster; + std::unique_ptr m_raycaster; #else Transform3d m_volume_matrix{ Transform3d::Identity() }; #endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp index dca64a5266..11c44113bc 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp @@ -327,21 +327,6 @@ const TriangleMesh* HollowedMesh::get_hollowed_interior() const } -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES -void Raycaster::update_from(const TriangleMesh& mesh) -{ - std::vector meshes = { &mesh }; - if (meshes != m_old_meshes) { - wxBusyCursor wait; - m_raycasters.clear(); - m_raycasters.emplace_back(new MeshRaycaster(std::make_shared(mesh))); - m_old_meshes = meshes; - } - validate(); -} -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - - void Raycaster::on_update() { wxBusyCursor wait; diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp index b02e3a920c..3878c6b25a 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp @@ -137,10 +137,6 @@ protected: virtual void on_update() = 0; CommonGizmosDataPool* get_pool() const { return m_common; } -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - void validate() { m_is_valid = true; } -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - private: bool m_is_valid = false; CommonGizmosDataPool* m_common = nullptr; @@ -245,10 +241,6 @@ public: const MeshRaycaster* raycaster() const { assert(m_raycasters.size() == 1); return m_raycasters.front().get(); } std::vector raycasters() const; -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - void update_from(const TriangleMesh& mesh); -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - protected: void on_update() override; void on_release() override; From 5382f4077ac88c988647979c4cb792a4cf475892 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Tue, 15 Nov 2022 16:08:27 +0100 Subject: [PATCH 48/89] Measurement: Partially fixed the common gizmo raycaster for self-intersecting meshes --- src/slic3r/GUI/MeshUtils.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/MeshUtils.cpp b/src/slic3r/GUI/MeshUtils.cpp index 0483d2bf0a..94375a6e34 100644 --- a/src/slic3r/GUI/MeshUtils.cpp +++ b/src/slic3r/GUI/MeshUtils.cpp @@ -409,6 +409,12 @@ bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& Vec3d direction; line_from_mouse_pos(mouse_pos, trafo, camera, point, direction); + if (rand()%100 == 0) { + int a=5; + int b=6; + int c=7; + } + std::vector hits = m_emesh.query_ray_hits(point, direction); if (hits.empty()) @@ -429,10 +435,10 @@ bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& // All hits are clipped. return false; } - if ((hits.size()-i) % 2 != 0) { + if (clipping_plane && (hits.size()-i) % 2 != 0) { // There is an odd number of unclipped hits - meaning the nearest must be from inside the mesh. // In that case, calculate intersection with the clipping place. - if (clipping_plane && was_clipping_plane_hit) { + if (was_clipping_plane_hit) { direction = direction + point; point = trafo * point; // transform to world coords direction = trafo * direction - point; From 075c24190691f90ac85d1544a295a80bbf26c4eb Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 16 Nov 2022 08:53:02 +0100 Subject: [PATCH 49/89] Tech ENABLE_GIZMO_MEASURE_WORLD_COORDINATES set as default Fixed conflicts during rebase to master --- src/libslic3r/Measure.cpp | 48 -- src/libslic3r/Measure.hpp | 30 +- src/libslic3r/Technologies.hpp | 2 - src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 850 +++++++++-------------- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 26 +- src/slic3r/GUI/Selection.cpp | 2 - src/slic3r/GUI/Selection.hpp | 2 - 7 files changed, 323 insertions(+), 637 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index 9b930df9aa..4e3bcaa822 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -47,9 +47,7 @@ public: std::optional get_feature(size_t face_idx, const Vec3d& point) const; std::vector> get_planes_triangle_indices() const; const std::vector& get_plane_features(unsigned int plane_id) const; -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES const TriangleMesh& get_mesh() const; -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES private: void update_planes(); @@ -57,11 +55,7 @@ private: std::vector m_planes; std::vector m_face_to_plane; -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES TriangleMesh m_mesh; -#else - const indexed_triangle_set& m_its; -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES }; @@ -70,11 +64,7 @@ private: MeasuringImpl::MeasuringImpl(const indexed_triangle_set& its) -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES : m_mesh(its) -#else -: m_its{its} -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES { update_planes(); extract_features(); @@ -87,17 +77,10 @@ void MeasuringImpl::update_planes() // Now we'll go through all the facets and append Points of facets sharing the same normal. // This part is still performed in mesh coordinate system. -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES const size_t num_of_facets = m_mesh.its.indices.size(); m_face_to_plane.resize(num_of_facets, size_t(-1)); const std::vector face_normals = its_face_normals(m_mesh.its); const std::vector face_neighbors = its_face_neighbors(m_mesh.its); -#else - const size_t num_of_facets = m_its.indices.size(); - m_face_to_plane.resize(num_of_facets, size_t(-1)); - const std::vector face_normals = its_face_normals(m_its); - const std::vector face_neighbors = its_face_neighbors(m_its); -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES std::vector facet_queue(num_of_facets, 0); int facet_queue_cnt = 0; const stl_normal* normal_ptr = nullptr; @@ -146,11 +129,7 @@ void MeasuringImpl::update_planes() assert(std::none_of(m_face_to_plane.begin(), m_face_to_plane.end(), [](size_t val) { return val == size_t(-1); })); // Now we will walk around each of the planes and save vertices which form the border. -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES SurfaceMesh sm(m_mesh.its); -#else - SurfaceMesh sm(m_its); -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES for (int plane_id=0; plane_id < int(m_planes.size()); ++plane_id) { const auto& facets = m_planes[plane_id].facets; m_planes[plane_id].borders.clear(); @@ -532,12 +511,10 @@ const std::vector& MeasuringImpl::get_plane_features(unsigned in return m_planes[plane_id].surface_features; } -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES const TriangleMesh& MeasuringImpl::get_mesh() const { return this->m_mesh; } -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES @@ -579,12 +556,10 @@ const std::vector& Measuring::get_plane_features(unsigned int pl return priv->get_plane_features(plane_id); } -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES const TriangleMesh& Measuring::get_mesh() const { return priv->get_mesh(); } -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES const AngleAndEdges AngleAndEdges::Dummy = { 0.0, Vec3d::Zero(), { Vec3d::Zero(), Vec3d::Zero() }, { Vec3d::Zero(), Vec3d::Zero() }, 0.0, true }; @@ -1184,29 +1159,6 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& return result; } -#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES -void DistAndPoints::transform(const Transform3d& trafo) { - from = trafo * from; - to = trafo * to; - dist = (to - from).norm(); -} - -void AngleAndEdges::transform(const Transform3d& trafo) { - const Vec3d old_e1 = e1.second - e1.first; - const Vec3d old_e2 = e2.second - e2.first; - center = trafo * center; - e1.first = trafo * e1.first; - e1.second = trafo * e1.second; - e2.first = trafo * e2.first; - e2.second = trafo * e2.second; - angle = std::acos(std::clamp(Measure::edge_direction(e1).dot(Measure::edge_direction(e2)), -1.0, 1.0)); - const Vec3d new_e1 = e1.second - e1.first; - const Vec3d new_e2 = e2.second - e2.first; - const double average_scale = 0.5 * (new_e1.norm() / old_e1.norm() + new_e2.norm() / old_e2.norm()); - radius = average_scale * radius; -} -#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - diff --git a/src/libslic3r/Measure.hpp b/src/libslic3r/Measure.hpp index 9cc380dd2b..3a1a4b89d9 100644 --- a/src/libslic3r/Measure.hpp +++ b/src/libslic3r/Measure.hpp @@ -13,9 +13,7 @@ struct indexed_triangle_set; namespace Slic3r { -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES class TriangleMesh; -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES namespace Measure { @@ -93,10 +91,7 @@ class MeasuringImpl; class Measuring { public: // Construct the measurement object on a given its. -#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - // The its must remain valid and unchanged during the whole lifetime of the object. -#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - explicit Measuring(const indexed_triangle_set& its); + explicit Measuring(const indexed_triangle_set& its); ~Measuring(); // Return a reference to a list of all features identified on the its. @@ -115,10 +110,8 @@ public: // Returns the surface features of the plane with the given index const std::vector& get_plane_features(unsigned int plane_id) const; -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES // Returns the mesh used for measuring const TriangleMesh& get_mesh() const; -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES private: std::unique_ptr priv; @@ -130,10 +123,6 @@ struct DistAndPoints { double dist; Vec3d from; Vec3d to; - -#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - void transform(const Transform3d& trafo); -#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES }; struct AngleAndEdges { @@ -146,10 +135,6 @@ struct AngleAndEdges { double radius; bool coplanar; -#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - void transform(const Transform3d& trafo); -#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - static const AngleAndEdges Dummy; }; @@ -166,19 +151,6 @@ struct MeasurementResult { bool has_any_data() const { return angle.has_value() || distance_infinite.has_value() || distance_strict.has_value() || distance_xyz.has_value(); } - -#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - void transform(const Transform3d& trafo) { - if (angle.has_value()) - angle->transform(trafo); - if (distance_infinite.has_value()) - distance_infinite->transform(trafo); - if (distance_strict.has_value()) { - distance_strict->transform(trafo); - distance_xyz = (distance_strict->to - distance_strict->from).cwiseAbs(); - } - } -#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES }; // Returns distance/angle between two SurfaceFeatures. diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index 759871c60d..f707b0f21d 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -64,8 +64,6 @@ // Enable picking using raytracing #define ENABLE_RAYCAST_PICKING (1 && ENABLE_LEGACY_OPENGL_REMOVAL) #define ENABLE_RAYCAST_PICKING_DEBUG (0 && ENABLE_RAYCAST_PICKING) -// Enable gizmo measure combining volumes meshes and passing them to the backend in world coordinates -#define ENABLE_GIZMO_MEASURE_WORLD_COORDINATES (1 && ENABLE_2_5_0_ALPHA1) #endif // _prusaslicer_technologies_h_ diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 8cfbf634eb..35767121d7 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -6,10 +6,6 @@ #include "slic3r/GUI/GUI_ObjectManipulation.hpp" -#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES -#include "slic3r/GUI/Gizmos/GLGizmosCommon.hpp" -#include "libslic3r/Model.hpp" -#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES #include "libslic3r/PresetBundle.hpp" #include "libslic3r/MeasureUtils.hpp" @@ -370,13 +366,8 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) } } - if (m_selected_features != selected_features_old && m_selected_features.second.feature.has_value()) { + if (m_selected_features != selected_features_old && m_selected_features.second.feature.has_value()) m_measurement_result = Measure::get_measurement(*m_selected_features.first.feature, *m_selected_features.second.feature, m_measuring.get()); -#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - // transform to world coordinates - m_measurement_result.transform(m_volume_matrix); -#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - } m_imgui->set_requires_extra_frame(); @@ -423,29 +414,12 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) void GLGizmoMeasure::data_changed() { -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES update_if_needed(); -#else - const Selection& selection = m_parent.get_selection(); - const ModelObject* model_object = nullptr; - const ModelVolume* model_volume = nullptr; - if (selection.is_single_full_instance() || - selection.is_from_single_object() ) { - model_object = selection.get_model()->objects[selection.get_object_idx()]; - model_volume = model_object->volumes[selection.get_first_volume()->volume_idx()]; - } - if (model_object != m_old_model_object || model_volume != m_old_model_volume) - update_if_needed(); -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES m_last_inv_zoom = 0.0f; m_last_plane_idx = -1; if (m_pending_scale) { m_measurement_result = Measure::get_measurement(*m_selected_features.first.feature, *m_selected_features.second.feature, m_measuring.get()); -#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - // transform to world coordinates - m_measurement_result.transform(m_volume_matrix); -#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES m_pending_scale = false; } else @@ -522,9 +496,7 @@ void GLGizmoMeasure::on_set_state() m_editing_distance = false; m_is_editing_distance_first_frame = true; m_measuring.reset(); -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES m_raycaster.reset(); -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES } else { m_mode = EMode::FeatureSelection; @@ -541,13 +513,6 @@ void GLGizmoMeasure::on_set_state() } } -#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES -CommonGizmosDataID GLGizmoMeasure::on_get_requirements() const -{ - return CommonGizmosDataID(int(CommonGizmosDataID::SelectionInfo) | int(CommonGizmosDataID::Raycaster)); -} -#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - std::string GLGizmoMeasure::on_get_name() const { return _u8L("Measure"); @@ -558,15 +523,9 @@ bool GLGizmoMeasure::on_is_activable() const const Selection& selection = m_parent.get_selection(); bool res = (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA) ? selection.is_single_full_instance() : -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES selection.is_single_full_instance() || selection.is_single_volume() || selection.is_single_modifier(); if (res) res &= !selection.contains_sinking_volumes(); -#else - selection.is_single_volume() || selection.is_single_volume_instance(); - if (res) - res &= !selection.get_first_volume()->is_sinking(); -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES return res; } @@ -583,473 +542,390 @@ void GLGizmoMeasure::on_render() const Selection& selection = m_parent.get_selection(); -#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - if ((wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA && selection.is_single_full_instance()) || - (selection.is_single_volume() || selection.is_single_volume_instance())) { -#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - update_if_needed(); + update_if_needed(); - const Camera& camera = wxGetApp().plater()->get_camera(); - const float inv_zoom = (float)camera.get_inv_zoom(); + const Camera& camera = wxGetApp().plater()->get_camera(); + const float inv_zoom = (float)camera.get_inv_zoom(); - Vec3f position_on_model; - Vec3f normal_on_model; - size_t model_facet_idx; -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - const bool mouse_on_object = m_raycaster->unproject_on_mesh(m_mouse_pos, Transform3d::Identity(), camera, position_on_model, normal_on_model, nullptr, &model_facet_idx); -#else - const bool mouse_on_object = m_c->raycaster()->raycasters().front()->unproject_on_mesh(m_mouse_pos, m_volume_matrix, camera, position_on_model, normal_on_model, nullptr, &model_facet_idx); -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - const bool is_hovering_on_feature = (m_mode == EMode::PointSelection || m_mode == EMode::CenterSelection) && m_hover_id != -1; + Vec3f position_on_model; + Vec3f normal_on_model; + size_t model_facet_idx; + const bool mouse_on_object = m_raycaster->unproject_on_mesh(m_mouse_pos, Transform3d::Identity(), camera, position_on_model, normal_on_model, nullptr, &model_facet_idx); + const bool is_hovering_on_feature = (m_mode == EMode::PointSelection || m_mode == EMode::CenterSelection) && m_hover_id != -1; - auto update_circle = [this, inv_zoom]() { - if (m_last_inv_zoom != inv_zoom || m_last_circle != m_curr_feature) { - m_last_inv_zoom = inv_zoom; - m_last_circle = m_curr_feature; - m_circle.reset(); - const auto [center, radius, normal] = m_curr_feature->get_circle(); -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - GLModel::Geometry circle_geometry = init_torus_data(64, 16, center.cast(), float(radius), 5.0f * inv_zoom, normal.cast(), Transform3f::Identity()); -#else - GLModel::Geometry circle_geometry = init_torus_data(64, 16, center.cast(), float(radius), 5.0f * inv_zoom, normal.cast(), m_volume_matrix.cast()); -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - m_circle.mesh_raycaster = std::make_unique(std::make_shared(circle_geometry.get_as_indexed_triangle_set())); - m_circle.model.init_from(std::move(circle_geometry)); - return true; - } - return false; - }; + auto update_circle = [this, inv_zoom]() { + if (m_last_inv_zoom != inv_zoom || m_last_circle != m_curr_feature) { + m_last_inv_zoom = inv_zoom; + m_last_circle = m_curr_feature; + m_circle.reset(); + const auto [center, radius, normal] = m_curr_feature->get_circle(); + GLModel::Geometry circle_geometry = init_torus_data(64, 16, center.cast(), float(radius), 5.0f * inv_zoom, normal.cast(), Transform3f::Identity()); + m_circle.mesh_raycaster = std::make_unique(std::make_shared(circle_geometry.get_as_indexed_triangle_set())); + m_circle.model.init_from(std::move(circle_geometry)); + return true; + } + return false; + }; - if (m_mode == EMode::FeatureSelection || m_mode == EMode::PointSelection) { - if ((m_hover_id == SELECTION_1_ID && boost::algorithm::istarts_with(m_selected_features.first.source, _u8L("Center"))) || - (m_hover_id == SELECTION_2_ID && boost::algorithm::istarts_with(m_selected_features.second.source, _u8L("Center")))) { - // Skip feature detection if hovering on a selected center - m_curr_feature.reset(); + if (m_mode == EMode::FeatureSelection || m_mode == EMode::PointSelection) { + if ((m_hover_id == SELECTION_1_ID && boost::algorithm::istarts_with(m_selected_features.first.source, _u8L("Center"))) || + (m_hover_id == SELECTION_2_ID && boost::algorithm::istarts_with(m_selected_features.second.source, _u8L("Center")))) { + // Skip feature detection if hovering on a selected center + m_curr_feature.reset(); + m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, POINT_ID); + m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, EDGE_ID); + m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, PLANE_ID); + m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_ID); + m_curr_point_on_feature_position.reset(); + } + else { + std::optional curr_feature = mouse_on_object ? m_measuring->get_feature(model_facet_idx, position_on_model.cast()) : std::nullopt; + if (m_curr_feature != curr_feature || + (curr_feature.has_value() && curr_feature->get_type() == Measure::SurfaceFeatureType::Circle && (m_curr_feature != curr_feature || m_last_inv_zoom != inv_zoom))) { m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, POINT_ID); m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, EDGE_ID); m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, PLANE_ID); m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_ID); - m_curr_point_on_feature_position.reset(); - } - else { - std::optional curr_feature = mouse_on_object ? m_measuring->get_feature(model_facet_idx, position_on_model.cast()) : std::nullopt; - if (m_curr_feature != curr_feature || - (curr_feature.has_value() && curr_feature->get_type() == Measure::SurfaceFeatureType::Circle && (m_curr_feature != curr_feature || m_last_inv_zoom != inv_zoom))) { - m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, POINT_ID); - m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, EDGE_ID); - m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, PLANE_ID); - m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_ID); - m_raycasters.clear(); - m_curr_feature = curr_feature; - if (!m_curr_feature.has_value()) - return; + m_raycasters.clear(); + m_curr_feature = curr_feature; + if (!m_curr_feature.has_value()) + return; - switch (m_curr_feature->get_type()) { - default: { assert(false); break; } - case Measure::SurfaceFeatureType::Point: - { - m_raycasters.insert({ POINT_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, POINT_ID, *m_sphere.mesh_raycaster) }); - break; - } - case Measure::SurfaceFeatureType::Edge: - { - m_raycasters.insert({ EDGE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, EDGE_ID, *m_cylinder.mesh_raycaster) }); - if (m_curr_feature->get_extra_point().has_value()) - m_raycasters.insert({ POINT_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, POINT_ID, *m_sphere.mesh_raycaster) }); - break; - } - case Measure::SurfaceFeatureType::Circle: - { - update_circle(); - m_raycasters.insert({ CIRCLE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_ID, *m_circle.mesh_raycaster) }); - m_raycasters.insert({ POINT_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, POINT_ID, *m_sphere.mesh_raycaster) }); - break; - } - case Measure::SurfaceFeatureType::Plane: - { - const auto [idx, normal, point] = m_curr_feature->get_plane(); - if (m_last_plane_idx != idx) { - m_last_plane_idx = idx; -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - const indexed_triangle_set& its = m_measuring->get_mesh().its; -#else - const indexed_triangle_set its = (m_old_model_volume != nullptr) ? m_old_model_volume->mesh().its : m_old_model_object->volumes.front()->mesh().its; -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - const std::vector> planes_triangles = m_measuring->get_planes_triangle_indices(); - GLModel::Geometry init_data = init_plane_data(its, planes_triangles, idx); - m_plane.reset(); - m_plane.mesh_raycaster = std::make_unique(std::make_shared(init_data.get_as_indexed_triangle_set())); - m_plane.model.init_from(std::move(init_data)); - } - - m_raycasters.insert({ PLANE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, PLANE_ID, *m_plane.mesh_raycaster) }); - break; - } - } - } - } - } - - if (m_mode != EMode::PointSelection) - m_curr_point_on_feature_position.reset(); - else if (is_hovering_on_feature) { - auto position_on_feature = [this](int feature_type_id, const Camera& camera, std::function callback = nullptr) -> Vec3d { - auto it = m_raycasters.find(feature_type_id); - if (it != m_raycasters.end() && it->second != nullptr) { - Vec3f p; - Vec3f n; - const Transform3d& trafo = it->second->get_transform(); - bool res = it->second->get_raycaster()->closest_hit(m_mouse_pos, trafo, camera, p, n); - if (res) { - if (callback) - p = callback(p); - return trafo * p.cast(); - } - } - return Vec3d::Zero(); - }; - - if (m_curr_feature.has_value()) { - switch (m_curr_feature->get_type()) - { + switch (m_curr_feature->get_type()) { default: { assert(false); break; } case Measure::SurfaceFeatureType::Point: { - m_curr_point_on_feature_position = m_curr_feature->get_point(); + m_raycasters.insert({ POINT_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, POINT_ID, *m_sphere.mesh_raycaster) }); break; } case Measure::SurfaceFeatureType::Edge: { - const std::optional extra = m_curr_feature->get_extra_point(); - if (extra.has_value() && m_hover_id == POINT_ID) - m_curr_point_on_feature_position = *extra; - else -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - m_curr_point_on_feature_position = position_on_feature(EDGE_ID, camera, [](const Vec3f& v) { return Vec3f(0.0f, 0.0f, v.z()); }); -#else - m_curr_point_on_feature_position = m_volume_matrix.inverse() * position_on_feature(EDGE_ID, camera, [](const Vec3f& v) { return Vec3f(0.0f, 0.0f, v.z()); }); -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + m_raycasters.insert({ EDGE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, EDGE_ID, *m_cylinder.mesh_raycaster) }); + if (m_curr_feature->get_extra_point().has_value()) + m_raycasters.insert({ POINT_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, POINT_ID, *m_sphere.mesh_raycaster) }); + break; + } + case Measure::SurfaceFeatureType::Circle: + { + update_circle(); + m_raycasters.insert({ CIRCLE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_ID, *m_circle.mesh_raycaster) }); + m_raycasters.insert({ POINT_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, POINT_ID, *m_sphere.mesh_raycaster) }); break; } case Measure::SurfaceFeatureType::Plane: { -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - m_curr_point_on_feature_position = position_on_feature(PLANE_ID, camera); -#else - m_curr_point_on_feature_position = m_volume_matrix.inverse() * position_on_feature(PLANE_ID, camera); -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - break; - } - case Measure::SurfaceFeatureType::Circle: - { - const auto [center, radius, normal] = m_curr_feature->get_circle(); - if (m_hover_id == POINT_ID) - m_curr_point_on_feature_position = center; - else { - const Vec3d world_pof = position_on_feature(CIRCLE_ID, camera, [](const Vec3f& v) { return v; }); -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - const Eigen::Hyperplane plane(normal, center); -#else - const Eigen::Hyperplane plane(m_volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal, m_volume_matrix * center); -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - const Transform3d local_to_model_matrix = Geometry::translation_transform(center) * Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), normal); -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - const Vec3d local_proj = local_to_model_matrix.inverse() * plane.projection(world_pof); -#else - const Vec3d local_proj = local_to_model_matrix.inverse() * m_volume_matrix.inverse() * plane.projection(world_pof); -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - double angle = std::atan2(local_proj.y(), local_proj.x()); - if (angle < 0.0) - angle += 2.0 * double(M_PI); - - const Vec3d local_pos = radius * Vec3d(std::cos(angle), std::sin(angle), 0.0); - m_curr_point_on_feature_position = local_to_model_matrix * local_pos; + const auto [idx, normal, point] = m_curr_feature->get_plane(); + if (m_last_plane_idx != idx) { + m_last_plane_idx = idx; + const indexed_triangle_set& its = m_measuring->get_mesh().its; + const std::vector> planes_triangles = m_measuring->get_planes_triangle_indices(); + GLModel::Geometry init_data = init_plane_data(its, planes_triangles, idx); + m_plane.reset(); + m_plane.mesh_raycaster = std::make_unique(std::make_shared(init_data.get_as_indexed_triangle_set())); + m_plane.model.init_from(std::move(init_data)); } + + m_raycasters.insert({ PLANE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, PLANE_ID, *m_plane.mesh_raycaster) }); break; } } } } - else { - if (m_curr_feature.has_value() && m_curr_feature->get_type() == Measure::SurfaceFeatureType::Circle) { - if (update_circle()) { - m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_ID); - auto it = m_raycasters.find(CIRCLE_ID); - if (it != m_raycasters.end()) - m_raycasters.erase(it); - m_raycasters.insert({ CIRCLE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_ID, *m_circle.mesh_raycaster) }); + } + + if (m_mode != EMode::PointSelection) + m_curr_point_on_feature_position.reset(); + else if (is_hovering_on_feature) { + auto position_on_feature = [this](int feature_type_id, const Camera& camera, std::function callback = nullptr) -> Vec3d { + auto it = m_raycasters.find(feature_type_id); + if (it != m_raycasters.end() && it->second != nullptr) { + Vec3f p; + Vec3f n; + const Transform3d& trafo = it->second->get_transform(); + bool res = it->second->get_raycaster()->closest_hit(m_mouse_pos, trafo, camera, p, n); + if (res) { + if (callback) + p = callback(p); + return trafo * p.cast(); } } + return Vec3d::Zero(); + }; + + if (m_curr_feature.has_value()) { + switch (m_curr_feature->get_type()) + { + default: { assert(false); break; } + case Measure::SurfaceFeatureType::Point: + { + m_curr_point_on_feature_position = m_curr_feature->get_point(); + break; + } + case Measure::SurfaceFeatureType::Edge: + { + const std::optional extra = m_curr_feature->get_extra_point(); + if (extra.has_value() && m_hover_id == POINT_ID) + m_curr_point_on_feature_position = *extra; + else + m_curr_point_on_feature_position = position_on_feature(EDGE_ID, camera, [](const Vec3f& v) { return Vec3f(0.0f, 0.0f, v.z()); }); + break; + } + case Measure::SurfaceFeatureType::Plane: + { + m_curr_point_on_feature_position = position_on_feature(PLANE_ID, camera); + break; + } + case Measure::SurfaceFeatureType::Circle: + { + const auto [center, radius, normal] = m_curr_feature->get_circle(); + if (m_hover_id == POINT_ID) + m_curr_point_on_feature_position = center; + else { + const Vec3d world_pof = position_on_feature(CIRCLE_ID, camera, [](const Vec3f& v) { return v; }); + const Eigen::Hyperplane plane(normal, center); + const Transform3d local_to_model_matrix = Geometry::translation_transform(center) * Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), normal); + const Vec3d local_proj = local_to_model_matrix.inverse() * plane.projection(world_pof); + double angle = std::atan2(local_proj.y(), local_proj.x()); + if (angle < 0.0) + angle += 2.0 * double(M_PI); + + const Vec3d local_pos = radius * Vec3d(std::cos(angle), std::sin(angle), 0.0); + m_curr_point_on_feature_position = local_to_model_matrix * local_pos; + } + break; + } + } } + } + else { + if (m_curr_feature.has_value() && m_curr_feature->get_type() == Measure::SurfaceFeatureType::Circle) { + if (update_circle()) { + m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_ID); + auto it = m_raycasters.find(CIRCLE_ID); + if (it != m_raycasters.end()) + m_raycasters.erase(it); + m_raycasters.insert({ CIRCLE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_ID, *m_circle.mesh_raycaster) }); + } + } + } - if (!m_curr_feature.has_value() && !m_selected_features.first.feature.has_value()) - return; + if (!m_curr_feature.has_value() && !m_selected_features.first.feature.has_value()) + return; - GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light"); - if (shader == nullptr) - return; + GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light"); + if (shader == nullptr) + return; - shader->start_using(); - shader->set_uniform("projection_matrix", camera.get_projection_matrix()); + shader->start_using(); + shader->set_uniform("projection_matrix", camera.get_projection_matrix()); - glsafe(::glClear(GL_DEPTH_BUFFER_BIT)); - glsafe(::glEnable(GL_DEPTH_TEST)); - const bool old_cullface = ::glIsEnabled(GL_CULL_FACE); - glsafe(::glDisable(GL_CULL_FACE)); + glsafe(::glClear(GL_DEPTH_BUFFER_BIT)); + glsafe(::glEnable(GL_DEPTH_TEST)); + const bool old_cullface = ::glIsEnabled(GL_CULL_FACE); + glsafe(::glDisable(GL_CULL_FACE)); - const Transform3d& view_matrix = camera.get_view_matrix(); + const Transform3d& view_matrix = camera.get_view_matrix(); - auto set_matrix_uniforms = [shader, &view_matrix](const Transform3d& model_matrix) { - const Transform3d view_model_matrix = view_matrix * model_matrix; - shader->set_uniform("view_model_matrix", view_model_matrix); - const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); - shader->set_uniform("view_normal_matrix", view_normal_matrix); - }; + auto set_matrix_uniforms = [shader, &view_matrix](const Transform3d& model_matrix) { + const Transform3d view_model_matrix = view_matrix * model_matrix; + shader->set_uniform("view_model_matrix", view_model_matrix); + const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); + shader->set_uniform("view_normal_matrix", view_normal_matrix); + }; - auto set_emission_uniform = [this, shader](const ColorRGBA& color, bool hover) { - shader->set_uniform("emission_factor", (color == m_parent.get_selection().get_first_volume()->render_color) ? 0.0f : - hover ? 0.5f : 0.25f); - }; + auto set_emission_uniform = [this, shader](const ColorRGBA& color, bool hover) { + shader->set_uniform("emission_factor", (color == m_parent.get_selection().get_first_volume()->render_color) ? 0.0f : + hover ? 0.5f : 0.25f); + }; - auto render_feature = [this, set_matrix_uniforms, set_emission_uniform](const Measure::SurfaceFeature& feature, const std::vector& colors, - float inv_zoom, bool hover, bool update_raycasters_transform) { - switch (feature.get_type()) - { - default: { assert(false); break; } - case Measure::SurfaceFeatureType::Point: - { -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - const Transform3d feature_matrix = Geometry::translation_transform(feature.get_point()) * Geometry::scale_transform(inv_zoom); -#else - const Vec3d position = TransformHelper::model_to_world(feature.get_point(), m_volume_matrix); - const Transform3d feature_matrix = Geometry::translation_transform(position) * Geometry::scale_transform(inv_zoom); -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - set_matrix_uniforms(feature_matrix); + auto render_feature = [this, set_matrix_uniforms, set_emission_uniform](const Measure::SurfaceFeature& feature, const std::vector& colors, + float inv_zoom, bool hover, bool update_raycasters_transform) { + switch (feature.get_type()) + { + default: { assert(false); break; } + case Measure::SurfaceFeatureType::Point: + { + const Transform3d feature_matrix = Geometry::translation_transform(feature.get_point()) * Geometry::scale_transform(inv_zoom); + set_matrix_uniforms(feature_matrix); + set_emission_uniform(colors.front(), hover); + m_sphere.model.set_color(colors.front()); + m_sphere.model.render(); + if (update_raycasters_transform) { + auto it = m_raycasters.find(POINT_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(feature_matrix); + } + break; + } + case Measure::SurfaceFeatureType::Circle: + { + const auto& [center, radius, normal] = feature.get_circle(); + // render center + if (update_raycasters_transform) { + const Transform3d center_matrix = Geometry::translation_transform(center) * Geometry::scale_transform(inv_zoom); + set_matrix_uniforms(center_matrix); set_emission_uniform(colors.front(), hover); m_sphere.model.set_color(colors.front()); m_sphere.model.render(); - if (update_raycasters_transform) { - auto it = m_raycasters.find(POINT_ID); - if (it != m_raycasters.end() && it->second != nullptr) - it->second->set_transform(feature_matrix); - } - break; + auto it = m_raycasters.find(POINT_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(center_matrix); } - case Measure::SurfaceFeatureType::Circle: - { - const auto& [center, radius, normal] = feature.get_circle(); - // render center + // render circle + if (m_mode != EMode::CenterSelection) { + const Transform3d circle_matrix = Transform3d::Identity(); + set_matrix_uniforms(circle_matrix); if (update_raycasters_transform) { -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - const Transform3d center_matrix = Geometry::translation_transform(center) * Geometry::scale_transform(inv_zoom); -#else - const Vec3d center_world = TransformHelper::model_to_world(center, m_volume_matrix); - const Transform3d center_matrix = Geometry::translation_transform(center_world) * Geometry::scale_transform(inv_zoom); -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - set_matrix_uniforms(center_matrix); + set_emission_uniform(colors.back(), hover); + m_circle.model.set_color(colors.back()); + m_circle.model.render(); + auto it = m_raycasters.find(CIRCLE_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(circle_matrix); + } + else { + GLModel circle; + GLModel::Geometry circle_geometry = init_torus_data(64, 16, center.cast(), float(radius), 5.0f * inv_zoom, normal.cast(), Transform3f::Identity()); + circle.init_from(std::move(circle_geometry)); + set_emission_uniform(colors.back(), hover); + circle.set_color(colors.back()); + circle.render(); + } + } + break; + } + case Measure::SurfaceFeatureType::Edge: + { + const auto& [from, to] = feature.get_edge(); + // render extra point + if (update_raycasters_transform) { + const std::optional extra = feature.get_extra_point(); + if (extra.has_value()) { + const Transform3d point_matrix = Geometry::translation_transform(*extra) * Geometry::scale_transform(inv_zoom); + set_matrix_uniforms(point_matrix); set_emission_uniform(colors.front(), hover); m_sphere.model.set_color(colors.front()); m_sphere.model.render(); auto it = m_raycasters.find(POINT_ID); if (it != m_raycasters.end() && it->second != nullptr) - it->second->set_transform(center_matrix); + it->second->set_transform(point_matrix); } - // render circle - if (m_mode != EMode::CenterSelection) { - const Transform3d circle_matrix = Transform3d::Identity(); - set_matrix_uniforms(circle_matrix); - if (update_raycasters_transform) { - set_emission_uniform(colors.back(), hover); - m_circle.model.set_color(colors.back()); - m_circle.model.render(); - auto it = m_raycasters.find(CIRCLE_ID); - if (it != m_raycasters.end() && it->second != nullptr) - it->second->set_transform(circle_matrix); - } - else { - GLModel circle; -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - GLModel::Geometry circle_geometry = init_torus_data(64, 16, center.cast(), float(radius), 5.0f * inv_zoom, normal.cast(), Transform3f::Identity()); -#else - GLModel::Geometry circle_geometry = init_torus_data(64, 16, center.cast(), float(radius), 5.0f * inv_zoom, normal.cast(), m_volume_matrix.cast()); -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - circle.init_from(std::move(circle_geometry)); - set_emission_uniform(colors.back(), hover); - circle.set_color(colors.back()); - circle.render(); - } - } - break; } - case Measure::SurfaceFeatureType::Edge: - { - const auto& [from, to] = feature.get_edge(); - // render extra point + // render edge + if (m_mode != EMode::CenterSelection) { + const Transform3d edge_matrix = Geometry::translation_transform(from) * + Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), to - from) * + Geometry::scale_transform({ (double)inv_zoom, (double)inv_zoom, (to - from).norm() }); + set_matrix_uniforms(edge_matrix); + set_emission_uniform(colors.back(), hover); + m_cylinder.model.set_color(colors.back()); + m_cylinder.model.render(); if (update_raycasters_transform) { - const std::optional extra = feature.get_extra_point(); - if (extra.has_value()) { -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - const Transform3d point_matrix = Geometry::translation_transform(*extra) * Geometry::scale_transform(inv_zoom); -#else - const Vec3d extra_world = TransformHelper::model_to_world(*extra, m_volume_matrix); - const Transform3d point_matrix = Geometry::translation_transform(extra_world) * Geometry::scale_transform(inv_zoom); -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - set_matrix_uniforms(point_matrix); - set_emission_uniform(colors.front(), hover); - m_sphere.model.set_color(colors.front()); - m_sphere.model.render(); - auto it = m_raycasters.find(POINT_ID); - if (it != m_raycasters.end() && it->second != nullptr) - it->second->set_transform(point_matrix); - } - } - // render edge - if (m_mode != EMode::CenterSelection) { -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - const Transform3d edge_matrix = Geometry::translation_transform(from) * - Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), to - from) * - Geometry::scale_transform({ (double)inv_zoom, (double)inv_zoom, (to - from).norm() }); -#else - const Vec3d from_world = TransformHelper::model_to_world(from, m_volume_matrix); - const Vec3d to_world = TransformHelper::model_to_world(to, m_volume_matrix); - const Transform3d edge_matrix = Geometry::translation_transform(from_world) * - Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), to_world - from_world) * - Geometry::scale_transform({ (double)inv_zoom, (double)inv_zoom, (to_world - from_world).norm() }); -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - set_matrix_uniforms(edge_matrix); - set_emission_uniform(colors.back(), hover); - m_cylinder.model.set_color(colors.back()); - m_cylinder.model.render(); - if (update_raycasters_transform) { - auto it = m_raycasters.find(EDGE_ID); - if (it != m_raycasters.end() && it->second != nullptr) - it->second->set_transform(edge_matrix); - } - } - break; - } - case Measure::SurfaceFeatureType::Plane: - { - // no need to render the plane in case it is rendered with the same color as the volume in the 3D scene - if (colors.front() != m_parent.get_selection().get_first_volume()->render_color) { - const auto& [idx, normal, pt] = feature.get_plane(); - assert(idx < m_plane_models_cache.size()); -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - set_matrix_uniforms(Transform3d::Identity()); -#else - set_matrix_uniforms(m_volume_matrix); -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - set_emission_uniform(colors.front(), hover); - m_plane_models_cache[idx].set_color(colors.front()); - m_plane_models_cache[idx].render(); - } - if (update_raycasters_transform) { - auto it = m_raycasters.find(PLANE_ID); + auto it = m_raycasters.find(EDGE_ID); if (it != m_raycasters.end() && it->second != nullptr) -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - it->second->set_transform(Transform3d::Identity()); -#else - it->second->set_transform(m_volume_matrix); -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + it->second->set_transform(edge_matrix); } - break; } + break; + } + case Measure::SurfaceFeatureType::Plane: + { + // no need to render the plane in case it is rendered with the same color as the volume in the 3D scene + if (colors.front() != m_parent.get_selection().get_first_volume()->render_color) { + const auto& [idx, normal, pt] = feature.get_plane(); + assert(idx < m_plane_models_cache.size()); + set_matrix_uniforms(Transform3d::Identity()); + set_emission_uniform(colors.front(), hover); + m_plane_models_cache[idx].set_color(colors.front()); + m_plane_models_cache[idx].render(); } - }; + if (update_raycasters_transform) { + auto it = m_raycasters.find(PLANE_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(Transform3d::Identity()); + } + break; + } + } + }; - auto hover_selection_color = [this]() { - return !m_selected_features.first.feature.has_value() ? SELECTED_1ST_COLOR : SELECTED_2ND_COLOR; - }; + auto hover_selection_color = [this]() { + return !m_selected_features.first.feature.has_value() ? SELECTED_1ST_COLOR : SELECTED_2ND_COLOR; + }; - auto hovering_color = [this, hover_selection_color, &selection]() { - return (m_mode == EMode::PointSelection) ? selection.get_first_volume()->render_color : hover_selection_color(); - }; + auto hovering_color = [this, hover_selection_color, &selection]() { + return (m_mode == EMode::PointSelection) ? selection.get_first_volume()->render_color : hover_selection_color(); + }; - if (m_curr_feature.has_value()) { - std::vector colors; - if (m_selected_features.first.feature.has_value() && *m_curr_feature == *m_selected_features.first.feature) + if (m_curr_feature.has_value()) { + std::vector colors; + if (m_selected_features.first.feature.has_value() && *m_curr_feature == *m_selected_features.first.feature) + colors.emplace_back(hovering_color()); + else if (m_selected_features.second.feature.has_value() && *m_curr_feature == *m_selected_features.second.feature) + colors.emplace_back(hovering_color()); + else { + switch (m_curr_feature->get_type()) + { + default: { assert(false); break; } + case Measure::SurfaceFeatureType::Point: + { + colors.emplace_back(hover_selection_color()); + break; + } + case Measure::SurfaceFeatureType::Edge: + case Measure::SurfaceFeatureType::Circle: + { + colors.emplace_back((m_hover_id == POINT_ID) ? hover_selection_color() : hovering_color()); colors.emplace_back(hovering_color()); - else if (m_selected_features.second.feature.has_value() && *m_curr_feature == *m_selected_features.second.feature) + break; + } + case Measure::SurfaceFeatureType::Plane: + { colors.emplace_back(hovering_color()); - else { - switch (m_curr_feature->get_type()) - { - default: { assert(false); break; } - case Measure::SurfaceFeatureType::Point: - { - colors.emplace_back(hover_selection_color()); - break; - } - case Measure::SurfaceFeatureType::Edge: - case Measure::SurfaceFeatureType::Circle: - { - colors.emplace_back((m_hover_id == POINT_ID) ? hover_selection_color() : hovering_color()); - colors.emplace_back(hovering_color()); - break; - } - case Measure::SurfaceFeatureType::Plane: - { - colors.emplace_back(hovering_color()); - break; - } - } + break; } - - render_feature(*m_curr_feature, colors, inv_zoom, true, true); - } - - if (m_selected_features.first.feature.has_value() && (!m_curr_feature.has_value() || *m_curr_feature != *m_selected_features.first.feature)) { - const std::vector colors = { SELECTED_1ST_COLOR }; - render_feature(*m_selected_features.first.feature, colors, inv_zoom, m_hover_id == SELECTION_1_ID, false); - if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Point) { - auto it = std::find_if(m_selection_raycasters.begin(), m_selection_raycasters.end(), - [](std::shared_ptr item) { return SceneRaycaster::decode_id(SceneRaycaster::EType::Gizmo, item->get_id()) == SELECTION_1_ID; }); - if (it != m_selection_raycasters.end()) -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - (*it)->set_transform(Geometry::translation_transform(m_selected_features.first.feature->get_point()) * Geometry::scale_transform(inv_zoom)); -#else - (*it)->set_transform(m_volume_matrix * Geometry::translation_transform(m_selected_features.first.feature->get_point()) * Geometry::scale_transform(inv_zoom)); -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - } - } - if (m_selected_features.second.feature.has_value() && (!m_curr_feature.has_value() || *m_curr_feature != *m_selected_features.second.feature)) { - const std::vector colors = { SELECTED_2ND_COLOR }; - render_feature(*m_selected_features.second.feature, colors, inv_zoom, m_hover_id == SELECTION_2_ID, false); - if (m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Point) { - auto it = std::find_if(m_selection_raycasters.begin(), m_selection_raycasters.end(), - [](std::shared_ptr item) { return SceneRaycaster::decode_id(SceneRaycaster::EType::Gizmo, item->get_id()) == SELECTION_2_ID; }); - if (it != m_selection_raycasters.end()) -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - (*it)->set_transform(Geometry::translation_transform(m_selected_features.second.feature->get_point()) * Geometry::scale_transform(inv_zoom)); -#else - (*it)->set_transform(m_volume_matrix * Geometry::translation_transform(m_selected_features.second.feature->get_point()) * Geometry::scale_transform(inv_zoom)); -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES } } - if (is_hovering_on_feature && m_curr_point_on_feature_position.has_value()) { - if (m_hover_id != POINT_ID) { -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - const Transform3d matrix = Geometry::translation_transform(*m_curr_point_on_feature_position) * Geometry::scale_transform(inv_zoom); -#else - const Vec3d position = TransformHelper::model_to_world(*m_curr_point_on_feature_position, m_volume_matrix); - const Transform3d matrix = Geometry::translation_transform(position) * Geometry::scale_transform(inv_zoom); -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - set_matrix_uniforms(matrix); - const ColorRGBA color = hover_selection_color(); - set_emission_uniform(color, true); - m_sphere.model.set_color(color); - m_sphere.model.render(); - } - } - - shader->stop_using(); - - if (old_cullface) - glsafe(::glEnable(GL_CULL_FACE)); -#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + render_feature(*m_curr_feature, colors, inv_zoom, true, true); } -#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + + if (m_selected_features.first.feature.has_value() && (!m_curr_feature.has_value() || *m_curr_feature != *m_selected_features.first.feature)) { + const std::vector colors = { SELECTED_1ST_COLOR }; + render_feature(*m_selected_features.first.feature, colors, inv_zoom, m_hover_id == SELECTION_1_ID, false); + if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Point) { + auto it = std::find_if(m_selection_raycasters.begin(), m_selection_raycasters.end(), + [](std::shared_ptr item) { return SceneRaycaster::decode_id(SceneRaycaster::EType::Gizmo, item->get_id()) == SELECTION_1_ID; }); + if (it != m_selection_raycasters.end()) + (*it)->set_transform(Geometry::translation_transform(m_selected_features.first.feature->get_point()) * Geometry::scale_transform(inv_zoom)); + } + } + if (m_selected_features.second.feature.has_value() && (!m_curr_feature.has_value() || *m_curr_feature != *m_selected_features.second.feature)) { + const std::vector colors = { SELECTED_2ND_COLOR }; + render_feature(*m_selected_features.second.feature, colors, inv_zoom, m_hover_id == SELECTION_2_ID, false); + if (m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Point) { + auto it = std::find_if(m_selection_raycasters.begin(), m_selection_raycasters.end(), + [](std::shared_ptr item) { return SceneRaycaster::decode_id(SceneRaycaster::EType::Gizmo, item->get_id()) == SELECTION_2_ID; }); + if (it != m_selection_raycasters.end()) + (*it)->set_transform(Geometry::translation_transform(m_selected_features.second.feature->get_point()) * Geometry::scale_transform(inv_zoom)); + } + } + + if (is_hovering_on_feature && m_curr_point_on_feature_position.has_value()) { + if (m_hover_id != POINT_ID) { + const Transform3d matrix = Geometry::translation_transform(*m_curr_point_on_feature_position) * Geometry::scale_transform(inv_zoom); + set_matrix_uniforms(matrix); + const ColorRGBA color = hover_selection_color(); + set_emission_uniform(color, true); + m_sphere.model.set_color(color); + m_sphere.model.render(); + } + } + + shader->stop_using(); + + if (old_cullface) + glsafe(::glEnable(GL_CULL_FACE)); render_dimensioning(); } @@ -1066,7 +942,6 @@ void GLGizmoMeasure::update_if_needed() } }; -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES auto do_update = [this, update_plane_models_cache](const std::vector& volumes_cache, const Selection& selection) { TriangleMesh composite_mesh; for (const auto& vol : volumes_cache) { @@ -1083,36 +958,11 @@ void GLGizmoMeasure::update_if_needed() m_raycaster.reset(new MeshRaycaster(std::make_shared(m_measuring->get_mesh()))); m_volumes_cache = volumes_cache; }; -#else - auto do_update = [this, update_plane_models_cache](const ModelObject* object, const ModelVolume* volume) { - const indexed_triangle_set& its = (volume != nullptr) ? volume->mesh().its : object->volumes.front()->mesh().its; - m_measuring.reset(new Measure::Measuring(its)); - - update_plane_models_cache(its); - - // Let's save what we calculated it from: - m_volumes_matrices.clear(); - m_volumes_types.clear(); - m_first_instance_scale = Vec3d::Ones(); - m_first_instance_mirror = Vec3d::Ones(); - if (object != nullptr) { - for (const ModelVolume* vol : object->volumes) { - m_volumes_matrices.push_back(vol->get_matrix()); - m_volumes_types.push_back(vol->type()); - } - m_first_instance_scale = object->instances.front()->get_scaling_factor(); - m_first_instance_mirror = object->instances.front()->get_mirror(); - } - m_old_model_object = object; - m_old_model_volume = volume; - }; -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES const Selection& selection = m_parent.get_selection(); if (selection.is_empty()) return; -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES const Selection::IndicesList& idxs = selection.get_volume_idxs(); std::vector volumes_cache; volumes_cache.reserve(idxs.size()); @@ -1130,36 +980,6 @@ void GLGizmoMeasure::update_if_needed() if (m_measuring == nullptr || m_volumes_cache != volumes_cache) do_update(volumes_cache, selection); -#else - m_volume_matrix = selection.get_first_volume()->world_matrix(); - - const ModelObject* mo = m_c->selection_info()->model_object(); - const ModelVolume* mv = m_c->selection_info()->model_volume(); - if (m_state != On || (mo == nullptr && mv == nullptr)) - return; - - if (mo == nullptr) - mo = mv->get_object(); - - if (mo->instances.empty()) - return; - - if (!m_measuring || mo != m_old_model_object || mv != m_old_model_volume || mo->volumes.size() != m_volumes_matrices.size()) - do_update(mo, mv); - - // We want to recalculate when the scale changes - some planes could (dis)appear. - if (!mo->instances.front()->get_scaling_factor().isApprox(m_first_instance_scale) || - !mo->instances.front()->get_mirror().isApprox(m_first_instance_mirror)) - do_update(mo, mv); - - for (unsigned int i = 0; i < mo->volumes.size(); ++i) { - if (!mo->volumes[i]->get_matrix().isApprox(m_volumes_matrices[i]) || - mo->volumes[i]->type() != m_volumes_types[i]) { - do_update(mo, mv); - break; - } - } -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES } void GLGizmoMeasure::disable_scene_raycasters() @@ -1279,7 +1099,6 @@ void GLGizmoMeasure::render_dimensioning() const double ratio = new_value / old_value; wxGetApp().plater()->take_snapshot(_L("Scale")); -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES struct TrafoData { double ratio; @@ -1333,7 +1152,6 @@ void GLGizmoMeasure::render_dimensioning() const TrafoData trafo_data(ratio, m_parent.get_selection().get_bounding_box().center()); scale_feature(*m_selected_features.first.feature, trafo_data); scale_feature(*m_selected_features.second.feature, trafo_data); -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES TransformationType type; type.set_world(); @@ -1392,14 +1210,7 @@ void GLGizmoMeasure::render_dimensioning() auto point_edge = [this, shader](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2) { assert(f1.get_type() == Measure::SurfaceFeatureType::Point && f2.get_type() == Measure::SurfaceFeatureType::Edge); std::pair e = f2.get_edge(); - // Transform to world coordinates -#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - e.first = TransformHelper::model_to_world(e.first, m_volume_matrix); - e.second = TransformHelper::model_to_world(e.second, m_volume_matrix); -#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - const Vec3d v_proj = m_measurement_result.distance_infinite->to; - const Vec3d e1e2 = e.second - e.first; const Vec3d v_proje1 = v_proj - e.first; const bool on_e1_side = v_proje1.dot(e1e2) < -EPSILON; @@ -1677,21 +1488,12 @@ void GLGizmoMeasure::render_debug_dialog() { case Measure::SurfaceFeatureType::Point: { -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES add_strings_row_to_table(*m_imgui, "m_pt1", ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(item.feature->get_point()), ImGui::GetStyleColorVec4(ImGuiCol_Text)); -#else - const Vec3d position = m_volume_matrix * item.feature->get_point(); - add_strings_row_to_table(*m_imgui, "m_pt1", ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(position), ImGui::GetStyleColorVec4(ImGuiCol_Text)); -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES break; } case Measure::SurfaceFeatureType::Edge: { auto [from, to] = item.feature->get_edge(); -#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - from = m_volume_matrix * from; - to = m_volume_matrix * to; -#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES add_strings_row_to_table(*m_imgui, "m_pt1", ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(from), ImGui::GetStyleColorVec4(ImGuiCol_Text)); add_strings_row_to_table(*m_imgui, "m_pt2", ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(to), ImGui::GetStyleColorVec4(ImGuiCol_Text)); break; @@ -1699,10 +1501,6 @@ void GLGizmoMeasure::render_debug_dialog() case Measure::SurfaceFeatureType::Plane: { auto [idx, normal, origin] = item.feature->get_plane(); -#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - origin = m_volume_matrix * origin; - normal = m_volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal; -#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES add_strings_row_to_table(*m_imgui, "m_pt1", ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(normal), ImGui::GetStyleColorVec4(ImGuiCol_Text)); add_strings_row_to_table(*m_imgui, "m_pt2", ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(origin), ImGui::GetStyleColorVec4(ImGuiCol_Text)); add_strings_row_to_table(*m_imgui, "m_value", ImGuiWrapper::COL_ORANGE_LIGHT, format_double(idx), ImGui::GetStyleColorVec4(ImGuiCol_Text)); @@ -1711,13 +1509,7 @@ void GLGizmoMeasure::render_debug_dialog() case Measure::SurfaceFeatureType::Circle: { auto [center, radius, normal] = item.feature->get_circle(); -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES const Vec3d on_circle = center + radius * Measure::get_orthogonal(normal, true); -#else - const Vec3d on_circle = m_volume_matrix * (center + radius * Measure::get_orthogonal(normal, true)); - center = m_volume_matrix * center; - normal = (m_volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal).normalized(); -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES radius = (on_circle - center).norm(); add_strings_row_to_table(*m_imgui, "m_pt1", ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(center), ImGui::GetStyleColorVec4(ImGuiCol_Text)); add_strings_row_to_table(*m_imgui, "m_pt2", ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(normal), ImGui::GetStyleColorVec4(ImGuiCol_Text)); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index fbbf30da78..9699d73cc8 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -6,16 +6,10 @@ #include "slic3r/GUI/GUI_Utils.hpp" #include "slic3r/GUI/MeshUtils.hpp" #include "libslic3r/Measure.hpp" -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES #include "libslic3r/Model.hpp" -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES namespace Slic3r { -#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES -class ModelVolume; -#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - enum class ModelVolumeType : int; namespace Measure { class Measuring; } @@ -74,7 +68,6 @@ class GLGizmoMeasure : public GLGizmoBase } }; -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES struct VolumeCacheItem { const ModelObject* object{ nullptr }; @@ -89,7 +82,6 @@ class GLGizmoMeasure : public GLGizmoBase }; std::vector m_volumes_cache; -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES EMode m_mode{ EMode::FeatureSelection }; Measure::MeasurementResult m_measurement_result; @@ -108,13 +100,10 @@ class GLGizmoMeasure : public GLGizmoBase }; Dimensioning m_dimensioning; -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES // Uses a standalone raycaster and not the shared one because of the // difference in how the mesh is updated std::unique_ptr m_raycaster; -#else - Transform3d m_volume_matrix{ Transform3d::Identity() }; -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES + std::vector m_plane_models_cache; std::map> m_raycasters; std::vector> m_selection_raycasters; @@ -129,21 +118,11 @@ class GLGizmoMeasure : public GLGizmoBase std::vector m_scene_raycasters; // These hold information to decide whether recalculation is necessary: -#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - std::vector m_volumes_matrices; - std::vector m_volumes_types; - Vec3d m_first_instance_scale{ Vec3d::Ones() }; - Vec3d m_first_instance_mirror{ Vec3d::Ones() }; -#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES float m_last_inv_zoom{ 0.0f }; std::optional m_last_circle; int m_last_plane_idx{ -1 }; bool m_mouse_left_down{ false }; // for detection left_up of this gizmo -#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - const ModelObject* m_old_model_object{ nullptr }; - const ModelVolume* m_old_model_volume{ nullptr }; -#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES Vec2d m_mouse_pos{ Vec2d::Zero() }; @@ -186,9 +165,6 @@ protected: bool on_is_activable() const override; void on_render() override; void on_set_state() override; -#if !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES - CommonGizmosDataID on_get_requirements() const override; -#endif // !ENABLE_GIZMO_MEASURE_WORLD_COORDINATES virtual void on_render_input_window(float x, float y, float bottom_limit) override; virtual void on_register_raycasters_for_picking() override; diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index 0e893fb16c..c3a7ec18be 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -613,7 +613,6 @@ bool Selection::contains_any_volume(const std::vector& volume_idxs return false; } -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES bool Selection::contains_sinking_volumes(bool ignore_modifiers) const { for (const GLVolume* v : *m_volumes) { @@ -624,7 +623,6 @@ bool Selection::contains_sinking_volumes(bool ignore_modifiers) const } return false; } -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES bool Selection::matches(const std::vector& volume_idxs) const { diff --git a/src/slic3r/GUI/Selection.hpp b/src/slic3r/GUI/Selection.hpp index cf9d26fc7d..6468f6a87d 100644 --- a/src/slic3r/GUI/Selection.hpp +++ b/src/slic3r/GUI/Selection.hpp @@ -338,10 +338,8 @@ public: bool contains_all_volumes(const std::vector& volume_idxs) const; // returns true if the selection contains at least one of the given indices bool contains_any_volume(const std::vector& volume_idxs) const; -#if ENABLE_GIZMO_MEASURE_WORLD_COORDINATES // returns true if the selection contains any sinking volume bool contains_sinking_volumes(bool ignore_modifiers = true) const; -#endif // ENABLE_GIZMO_MEASURE_WORLD_COORDINATES // returns true if the selection contains all and only the given indices bool matches(const std::vector& volume_idxs) const; From 6dd8199edf518f5a83ee2de7d338b78c002f477d Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 16 Nov 2022 09:38:19 +0100 Subject: [PATCH 50/89] Gizmo measure - Fixed orientation of arrows in arc dimensioning --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 35767121d7..423c23edd2 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -1295,7 +1295,7 @@ void GLGizmoMeasure::render_dimensioning() const double angle = (endpoint_id == 1) ? 0.0 : step * double(resolution); const Vec3d position_model = Geometry::translation_transform(center) * (draw_radius * (Eigen::Quaternion(Eigen::AngleAxisd(angle, normal)) * e1_unit)); const Vec3d direction_model = (endpoint_id == 1) ? -normal.cross(position_model - center).normalized() : normal.cross(position_model - center).normalized(); - const auto qz = Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), normal); + const auto qz = Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), (endpoint_id == 1) ? normal : -normal); const auto qx = Eigen::Quaternion::FromTwoVectors(qz * Vec3d::UnitX(), direction_model); const Transform3d view_model_matrix = camera.get_view_matrix() * Geometry::translation_transform(position_model) * qx * qz * Geometry::scale_transform(camera.get_inv_zoom()); From e6b2467f44623f59cba5ca8355eb5484ff8744ee Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 16 Nov 2022 09:42:55 +0100 Subject: [PATCH 51/89] Fixed warnings --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 423c23edd2..b2edc0b979 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -1118,7 +1118,7 @@ void GLGizmoMeasure::render_dimensioning() } }; - auto scale_feature = [this](Measure::SurfaceFeature& feature, const TrafoData& trafo_data) { + auto scale_feature = [](Measure::SurfaceFeature& feature, const TrafoData& trafo_data) { switch (feature.get_type()) { case Measure::SurfaceFeatureType::Point: @@ -1146,6 +1146,7 @@ void GLGizmoMeasure::render_dimensioning() feature = Measure::SurfaceFeature(Measure::SurfaceFeatureType::Plane, normal, trafo_data.transform(origin), std::nullopt, idx); break; } + default: { break; } } }; From 832b0a69e8efea32de28f44d098df6275f0310ee Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 16 Nov 2022 09:46:50 +0100 Subject: [PATCH 52/89] Fixed warnings --- src/libslic3r/Measure.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index 4e3bcaa822..ffb8f953a0 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -291,14 +291,14 @@ void MeasuringImpl::extract_features() // point happened to be inside the segment. The discrimination of too small segments // will follow, so we need a complete picture before that. if (circles_idxs.size() > 1 - && circles_idxs.back().second == angles.size()-1 + && circles_idxs.back().second == (int)angles.size()-1 && circles_idxs.front().first == 0) { // Possibly the same circle. Check that the angle and length criterion holds along the combined segment. bool same = true; double last_len = -1.; double last_angle = 0.; for (int i=circles_idxs.back().first + 1; i != circles_idxs.front().second; ++i) { - if (i == angles.size()) + if (i == (int)angles.size()) i = 1; if (last_len == -1.) { last_len = lengths[i]; @@ -347,12 +347,12 @@ void MeasuringImpl::extract_features() for (int i=int(circles_idxs.size())-1; i>=0; --i) { const auto& [start, end] = circles_idxs[i]; int N = start >= 0 - ? end - start + (start == 0 && end == border.size()-1 ? 0 : 1) // last point is the same as first + ? end - start + (start == 0 && end == (int)border.size()-1 ? 0 : 1) // last point is the same as first : end + (border.size() + start); if (N < 5) { circles.erase(circles.begin() + i); circles_idxs.erase(circles_idxs.begin() + i); - } else if (N <= 8 && start == 0 && end == border.size()-1) { + } else if (N <= 8 && start == 0 && end == (int)border.size()-1) { // This is a regular 5-8 polygon. Add the edges as edges with a special // point and remove the circle. Leave the indices in circles_idxs, so // the edges are not picked up again later. From ce46a1d03d21654a8a891a9eee295ea6617eda4c Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 16 Nov 2022 10:04:25 +0100 Subject: [PATCH 53/89] Removed debug code --- src/slic3r/GUI/MeshUtils.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/slic3r/GUI/MeshUtils.cpp b/src/slic3r/GUI/MeshUtils.cpp index 94375a6e34..68572c801e 100644 --- a/src/slic3r/GUI/MeshUtils.cpp +++ b/src/slic3r/GUI/MeshUtils.cpp @@ -409,12 +409,6 @@ bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& Vec3d direction; line_from_mouse_pos(mouse_pos, trafo, camera, point, direction); - if (rand()%100 == 0) { - int a=5; - int b=6; - int c=7; - } - std::vector hits = m_emesh.query_ray_hits(point, direction); if (hits.empty()) From 305ea0da27ea499230d4f4d6ee7b7e929f60ecc3 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 16 Nov 2022 12:04:38 +0100 Subject: [PATCH 54/89] Gizmo measure - Fixed angle for perpendicular edge-plane use case --- src/libslic3r/Measure.cpp | 53 +++++++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 19 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index ffb8f953a0..8213f9778d 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -29,6 +29,21 @@ static std::pair get_center_and_radius(const std::vector& return std::make_pair(trafo.inverse() * Vec3d(circle.center.x(), circle.center.y(), z), circle.radius); } +static std::array orthonormal_basis(const Vec3d& v) +{ + std::array ret; + ret[2] = v.normalized(); + int index; + ret[2].maxCoeff(&index); + switch (index) + { + case 0: { ret[0] = Vec3d(ret[2].y(), -ret[2].x(), 0.0).normalized(); break; } + case 1: { ret[0] = Vec3d(0.0, ret[2].z(), -ret[2].y()).normalized(); break; } + case 2: { ret[0] = Vec3d(-ret[2].z(), 0.0, ret[2].x()).normalized(); break; } + } + ret[1] = ret[2].cross(ret[0]).normalized(); + return ret; +} @@ -630,8 +645,8 @@ static AngleAndEdges angle_edge_edge(const std::pair& e1, const st static AngleAndEdges angle_edge_plane(const std::pair& e, const std::tuple& p) { const auto& [idx, normal, origin] = p; - const Vec3d e1e2_unit = edge_direction(e); - if (are_parallel(e1e2_unit, normal) || are_perpendicular(e1e2_unit, normal)) + Vec3d e1e2_unit = edge_direction(e); + if (are_perpendicular(e1e2_unit, normal)) return AngleAndEdges::Dummy; // ensure the edge is pointing away from the intersection @@ -643,8 +658,22 @@ static AngleAndEdges angle_edge_plane(const std::pair& e, const st // then verify edge direction and revert it, if needed Vec3d e1 = e.first; Vec3d e2 = e.second; - if ((e1 - inters).squaredNorm() > (e2 - inters).squaredNorm()) + if ((e1 - inters).squaredNorm() > (e2 - inters).squaredNorm()) { std::swap(e1, e2); + e1e2_unit = -e1e2_unit; + } + + if (are_parallel(e1e2_unit, normal)) { + const std::array basis = orthonormal_basis(e1e2_unit); + const double radius = (0.5 * (e1 + e2) - inters).norm(); + const Vec3d edge_on_plane_dir = (basis[1].dot(origin - inters) >= 0.0) ? basis[1] : -basis[1]; + std::pair edge_on_plane = std::make_pair(inters, inters + radius * edge_on_plane_dir); + if (!inters.isApprox(e1)) { + edge_on_plane.first += radius * edge_on_plane_dir; + edge_on_plane.second += radius * edge_on_plane_dir; + } + return AngleAndEdges(0.5 * double(PI), inters, std::make_pair(e1, e2), edge_on_plane, radius, inters.isApprox(e1)); + } const Vec3d e1e2 = e2 - e1; const double e1e2_len = e1e2.norm(); @@ -773,7 +802,8 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// - } else if (f1.get_type() == SurfaceFeatureType::Edge) { + } + else if (f1.get_type() == SurfaceFeatureType::Edge) { if (f2.get_type() == SurfaceFeatureType::Edge) { std::vector distances; @@ -900,21 +930,6 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature& const Vec3d D = c1 - c0; if (!are_parallel(n0, n1)) { - auto orthonormal_basis = [](const Vec3d& v) { - std::array ret; - ret[2] = v.normalized(); - int index; - ret[2].maxCoeff(&index); - switch (index) - { - case 0: { ret[0] = Vec3d(ret[2].y(), -ret[2].x(), 0.0).normalized(); break; } - case 1: { ret[0] = Vec3d(0.0, ret[2].z(), -ret[2].y()).normalized(); break; } - case 2: { ret[0] = Vec3d(-ret[2].z(), 0.0, ret[2].x()).normalized(); break; } - } - ret[1] = ret[2].cross(ret[0]).normalized(); - return ret; - }; - // Get parameters for constructing the degree-8 polynomial phi. const double one = 1.0; const double two = 2.0; From 89bae8606b774f505f21831d4c96b8d26b8a0445 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 16 Nov 2022 15:44:01 +0100 Subject: [PATCH 55/89] Removed debug code --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index b2edc0b979..1d71232fb0 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -396,7 +396,6 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) else if (mouse_event.RightDown()) { // let the event pass through to allow panning/rotating the 3D scene if ((m_mode != EMode::CenterSelection && mouse_event.CmdDown()) || (m_mode == EMode::CenterSelection && m_hover_id != SELECTION_1_ID && m_hover_id != SELECTION_2_ID)) { - std::cout << "RightDown -> false\n"; return false; } From 534d0353eb7b473284443a3424b5bb50fc4062f3 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 18 Nov 2022 08:42:47 +0100 Subject: [PATCH 56/89] Gizmo measure - Draw background for dimensioning labels --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 1d71232fb0..2f04e43a64 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -1071,8 +1071,17 @@ void GLGizmoMeasure::render_dimensioning() ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, { 1.0f, 1.0f }); m_imgui->begin(std::string("distance"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration); + ImGui::BringWindowToDisplayFront(ImGui::GetCurrentWindow()); ImGui::AlignTextToFramePadding(); - m_imgui->text(curr_value_str + " " + units); + ImDrawList* draw_list = ImGui::GetWindowDrawList(); + const ImVec2 pos = ImGui::GetCursorScreenPos(); + const std::string txt = curr_value_str + " " + units; + ImVec2 txt_size = ImGui::CalcTextSize(txt.c_str()); + const ImGuiStyle& style = ImGui::GetStyle(); + draw_list->AddRectFilled({ pos.x - style.FramePadding.x, pos.y + style.FramePadding.y }, { pos.x + txt_size.x + 2.0f * style.FramePadding.x , pos.y + txt_size.y + 2.0f * style.FramePadding.y }, + ImGuiWrapper::to_ImU32(ColorRGBA(0.5f, 0.5f, 0.5f, 0.5f))); + ImGui::SetCursorScreenPos({ pos.x + style.FramePadding.x, pos.y }); + m_imgui->text(txt); ImGui::SameLine(); if (m_imgui->image_button(ImGui::SliderFloatEditBtnIcon, _L("Edit to scale"))) { m_editing_distance = true; @@ -1345,7 +1354,16 @@ void GLGizmoMeasure::render_dimensioning() ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); m_imgui->begin(_L("##angle"), ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove); ImGui::BringWindowToDisplayFront(ImGui::GetCurrentWindow()); - m_imgui->text(format_double(Geometry::rad2deg(angle)) + "°"); + ImGui::AlignTextToFramePadding(); + ImDrawList* draw_list = ImGui::GetWindowDrawList(); + const ImVec2 pos = ImGui::GetCursorScreenPos(); + const std::string txt = format_double(Geometry::rad2deg(angle)) + "°"; + ImVec2 txt_size = ImGui::CalcTextSize(txt.c_str()); + const ImGuiStyle& style = ImGui::GetStyle(); + draw_list->AddRectFilled({ pos.x - style.FramePadding.x, pos.y + style.FramePadding.y }, { pos.x + txt_size.x + 2.0f * style.FramePadding.x , pos.y + txt_size.y + 2.0f * style.FramePadding.y }, + ImGuiWrapper::to_ImU32(ColorRGBA(0.5f, 0.5f, 0.5f, 0.5f))); + ImGui::SetCursorScreenPos({ pos.x + style.FramePadding.x, pos.y }); + m_imgui->text(txt); m_imgui->end(); ImGui::PopStyleVar(); }; From 1ba80257028a844cc75ca927c0363195f8ceb641 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 18 Nov 2022 10:53:42 +0100 Subject: [PATCH 57/89] Gizmo measure - Show diameter of selected circles into imgui dialog --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 2f04e43a64..ac957887dc 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -1789,10 +1789,23 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit ImGui::Separator(); const ImGuiTableFlags flags = ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersH; if (ImGui::BeginTable("Selection", 2, flags)) { - add_strings_row_to_table(*m_imgui, _u8L("Selection") + " 1:", ImGuiWrapper::to_ImVec4(SELECTED_1ST_COLOR), m_selected_features.first.feature.has_value() ? - m_selected_features.first.source : _u8L("None"), ImGuiWrapper::to_ImVec4(SELECTED_1ST_COLOR)); - add_strings_row_to_table(*m_imgui, _u8L("Selection") + " 2:", ImGuiWrapper::to_ImVec4(SELECTED_2ND_COLOR), m_selected_features.second.feature.has_value() ? - m_selected_features.second.source : _u8L("None"), ImGuiWrapper::to_ImVec4(SELECTED_2ND_COLOR)); + auto format_item_text = [use_inches, &units](const SelectedFeatures::Item& item) { + std::string txt = item.feature.has_value() ? item.source : _u8L("None"); + if (item.feature.has_value() && item.feature->get_type() == Measure::SurfaceFeatureType::Circle) { + auto [center, radius, normal] = item.feature->get_circle(); + const Vec3d on_circle = center + radius * Measure::get_orthogonal(normal, true); + radius = (on_circle - center).norm(); + if (use_inches) + radius = ObjectManipulation::mm_to_in * radius; + txt += " (" + _u8L("Diameter:") + " " + format_double(2.0 * radius) + units + ")"; + } + return txt; + }; + + add_strings_row_to_table(*m_imgui, _u8L("Selection") + " 1:", ImGuiWrapper::to_ImVec4(SELECTED_1ST_COLOR), format_item_text(m_selected_features.first), + ImGuiWrapper::to_ImVec4(SELECTED_1ST_COLOR)); + add_strings_row_to_table(*m_imgui, _u8L("Selection") + " 2:", ImGuiWrapper::to_ImVec4(SELECTED_2ND_COLOR), format_item_text(m_selected_features.second), + ImGuiWrapper::to_ImVec4(SELECTED_2ND_COLOR)); ImGui::EndTable(); } From 62d683b50c0d3b5c93af290a825036070ac273d6 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 18 Nov 2022 11:17:20 +0100 Subject: [PATCH 58/89] Removed commented out code --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 104 ----------------------- 1 file changed, 104 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index ac957887dc..358ccd87f3 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -1682,110 +1682,6 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit const bool use_inches = wxGetApp().app_config->get("use_inches") == "1"; const std::string units = use_inches ? " " + _u8L("in") : " " + _u8L("mm"); - //const Measure::SurfaceFeatureType feature_type = m_curr_feature.has_value() ? m_curr_feature->get_type() : Measure::SurfaceFeatureType::Undef; - //bool data_text_set = false; - //ImGui::Separator(); - //if (feature_type != Measure::SurfaceFeatureType::Undef) { - // if (m_mode == EMode::FeatureSelection) { - // m_imgui->text(surface_feature_type_as_string(feature_type)); - // data_text_set = true; - // } - // else if (m_mode == EMode::PointSelection) { - // if (m_hover_id != -1 && m_curr_point_on_feature_position.has_value()) { - // m_imgui->text(point_on_feature_type_as_string(feature_type, m_hover_id)); - // data_text_set = true; - // } - // } - // else if (m_mode == EMode::CenterSelection) { - // if (m_hover_id != -1 && m_curr_point_on_feature_position.has_value()) { - // m_imgui->text(center_on_feature_type_as_string(feature_type)); - // data_text_set = true; - // } - // } - //} - //if (!data_text_set) - // m_imgui->text(_u8L("No feature")); - - //const unsigned int max_data_row_count = 3; - //unsigned int data_row_count = 0; - //if (ImGui::BeginTable("Data", 2)) { - // if (m_mode == EMode::FeatureSelection) { - // switch (feature_type) - // { - // default: { break; } - // case Measure::SurfaceFeatureType::Point: - // { - // Vec3d position = m_volume_matrix * m_curr_feature->get_point(); - // if (use_inches) - // position = ObjectManipulation::mm_to_in * position; - // add_strings_row_to_table(*m_imgui, _u8L("Position"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(position), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - // data_row_count = 1; - // break; - // } - // case Measure::SurfaceFeatureType::Edge: - // { - // auto [from, to] = m_curr_feature->get_edge(); - // from = m_volume_matrix * from; - // to = m_volume_matrix * to; - // if (use_inches) { - // from = ObjectManipulation::mm_to_in * from; - // to = ObjectManipulation::mm_to_in * to; - // } - // add_strings_row_to_table(*m_imgui, _u8L("From"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(from), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - // add_strings_row_to_table(*m_imgui, _u8L("To"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(to), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - // add_strings_row_to_table(*m_imgui, _u8L("Length"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double((to - from).norm()) + units, ImGui::GetStyleColorVec4(ImGuiCol_Text)); - // data_row_count = 3; - // break; - // } - // case Measure::SurfaceFeatureType::Circle: - // { - // auto [center, radius, normal] = m_curr_feature->get_circle(); - // // generic point on circle, used to recalculate radius after transformation - // const Vec3d on_circle = m_volume_matrix * (center + radius * Measure::get_orthogonal(normal, true)); - // center = m_volume_matrix * center; - // normal = (m_volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal).normalized(); - // radius = (on_circle - center).norm(); - // if (use_inches) { - // center = ObjectManipulation::mm_to_in * center; - // radius = ObjectManipulation::mm_to_in * radius; - // } - // add_strings_row_to_table(*m_imgui, _u8L("Center"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(center), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - // add_strings_row_to_table(*m_imgui, _u8L("Radius"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(radius) + units, ImGui::GetStyleColorVec4(ImGuiCol_Text)); - // add_strings_row_to_table(*m_imgui, _u8L("Normal"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(normal), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - // data_row_count = 3; - // break; - // } - // case Measure::SurfaceFeatureType::Plane: - // { - // auto [idx, normal, origin] = m_curr_feature->get_plane(); - // origin = m_volume_matrix * origin; - // normal = m_volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal; - // if (use_inches) - // origin = ObjectManipulation::mm_to_in * origin; - // add_strings_row_to_table(*m_imgui, _u8L("Origin"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(origin), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - // add_strings_row_to_table(*m_imgui, _u8L("Normal"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(normal), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - // data_row_count = 2; - // break; - // } - // } - // } - // else { - // if (m_hover_id != -1 && m_curr_point_on_feature_position.has_value()) { - // Vec3d position = m_volume_matrix * *m_curr_point_on_feature_position; - // if (use_inches) - // position = ObjectManipulation::mm_to_in * position; - // add_strings_row_to_table(*m_imgui, _u8L("Position"), ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(position), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - // data_row_count = 1; - // } - // } - - // // add dummy rows to keep dialog size fixed - // for (unsigned int i = data_row_count; i < max_data_row_count; ++i) { - // add_strings_row_to_table(*m_imgui, " ", ImGuiWrapper::COL_ORANGE_LIGHT, " ", ImGui::GetStyleColorVec4(ImGuiCol_Text)); - // } - // ImGui::EndTable(); - //} - ImGui::Separator(); const ImGuiTableFlags flags = ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersH; if (ImGui::BeginTable("Selection", 2, flags)) { From cf2a7608d3e35e21c1e49bdaa428519f3afe8c98 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 18 Nov 2022 14:53:19 +0100 Subject: [PATCH 59/89] Gizmo measure - Render dimensioning thicker main lines --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 72 +++++++++++++++++++++++- 1 file changed, 69 insertions(+), 3 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 358ccd87f3..d85408f99c 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -1006,7 +1006,7 @@ void GLGizmoMeasure::render_dimensioning() if (shader == nullptr) return; - auto point_point = [this, shader](const Vec3d& v1, const Vec3d& v2, float distance) { + auto point_point = [this, &shader](const Vec3d& v1, const Vec3d& v2, float distance) { if ((v2 - v1).squaredNorm() < 0.000001 || distance < 0.001f) return; @@ -1036,6 +1036,25 @@ void GLGizmoMeasure::render_dimensioning() const Transform3d ss_to_ndc_matrix = TransformHelper::ndc_to_ss_matrix_inverse(viewport); +#if ENABLE_GL_CORE_PROFILE + if (OpenGLManager::get_gl_info().is_core_profile()) { + shader->stop_using(); + + shader = wxGetApp().get_shader("dashed_thick_lines"); + if (shader == nullptr) + return; + + shader->start_using(); + shader->set_uniform("projection_matrix", Transform3d::Identity()); + const std::array& viewport = camera.get_viewport(); + shader->set_uniform("viewport_size", Vec2d(double(viewport[2]), double(viewport[3]))); + shader->set_uniform("width", 1.0f); + shader->set_uniform("gap_size", 0.0f); + } + else +#endif // ENABLE_GL_CORE_PROFILE + glsafe(::glLineWidth(2.0f)); + // stem shader->set_uniform("view_model_matrix", overlap ? ss_to_ndc_matrix * Geometry::translation_transform(v1ss_3) * q12ss * Geometry::translation_transform(-2.0 * TRIANGLE_HEIGHT * Vec3d::UnitX()) * Geometry::scale_transform({ v12ss_len + 4.0 * TRIANGLE_HEIGHT, 1.0f, 1.0f }) : @@ -1043,6 +1062,20 @@ void GLGizmoMeasure::render_dimensioning() m_dimensioning.line.set_color(ColorRGBA::WHITE()); m_dimensioning.line.render(); +#if ENABLE_GL_CORE_PROFILE + if (OpenGLManager::get_gl_info().is_core_profile()) { + shader->stop_using(); + + shader = wxGetApp().get_shader("flat"); + if (shader == nullptr) + return; + + shader->start_using(); + } + else +#endif // ENABLE_GL_CORE_PROFILE + glsafe(::glLineWidth(1.0f)); + // arrow 1 shader->set_uniform("view_model_matrix", overlap ? ss_to_ndc_matrix * Geometry::translation_transform(v1ss_3) * q12ss : @@ -1251,7 +1284,7 @@ void GLGizmoMeasure::render_dimensioning() } }; - auto arc_edge_edge = [this, shader](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2, double radius = 0.0) { + auto arc_edge_edge = [this, &shader](const Measure::SurfaceFeature& f1, const Measure::SurfaceFeature& f2, double radius = 0.0) { assert(f1.get_type() == Measure::SurfaceFeatureType::Edge && f2.get_type() == Measure::SurfaceFeatureType::Edge); if (!m_measurement_result.angle.has_value()) return; @@ -1293,12 +1326,45 @@ void GLGizmoMeasure::render_dimensioning() m_dimensioning.arc.init_from(std::move(init_data)); } - // arc const Camera& camera = wxGetApp().plater()->get_camera(); +#if ENABLE_GL_CORE_PROFILE + if (OpenGLManager::get_gl_info().is_core_profile()) { + shader->stop_using(); + + shader = wxGetApp().get_shader("dashed_thick_lines"); + if (shader == nullptr) + return; + + shader->start_using(); + shader->set_uniform("projection_matrix", Transform3d::Identity()); + const std::array& viewport = camera.get_viewport(); + shader->set_uniform("viewport_size", Vec2d(double(viewport[2]), double(viewport[3]))); + shader->set_uniform("width", 1.0f); + shader->set_uniform("gap_size", 0.0f); + } + else +#endif // ENABLE_GL_CORE_PROFILE + glsafe(::glLineWidth(2.0f)); + + // arc shader->set_uniform("projection_matrix", camera.get_projection_matrix()); shader->set_uniform("view_model_matrix", camera.get_view_matrix() * Geometry::translation_transform(center)); m_dimensioning.arc.render(); +#if ENABLE_GL_CORE_PROFILE + if (OpenGLManager::get_gl_info().is_core_profile()) { + shader->stop_using(); + + shader = wxGetApp().get_shader("flat"); + if (shader == nullptr) + return; + + shader->start_using(); + } + else +#endif // ENABLE_GL_CORE_PROFILE + glsafe(::glLineWidth(1.0f)); + // arrows auto render_arrow = [this, shader, &camera, &normal, ¢er, &e1_unit, draw_radius, step, resolution](unsigned int endpoint_id) { const double angle = (endpoint_id == 1) ? 0.0 : step * double(resolution); From 5d6346f27508b35c58157b9fd11a684971183e73 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 21 Nov 2022 08:37:58 +0100 Subject: [PATCH 60/89] Gizmo Measure - When CTRL+dragging to pan/rotate the scene, do not select the hovered feature, if any --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index d85408f99c..77d816aa76 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -254,6 +254,7 @@ GLGizmoMeasure::GLGizmoMeasure(GLCanvas3D& parent, const std::string& icon_filen bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) { m_mouse_pos = { double(mouse_event.GetX()), double(mouse_event.GetY()) }; + m_dragging = false; if (mouse_event.Moving()) { // only for sure @@ -261,6 +262,8 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) return false; } else if (mouse_event.Dragging()) { + m_dragging = true; + // Enable/Disable panning/rotating the 3D scene // Ctrl is pressed or the mouse is not hovering a selected volume bool unlock_dragging = mouse_event.CmdDown() || (m_hover_id == -1 && !m_parent.get_selection().contains_volume(m_parent.get_first_hover_volume_idx())); @@ -578,7 +581,9 @@ void GLGizmoMeasure::on_render() m_curr_point_on_feature_position.reset(); } else { - std::optional curr_feature = mouse_on_object ? m_measuring->get_feature(model_facet_idx, position_on_model.cast()) : std::nullopt; + std::optional curr_feature = m_dragging ? m_curr_feature : + mouse_on_object ? m_measuring->get_feature(model_facet_idx, position_on_model.cast()) : std::nullopt; + if (m_curr_feature != curr_feature || (curr_feature.has_value() && curr_feature->get_type() == Measure::SurfaceFeatureType::Circle && (m_curr_feature != curr_feature || m_last_inv_zoom != inv_zoom))) { m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, POINT_ID); From 543950bf4bc3dcead2696a555cbe4430226da6dc Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 21 Nov 2022 09:13:28 +0100 Subject: [PATCH 61/89] Gizmo Measure - Use [Delete] key in place of Shift+Right mouse to restart selection --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 13 ++++++------- src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 2 +- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 77d816aa76..2440b5f0a1 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -401,12 +401,6 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) if ((m_mode != EMode::CenterSelection && mouse_event.CmdDown()) || (m_mode == EMode::CenterSelection && m_hover_id != SELECTION_1_ID && m_hover_id != SELECTION_2_ID)) { return false; } - - if (mouse_event.ShiftDown()) { - m_selected_features.reset(); - m_selection_raycasters.clear(); - m_parent.request_extra_frame(); - } } else if (mouse_event.Leaving()) m_mouse_left_down = false; @@ -477,6 +471,11 @@ bool GLGizmoMeasure::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_po m_mode = control_down ? EMode::PointSelection : EMode::FeatureSelection; restore_scene_raycasters_state(); } + else if (action == SLAGizmoEventType::Delete) { + m_selected_features.reset(); + m_selection_raycasters.clear(); + m_parent.request_extra_frame(); + } return true; } @@ -1738,7 +1737,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit } if (m_selected_features.first.feature.has_value()) { - add_strings_row_to_table(*m_imgui, _u8L("Shift") + "+" + _u8L("Right mouse button"), ImGuiWrapper::COL_ORANGE_LIGHT, _u8L("Restart selection"), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + add_strings_row_to_table(*m_imgui, _u8L("Delete"), ImGuiWrapper::COL_ORANGE_LIGHT, _u8L("Restart selection"), ImGui::GetStyleColorVec4(ImGuiCol_Text)); ++row_count; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index 37d1d3de4c..c10741a14e 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -554,7 +554,7 @@ bool GLGizmosManager::on_char(wxKeyEvent& evt) case WXK_BACK: case WXK_DELETE: { - if ((m_current == SlaSupports || m_current == Hollow || m_current == Cut) && gizmo_event(SLAGizmoEventType::Delete)) + if ((m_current == SlaSupports || m_current == Hollow || m_current == Cut || m_current == Measure) && gizmo_event(SLAGizmoEventType::Delete)) processed = true; break; From a03528e55a402358540ad588b3772608ace0355f Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 21 Nov 2022 09:46:30 +0100 Subject: [PATCH 62/89] Gizmo Measure - Added [Restart selection] button to imgui dialog --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 2440b5f0a1..d01b74518d 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -1775,13 +1775,13 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit ImGui::EndTable(); } - //if (m_selected_features.first.feature.has_value()) { - // if (m_imgui->button(_u8L("Restart"))) { - // m_selected_features.reset(); - // m_selection_raycasters.clear(); - // m_imgui->set_requires_extra_frame(); - // } - //} + m_imgui->disabled_begin(!m_selected_features.first.feature.has_value()); + if (m_imgui->button(_u8L("Restart selection"))) { + m_selected_features.reset(); + m_selection_raycasters.clear(); + m_imgui->set_requires_extra_frame(); + } + m_imgui->disabled_end(); auto add_measure_row_to_table = [this](const std::string& col_1, const ImVec4& col_1_color, const std::string& col_2, const ImVec4& col_2_color) { ImGui::TableNextRow(); From ef018318bd8464b5b8a105adf7c8b7b141463900 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 21 Nov 2022 10:26:53 +0100 Subject: [PATCH 63/89] Gizmo Measure - Clicking on 1st selected let second selected to be promoted as first selected --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 27 +++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index d01b74518d..0c8d83fdb6 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -354,6 +354,10 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) else { if (!m_selected_features.second.feature.has_value()) m_selected_features.first.reset(); + else { + m_selected_features.first = m_selected_features.second; + m_selected_features.second.reset(); + } } } else { @@ -853,7 +857,7 @@ void GLGizmoMeasure::on_render() }; auto hover_selection_color = [this]() { - return !m_selected_features.first.feature.has_value() ? SELECTED_1ST_COLOR : SELECTED_2ND_COLOR; + return (!m_selected_features.first.feature.has_value() || *m_curr_feature == *m_selected_features.first.feature) ? SELECTED_1ST_COLOR : SELECTED_2ND_COLOR; }; auto hovering_color = [this, hover_selection_color, &selection]() { @@ -1693,14 +1697,27 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit std::string text; ColorRGBA color; if (m_selected_features.second.feature.has_value()) { - if (m_selected_features.second.feature == m_curr_feature && m_mode == EMode::FeatureSelection) + if (m_selected_features.first.feature == m_curr_feature && m_mode == EMode::FeatureSelection) { text = _u8L("Unselect feature"); - else if (m_hover_id == SELECTION_2_ID) + color = SELECTED_1ST_COLOR; + } + else if (m_selected_features.second.feature == m_curr_feature && m_mode == EMode::FeatureSelection) { + text = _u8L("Unselect feature"); + color = SELECTED_2ND_COLOR; + } + else if (m_hover_id == SELECTION_1_ID) { text = (m_mode == EMode::CenterSelection) ? _u8L("Unselect center") : _u8L("Unselect point"); - else + color = SELECTED_1ST_COLOR; + } + else if (m_hover_id == SELECTION_2_ID) { + text = (m_mode == EMode::CenterSelection) ? _u8L("Unselect center") : _u8L("Unselect point"); + color = SELECTED_2ND_COLOR; + } + else { text = (m_mode == EMode::PointSelection) ? _u8L("Select point") : (m_mode == EMode::CenterSelection) ? _u8L("Select center") : _u8L("Select feature"); - color = SELECTED_2ND_COLOR; + color = SELECTED_2ND_COLOR; + } } else { if (m_selected_features.first.feature.has_value()) { From 38d2e0605a405c703c5a671aad284a9077a966b3 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 21 Nov 2022 11:20:14 +0100 Subject: [PATCH 64/89] Gizmo Measure - Handling of [ESC] key When two features are selected -> unselected second feature When one feature is selected -> unselect first feature When no feature is selected -> close gizmo --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 31 ++++++++++++++++++++++- src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp | 1 + src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 5 +++- 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 0c8d83fdb6..30602b1d49 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -480,6 +480,16 @@ bool GLGizmoMeasure::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_po m_selection_raycasters.clear(); m_parent.request_extra_frame(); } + else if (action == SLAGizmoEventType::Escape) { + if (!m_selected_features.first.feature.has_value()) + return false; + else { + if (m_selected_features.second.feature.has_value()) + m_selected_features.second.feature.reset(); + else + m_selected_features.first.feature.reset(); + } + } return true; } @@ -1758,8 +1768,27 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit ++row_count; } + if (m_selected_features.first.feature.has_value() || m_selected_features.second.feature.has_value()) { + add_row_to_table( + [this]() { + m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, _u8L("Esc")); + }, + [this]() { + m_imgui->text_colored(ImGui::GetStyleColorVec4(ImGuiCol_Text), _u8L("Unselect")); + ImGui::SameLine(); + const ImVec2 pos = ImGui::GetCursorScreenPos(); + const float rect_size = ImGui::GetTextLineHeight(); + const ColorRGBA color = m_selected_features.second.feature.has_value() ? SELECTED_2ND_COLOR : SELECTED_1ST_COLOR; + ImGui::GetWindowDrawList()->AddRectFilled(ImVec2(pos.x + 1.0f, pos.y + 1.0f), ImVec2(pos.x + rect_size, pos.y + rect_size), ImGuiWrapper::to_ImU32(color)); + ImGui::Dummy(ImVec2(rect_size, rect_size)); + } + ); + + ++row_count; + } + // add dummy rows to keep dialog size fixed - for (unsigned int i = row_count; i < 4; ++i) { + for (unsigned int i = row_count; i < 5; ++i) { add_strings_row_to_table(*m_imgui, " ", ImGuiWrapper::COL_ORANGE_LIGHT, " ", ImGui::GetStyleColorVec4(ImGuiCol_Text)); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp index 3878c6b25a..c1b605726c 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.hpp @@ -29,6 +29,7 @@ enum class SLAGizmoEventType : unsigned char { ShiftDown, ShiftUp, AltUp, + Escape, ApplyChanges, DiscardChanges, AutomaticGeneration, diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index c10741a14e..c68a510276 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -526,7 +526,10 @@ bool GLGizmosManager::on_char(wxKeyEvent& evt) case WXK_ESCAPE: { if (m_current != Undefined) { - if ((m_current != SlaSupports) || !gizmo_event(SLAGizmoEventType::DiscardChanges)) + if (m_current == Measure && gizmo_event(SLAGizmoEventType::Escape)) { + // do nothing + } + else if (m_current != SlaSupports || !gizmo_event(SLAGizmoEventType::DiscardChanges)) reset_all_states(); processed = true; From ab5c81a2ef0cac6d688f1b660e76324637ab75ef Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 21 Nov 2022 12:01:22 +0100 Subject: [PATCH 65/89] Gizmo Measure - Fixed point color and hint in dialog when adding a point on a selected feature --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 30602b1d49..29475105df 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -867,7 +867,9 @@ void GLGizmoMeasure::on_render() }; auto hover_selection_color = [this]() { - return (!m_selected_features.first.feature.has_value() || *m_curr_feature == *m_selected_features.first.feature) ? SELECTED_1ST_COLOR : SELECTED_2ND_COLOR; + return ((m_mode == EMode::PointSelection && !m_selected_features.first.feature.has_value()) || + (m_mode != EMode::PointSelection && (!m_selected_features.first.feature.has_value() || *m_curr_feature == *m_selected_features.first.feature))) ? + SELECTED_1ST_COLOR : SELECTED_2ND_COLOR; }; auto hovering_color = [this, hover_selection_color, &selection]() { @@ -1731,11 +1733,14 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit } else { if (m_selected_features.first.feature.has_value()) { - if (m_selected_features.first.feature == m_curr_feature) + if (m_selected_features.first.feature == m_curr_feature && m_mode == EMode::FeatureSelection) { text = _u8L("Unselect feature"); - else if (m_hover_id == SELECTION_1_ID) + color = SELECTED_1ST_COLOR; + } + else if (m_hover_id == SELECTION_1_ID) { text = (m_mode == EMode::CenterSelection) ? _u8L("Unselect center") : _u8L("Unselect point"); - color = SELECTED_1ST_COLOR; + color = SELECTED_1ST_COLOR; + } } if (text.empty()) { text = (m_mode == EMode::PointSelection) ? _u8L("Select point") : From df266798a63d94ee0fc2853b398edee4e3fce330 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 21 Nov 2022 14:44:31 +0100 Subject: [PATCH 66/89] Fixed crash when opening Measure Gizmo after slicing in SLA mode --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 29475105df..6f398d111b 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -968,7 +968,7 @@ void GLGizmoMeasure::update_if_needed() // continue; TriangleMesh volume_mesh = vol.volume->mesh(); - volume_mesh.transform(vol.instance->get_transformation().get_matrix() * vol.volume->get_transformation().get_matrix()); + volume_mesh.transform(vol.world_trafo); composite_mesh.merge(volume_mesh); } @@ -987,10 +987,17 @@ void GLGizmoMeasure::update_if_needed() volumes_cache.reserve(idxs.size()); for (unsigned int idx : idxs) { const GLVolume* v = selection.get_volume(idx); + const int volume_idx = v->volume_idx(); + if (volume_idx < 0) + continue; + const ModelObject* obj = selection.get_model()->objects[v->object_idx()]; const ModelInstance* inst = obj->instances[v->instance_idx()]; - const ModelVolume* vol = obj->volumes[v->volume_idx()]; - const VolumeCacheItem item = { obj, inst, vol, inst->get_matrix() * vol->get_matrix() }; + const ModelVolume* vol = obj->volumes[volume_idx]; + const VolumeCacheItem item = { + obj, inst, vol, + Geometry::translation_transform(selection.get_first_volume()->get_sla_shift_z() * Vec3d::UnitZ()) * inst->get_matrix() * vol->get_matrix() + }; volumes_cache.emplace_back(item); } From cc0901228beecaa3a3187a57b5d3d58737bd4fa8 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 22 Nov 2022 08:34:12 +0100 Subject: [PATCH 67/89] Gizmo measure - Fixed dimensioning after scaling a part of a multipart object --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 6f398d111b..8e32e7e3a5 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -1174,16 +1174,14 @@ void GLGizmoMeasure::render_dimensioning() Vec3d new_pivot; Transform3d scale_matrix; - TrafoData(double ratio, const Vec3d& pivot) { + TrafoData(double ratio, const Vec3d& old_pivot, const Vec3d& new_pivot) { this->ratio = ratio; this->scale_matrix = Geometry::scale_transform(ratio); - this->old_pivot = pivot; - this->new_pivot = { pivot.x(), pivot.y(), (this->scale_matrix * pivot).z() }; + this->old_pivot = old_pivot; + this->new_pivot = new_pivot; } - Vec3d transform(const Vec3d& point) const { - return this->scale_matrix * (point - this->old_pivot) + this->new_pivot; - } + Vec3d transform(const Vec3d& point) const { return this->scale_matrix * (point - this->old_pivot) + this->new_pivot; } }; auto scale_feature = [](Measure::SurfaceFeature& feature, const TrafoData& trafo_data) { @@ -1218,22 +1216,26 @@ void GLGizmoMeasure::render_dimensioning() } }; - const TrafoData trafo_data(ratio, m_parent.get_selection().get_bounding_box().center()); - scale_feature(*m_selected_features.first.feature, trafo_data); - scale_feature(*m_selected_features.second.feature, trafo_data); - + // apply scale TransformationType type; type.set_world(); type.set_relative(); type.set_joint(); - // apply scale + // scale selection Selection& selection = m_parent.get_selection(); + const Vec3d old_center = selection.get_bounding_box().center(); selection.setup_cache(); selection.scale(ratio * Vec3d::Ones(), type); wxGetApp().plater()->canvas3D()->do_scale(""); // avoid storing another snapshot wxGetApp().obj_manipul()->set_dirty(); + // scale dimensioning + const Vec3d new_center = selection.get_bounding_box().center(); + const TrafoData trafo_data(ratio, old_center, new_center); + scale_feature(*m_selected_features.first.feature, trafo_data); + scale_feature(*m_selected_features.second.feature, trafo_data); + // update measure on next call to data_changed() m_pending_scale = true; }; From 87fb1604d88e65b25260a5bdb82f8bcc5c0c86b1 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 22 Nov 2022 12:36:51 +0100 Subject: [PATCH 68/89] Gizmo measure - Fixed incorrect point on feature detection --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 8e32e7e3a5..f4c85a1b54 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -666,7 +666,7 @@ void GLGizmoMeasure::on_render() return trafo * p.cast(); } } - return Vec3d::Zero(); + return Vec3d(DBL_MAX, DBL_MAX, DBL_MAX); }; if (m_curr_feature.has_value()) { @@ -683,8 +683,11 @@ void GLGizmoMeasure::on_render() const std::optional extra = m_curr_feature->get_extra_point(); if (extra.has_value() && m_hover_id == POINT_ID) m_curr_point_on_feature_position = *extra; - else - m_curr_point_on_feature_position = position_on_feature(EDGE_ID, camera, [](const Vec3f& v) { return Vec3f(0.0f, 0.0f, v.z()); }); + else { + const Vec3d pos = position_on_feature(EDGE_ID, camera, [](const Vec3f& v) { return Vec3f(0.0f, 0.0f, v.z()); }); + if (!pos.isApprox(Vec3d(DBL_MAX, DBL_MAX, DBL_MAX))) + m_curr_point_on_feature_position = pos; + } break; } case Measure::SurfaceFeatureType::Plane: @@ -715,6 +718,7 @@ void GLGizmoMeasure::on_render() } } else { + m_curr_point_on_feature_position.reset(); if (m_curr_feature.has_value() && m_curr_feature->get_type() == Measure::SurfaceFeatureType::Circle) { if (update_circle()) { m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_ID); From 36b4a149a48e4f1a3922572656a13c884dc1c5ad Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 22 Nov 2022 13:13:25 +0100 Subject: [PATCH 69/89] Gizmo measure - Fixed calculation of angle edge-plane --- src/libslic3r/Measure.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index 8213f9778d..9105d65c85 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -34,7 +34,7 @@ static std::array orthonormal_basis(const Vec3d& v) std::array ret; ret[2] = v.normalized(); int index; - ret[2].maxCoeff(&index); + ret[2].cwiseAbs().maxCoeff(&index); switch (index) { case 0: { ret[0] = Vec3d(ret[2].y(), -ret[2].x(), 0.0).normalized(); break; } From 786eb4dc530377e67ec62c76b8808c494581475b Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 22 Nov 2022 14:40:35 +0100 Subject: [PATCH 70/89] Follow-up of fdc9c73340060cea7d8335e1211836681e18cae0 - Alternate implementation of 'When panning/rotating the scene, do not select the hovered feature, if any' --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index f4c85a1b54..05374124e6 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -254,7 +254,6 @@ GLGizmoMeasure::GLGizmoMeasure(GLCanvas3D& parent, const std::string& icon_filen bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) { m_mouse_pos = { double(mouse_event.GetX()), double(mouse_event.GetY()) }; - m_dragging = false; if (mouse_event.Moving()) { // only for sure @@ -262,8 +261,6 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) return false; } else if (mouse_event.Dragging()) { - m_dragging = true; - // Enable/Disable panning/rotating the 3D scene // Ctrl is pressed or the mouse is not hovering a selected volume bool unlock_dragging = mouse_event.CmdDown() || (m_hover_id == -1 && !m_parent.get_selection().contains_volume(m_parent.get_first_hover_volume_idx())); @@ -594,7 +591,7 @@ void GLGizmoMeasure::on_render() m_curr_point_on_feature_position.reset(); } else { - std::optional curr_feature = m_dragging ? m_curr_feature : + std::optional curr_feature = wxGetMouseState().LeftIsDown() ? m_curr_feature : mouse_on_object ? m_measuring->get_feature(model_facet_idx, position_on_model.cast()) : std::nullopt; if (m_curr_feature != curr_feature || From dedaa7b49b164717943729f35c5d6f6b9009635c Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 23 Nov 2022 08:24:08 +0100 Subject: [PATCH 71/89] Gizmo measure - Fixed color of hovered features when part of the object is outside the printbed --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 05374124e6..fa8240f8d6 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -752,7 +752,7 @@ void GLGizmoMeasure::on_render() }; auto set_emission_uniform = [this, shader](const ColorRGBA& color, bool hover) { - shader->set_uniform("emission_factor", (color == m_parent.get_selection().get_first_volume()->render_color) ? 0.0f : + shader->set_uniform("emission_factor", (color == GLVolume::SELECTED_COLOR) ? 0.0f : hover ? 0.5f : 0.25f); }; @@ -874,7 +874,7 @@ void GLGizmoMeasure::on_render() }; auto hovering_color = [this, hover_selection_color, &selection]() { - return (m_mode == EMode::PointSelection) ? selection.get_first_volume()->render_color : hover_selection_color(); + return (m_mode == EMode::PointSelection) ? GLVolume::SELECTED_COLOR : hover_selection_color(); }; if (m_curr_feature.has_value()) { From 946bbd285a54ecd389a7f2ef859ca4f82ce9808b Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 23 Nov 2022 09:10:56 +0100 Subject: [PATCH 72/89] Fixed warnings --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index fa8240f8d6..89e6b63ef1 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -751,7 +751,7 @@ void GLGizmoMeasure::on_render() shader->set_uniform("view_normal_matrix", view_normal_matrix); }; - auto set_emission_uniform = [this, shader](const ColorRGBA& color, bool hover) { + auto set_emission_uniform = [shader](const ColorRGBA& color, bool hover) { shader->set_uniform("emission_factor", (color == GLVolume::SELECTED_COLOR) ? 0.0f : hover ? 0.5f : 0.25f); }; @@ -873,7 +873,7 @@ void GLGizmoMeasure::on_render() SELECTED_1ST_COLOR : SELECTED_2ND_COLOR; }; - auto hovering_color = [this, hover_selection_color, &selection]() { + auto hovering_color = [this, hover_selection_color]() { return (m_mode == EMode::PointSelection) ? GLVolume::SELECTED_COLOR : hover_selection_color(); }; From 2b155d593292c78f51e69118fa6fc79cc119cdbc Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 23 Nov 2022 12:03:36 +0100 Subject: [PATCH 73/89] Gizmo measure - Hide SLA supports and pad when opening the gizmo --- src/slic3r/GUI/GLCanvas3D.cpp | 19 +++++++++++++++++-- src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp | 5 +++++ src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 3 +++ 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 991bbead28..345beb4434 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1346,11 +1346,26 @@ void GLCanvas3D::toggle_sla_auxiliaries_visibility(bool visible, const ModelObje m_render_sla_auxiliaries = visible; +#if ENABLE_RAYCAST_PICKING + std::vector>* raycasters = get_raycasters_for_picking(SceneRaycaster::EType::Volume); +#endif // ENABLE_RAYCAST_PICKING + for (GLVolume* vol : m_volumes.volumes) { +#if ENABLE_RAYCAST_PICKING if ((mo == nullptr || m_model->objects[vol->composite_id.object_id] == mo) - && (instance_idx == -1 || vol->composite_id.instance_id == instance_idx) - && vol->composite_id.volume_id < 0) + && (instance_idx == -1 || vol->composite_id.instance_id == instance_idx) + && vol->composite_id.volume_id < 0) { vol->is_active = visible; + auto it = std::find_if(raycasters->begin(), raycasters->end(), [vol](std::shared_ptr item) { return item->get_raycaster() == vol->mesh_raycaster.get(); }); + if (it != raycasters->end()) + (*it)->set_active(vol->is_active); + } +#else + if ((mo == nullptr || m_model->objects[vol->composite_id.object_id] == mo) + && (instance_idx == -1 || vol->composite_id.instance_id == instance_idx) + && vol->composite_id.volume_id < 0) + vol->is_active = visible; +#endif // ENABLE_RAYCAST_PICKING } } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp index 1ce118d71d..51ea56c821 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp @@ -900,6 +900,11 @@ RENDER_AGAIN: bool show_sups = m_c->instances_hider()->are_supports_shown(); if (m_imgui->checkbox(m_desc["show_supports"], show_sups)) { m_c->instances_hider()->show_supports(show_sups); +#if ENABLE_RAYCAST_PICKING + if (show_sups) + // ensure supports and pad are disabled from picking even when they are visible + set_sla_auxiliary_volumes_picking_state(false); +#endif // ENABLE_RAYCAST_PICKING force_refresh = true; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 89e6b63ef1..2de29087b8 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -411,6 +411,8 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) void GLGizmoMeasure::data_changed() { + m_parent.toggle_sla_auxiliaries_visibility(false, nullptr, -1); + update_if_needed(); m_last_inv_zoom = 0.0f; @@ -500,6 +502,7 @@ bool GLGizmoMeasure::on_init() void GLGizmoMeasure::on_set_state() { if (m_state == Off) { + m_parent.toggle_sla_auxiliaries_visibility(true, nullptr, -1); m_ctrl_kar_filter.reset_count(); m_shift_kar_filter.reset_count(); m_curr_feature.reset(); From 3bdd548358735fa75987a6560234470525b649b4 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 23 Nov 2022 12:37:54 +0100 Subject: [PATCH 74/89] Gizmo measure - Undo/Redo related fix --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 9699d73cc8..1672e8b74e 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -159,6 +159,11 @@ public: 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() override { return _u8L("Measure gizmo editing"); } + protected: bool on_init() override; std::string on_get_name() const override; From d4ad4aff01598d60ce0d9e3114e47cd704083b4d Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Tue, 22 Nov 2022 09:49:10 +0100 Subject: [PATCH 75/89] Measurement: Fixed and refactored circle detection: - first/last segment of a circular segment was sometimes separated - circles were sometimes shown where they shouldn't be --- src/libslic3r/Measure.cpp | 236 +++++++++++++++++++------------------- 1 file changed, 120 insertions(+), 116 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index 9105d65c85..a9cea06bdd 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -14,17 +14,17 @@ namespace Measure { constexpr double feature_hover_limit = 0.5; // how close to a feature the mouse must be to highlight it -static std::pair get_center_and_radius(const std::vector& border, int start_idx, int end_idx, const Transform3d& trafo) +static std::pair get_center_and_radius(const std::vector& points, const Transform3d& trafo) { - Vec2ds pts; + Vec2ds out; double z = 0.; - for (int i=start_idx; i<=end_idx; ++i) { - Vec3d pt_transformed = trafo * border[i]; + for (const Vec3d pt : points) { + Vec3d pt_transformed = trafo * pt; z = pt_transformed.z(); - pts.emplace_back(pt_transformed.x(), pt_transformed.y()); + out.emplace_back(pt_transformed.x(), pt_transformed.y()); } - auto circle = Geometry::circle_ransac(pts, 20); // FIXME: iterations? + auto circle = Geometry::circle_ransac(out, 20); // FIXME: iterations? return std::make_pair(trafo.inverse() * Vec3d(circle.center.x(), circle.center.y(), z), circle.radius); } @@ -216,6 +216,7 @@ void MeasuringImpl::update_planes() m_planes[plane_id].borders.pop_back(); else { assert(last_border.front() == last_border.back()); + last_border.pop_back(); } } } @@ -233,6 +234,9 @@ void MeasuringImpl::update_planes() void MeasuringImpl::extract_features() { + auto are_angles_same = [](double a, double b) { return Slic3r::is_approx(a,b); }; + auto are_lengths_same = [](double a, double b) { return Slic3r::is_approx(a,b); }; + std::vector angles; std::vector lengths; @@ -246,152 +250,152 @@ void MeasuringImpl::extract_features() q.setFromTwoVectors(plane.normal, Vec3d::UnitZ()); Transform3d trafo = Transform3d::Identity(); trafo.rotate(q); - + for (const std::vector& border : plane.borders) { if (border.size() <= 1) continue; - assert(border.front() == border.back()); - int start_idx = -1; - std::vector edges; + // Given an idx into border, return the index that is idx+offset position, + // while taking into account the need for warp-around and the fact that + // the first and last point are the same. + auto offset_to_index = [border_size = int(border.size())](int idx, int offset) -> int { + assert(std::abs(offset) < border_size); + int out = idx+offset; + if (out >= border_size) + out = out - border_size; + else if (out < 0) + out = border_size + out; + + return out; + }; // First calculate angles at all the vertices. angles.clear(); lengths.clear(); - for (int i=0; i M_PI) angle = 2*M_PI - angle; angles.push_back(angle); lengths.push_back(v2.norm()); + if (first_different_angle_idx == 0 && angles.size() > 1) { + if (! are_angles_same(angles.back(), angles[angles.size()-2])) + first_different_angle_idx = angles.size()-1; + } } assert(border.size() == angles.size()); assert(border.size() == lengths.size()); - // First go around the border and pick what might be circular segments. // Save pair of indices to where such potential segments start and end. // Also remember the length of these segments. + int start_idx = -1; bool circle = false; + bool first_iter = true; std::vector circles; + std::vector edges; std::vector> circles_idxs; - std::vector circles_lengths; - for (int i=1; i<(int)angles.size(); ++i) { - if (Slic3r::is_approx(lengths[i], lengths[i-1]) - && Slic3r::is_approx(angles[i], angles[i-1]) - && i != (int)angles.size()-1 ) { + //std::vector circles_lengths; + std::vector single_circle; // could be in loop-scope, but reallocations + double single_circle_length = 0.; + int first_pt_idx = offset_to_index(first_different_angle_idx, 1); + int i = first_pt_idx; + while (i != first_pt_idx || first_iter) { + if (are_angles_same(angles[i], angles[offset_to_index(i,-1)]) + && i != offset_to_index(first_pt_idx, -1) // not the last point + && i != start_idx ) { // circle if (! circle) { circle = true; - start_idx = std::max(0, i-2); + single_circle.clear(); + single_circle_length = 0.; + start_idx = offset_to_index(i, -2); + single_circle = { border[start_idx], border[offset_to_index(start_idx,1)] }; + single_circle_length += lengths[offset_to_index(i, -1)]; } + single_circle.emplace_back(border[i]); + single_circle_length += lengths[i]; } else { - if (circle) { - const auto& [center, radius] = get_center_and_radius(border, start_idx, i, trafo); - // Add the circle and remember indices into borders. - circles_idxs.emplace_back(start_idx, i); - circles.emplace_back(SurfaceFeature(SurfaceFeatureType::Circle, center, plane.normal, std::nullopt, radius)); - circles_lengths.emplace_back(std::accumulate(lengths.begin() + start_idx + 1, lengths.begin() + i + 1, 0.)); - circle = false; - } - } - } + if (circle && single_circle.size() >= 5) { // Less than 5 vertices? Not a circle. + single_circle.emplace_back(border[i]); + single_circle_length += lengths[i]; - // At this point we might need to merge the first and last segment, if the starting - // point happened to be inside the segment. The discrimination of too small segments - // will follow, so we need a complete picture before that. - if (circles_idxs.size() > 1 - && circles_idxs.back().second == (int)angles.size()-1 - && circles_idxs.front().first == 0) { - // Possibly the same circle. Check that the angle and length criterion holds along the combined segment. - bool same = true; - double last_len = -1.; - double last_angle = 0.; - for (int i=circles_idxs.back().first + 1; i != circles_idxs.front().second; ++i) { - if (i == (int)angles.size()) - i = 1; - if (last_len == -1.) { - last_len = lengths[i]; - last_angle = angles[i]; - } else { - if (! Slic3r::is_approx(lengths[i], last_len) || ! Slic3r::is_approx(angles[i], last_angle)) { - same = false; - break; + bool accept_circle = true; + { + // Check that lengths of internal (!!!) edges match. + int j = offset_to_index(start_idx, 3); + while (j != i) { + if (! are_lengths_same(lengths[offset_to_index(j,-1)], lengths[j])) { + accept_circle = false; + break; + } + j = offset_to_index(j, 1); + } + } + + if (accept_circle) { + const auto& [center, radius] = get_center_and_radius(single_circle, trafo); + + // Check that the fit went well. The tolerance is high, only to + // reject complete failures. + for (const Vec3d& pt : single_circle) { + if (std::abs((pt - center).norm() - radius) > 0.5) { + accept_circle = false; + break; + } + } + + // If the segment subtends less than 90 degrees, throw it away. + accept_circle &= single_circle_length / radius > 0.9*M_PI/2.; + + // If this is all-around and 5 to 8 vertices, consider it a polygon. + bool is_polygon = start_idx == i && single_circle.size() <= 9 && single_circle.size() >= 6; + + if (accept_circle) { + // Add the circle and remember indices into borders. + circles_idxs.emplace_back(start_idx, i); + if (is_polygon) { + for (int j=0; j<=i; ++j) // No wrap-around handling needed here. + edges.emplace_back(SurfaceFeature(SurfaceFeatureType::Edge, + border[j==0 ? border.size()-1 : j-1], border[j], + std::make_optional(center))); + } + else + circles.emplace_back(SurfaceFeature(SurfaceFeatureType::Circle, center, plane.normal, std::nullopt, radius)); + } } } + circle = false; } - if (same) { - // This seems to really be the same circle. Better apply ransac again. The parts can be small and inexact. - std::vector points(border.begin() + circles_idxs.back().first, border.end()); - points.insert(points.end(), border.begin(), border.begin() + circles_idxs.front().second+1); - auto [c, radius] = get_center_and_radius(points, 0, points.size()-1, trafo); - - // Now replace the first circle with the combined one, remove the last circle. - // First index of the first circle is saved negative - we are going to pick edges - // from the border later, we will need to know where the merged in segment was. - // The sign simplifies the algorithm that picks the remaining edges - see below. - circles.front() = SurfaceFeature(SurfaceFeatureType::Circle, c, plane.normal, std::nullopt, radius); - circles_idxs.front().first = - circles_idxs.back().first; - circles_lengths.front() += circles_lengths.back(); - circles.pop_back(); - circles_idxs.pop_back(); - circles_lengths.pop_back(); - } - } - - // Now throw away all circles that subtend less than 90 deg. - assert(circles.size() == circles_lengths.size()); - for (int i=0; i(circles[i].get_circle()); - if (circles_lengths[i] / r < 0.9*M_PI/2.) { - circles_lengths.erase(circles_lengths.begin() + i); - circles.erase(circles.begin() + i); - circles_idxs.erase(circles_idxs.begin() + i); - --i; - } + // Take care of the wrap around. + first_iter = false; + i = offset_to_index(i, 1); } - circles_lengths.clear(); // no longer needed, make it obvious - - // Anything under 5 vertices shall not be considered a circle. - assert(circles_idxs.size() == circles.size()); - for (int i=int(circles_idxs.size())-1; i>=0; --i) { - const auto& [start, end] = circles_idxs[i]; - int N = start >= 0 - ? end - start + (start == 0 && end == (int)border.size()-1 ? 0 : 1) // last point is the same as first - : end + (border.size() + start); - if (N < 5) { - circles.erase(circles.begin() + i); - circles_idxs.erase(circles_idxs.begin() + i); - } else if (N <= 8 && start == 0 && end == (int)border.size()-1) { - // This is a regular 5-8 polygon. Add the edges as edges with a special - // point and remove the circle. Leave the indices in circles_idxs, so - // the edges are not picked up again later. - const Vec3d center = std::get<0>(circles[i].get_circle()); - for (int j=1; j<=end; ++j) - edges.emplace_back(SurfaceFeature(SurfaceFeatureType::Edge, - border[j - 1], border[j], std::make_optional(center))); - circles.erase(circles.begin() + i); - } - } - // We have the circles. Now go around again and pick edges, while jumping over circles. - // If the first index of the first circle is negative, it means that it was merged - // with a segment that was originally at the back and is no longer there. Ressurect - // its pair of indices so that edges are not picked again. - if (! circles_idxs.empty() && circles_idxs.front().first < 0) - circles_idxs.emplace_back(-circles_idxs.front().first, int(border.size())); - int cidx = 0; // index of next circle to jump over - for (int i=1; i (int)circles_idxs[cidx].first) - i = circles_idxs[cidx++].second; - else - edges.emplace_back(SurfaceFeature(SurfaceFeatureType::Edge, border[i - 1], border[i])); + if (circles_idxs.empty()) { + // Just add all edges. + for (int i=1; i Date: Fri, 25 Nov 2022 13:45:23 +0100 Subject: [PATCH 76/89] Measurement: prevent ending up in an infinite loop with broken models --- src/libslic3r/Measure.cpp | 16 ++++++++++++++-- src/libslic3r/SurfaceMesh.hpp | 9 +++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index a9cea06bdd..37bf68e83d 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -189,10 +189,16 @@ void MeasuringImpl::update_planes() he = sm.next_around_target(he); if (he.is_invalid()) goto PLANE_FAILURE; + + // For broken meshes, the iteration might never get back to he_orig. + // Remember all halfedges we saw to break out of such infinite loops. + boost::container::small_vector he_seen; + while ( (int)m_face_to_plane[sm.face(he)] == plane_id && he != he_orig) { + he_seen.emplace_back(he); he = sm.next_around_target(he); - if (he.is_invalid()) - goto PLANE_FAILURE; + if (he.is_invalid() || std::find(he_seen.begin(), he_seen.end(), he) != he_seen.end()) + goto PLANE_FAILURE; } he = sm.opposite(he); if (he.is_invalid()) @@ -210,6 +216,12 @@ void MeasuringImpl::update_planes() visited[face_it - facets.begin()][he.side()] = true; last_border.emplace_back(sm.point(sm.source(he)).cast()); + + // In case of broken meshes, this loop might be infinite. Break + // out in case it is clearly going bad. + if (last_border.size() > 3*facets.size()) + goto PLANE_FAILURE; + } while (he != he_start); if (last_border.size() == 1) diff --git a/src/libslic3r/SurfaceMesh.hpp b/src/libslic3r/SurfaceMesh.hpp index 9e547eec49..93eb9fdaa6 100644 --- a/src/libslic3r/SurfaceMesh.hpp +++ b/src/libslic3r/SurfaceMesh.hpp @@ -4,6 +4,8 @@ #include #include +#include "boost/container/small_vector.hpp" + namespace Slic3r { class TriangleMesh; @@ -115,11 +117,18 @@ public: size_t degree(Vertex_index v) const { + // In case the mesh is broken badly, the loop might end up to be infinite, + // never getting back to the first halfedge. Remember list of all half-edges + // and trip if any is encountered for the second time. Halfedge_index h_first = halfedge(v); + boost::container::small_vector he_visited; Halfedge_index h = next_around_target(h_first); size_t degree = 2; while (! h.is_invalid() && h != h_first) { + he_visited.emplace_back(h); h = next_around_target(h); + if (std::find(he_visited.begin(), he_visited.end(), h) == he_visited.end()) + return 0; ++degree; } return h.is_invalid() ? 0 : degree - 1; From 8ef55ff82eabe498e0f08fe1cd7f02afedda20de Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 29 Nov 2022 11:13:09 +0100 Subject: [PATCH 77/89] Tech ENABLE_RAYCAST_PICKING_DEBUG - Extended data shown into debug imgui dialog --- src/slic3r/GUI/GLCanvas3D.cpp | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 345beb4434..9f2e7c0dad 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -5542,12 +5542,17 @@ void GLCanvas3D::_picking_pass() default: { break; } } - auto add_strings_row_to_table = [&imgui](const std::string& col_1, const ImVec4& col_1_color, const std::string& col_2, const ImVec4& col_2_color) { + auto add_strings_row_to_table = [&imgui](const std::string& col_1, const ImVec4& col_1_color, const std::string& col_2, const ImVec4& col_2_color, + const std::string& col_3 = "", const ImVec4& col_3_color = ImGui::GetStyleColorVec4(ImGuiCol_Text)) { ImGui::TableNextRow(); ImGui::TableSetColumnIndex(0); imgui.text_colored(col_1_color, col_1.c_str()); ImGui::TableSetColumnIndex(1); imgui.text_colored(col_2_color, col_2.c_str()); + if (!col_3.empty()) { + ImGui::TableSetColumnIndex(2); + imgui.text_colored(col_3_color, col_3.c_str()); + } }; char buf[1024]; @@ -5576,6 +5581,21 @@ void GLCanvas3D::_picking_pass() add_strings_row_to_table("Gizmo elements", ImGuiWrapper::COL_ORANGE_LIGHT, std::string(buf), ImGui::GetStyleColorVec4(ImGuiCol_Text)); ImGui::EndTable(); } + + std::vector>* gizmo_raycasters = m_scene_raycaster.get_raycasters(SceneRaycaster::EType::Gizmo); + if (gizmo_raycasters != nullptr && !gizmo_raycasters->empty()) { + ImGui::Separator(); + imgui.text("Gizmo raycasters IDs:"); + if (ImGui::BeginTable("GizmoRaycasters", 3)) { + for (size_t i = 0; i < gizmo_raycasters->size(); ++i) { + add_strings_row_to_table(std::to_string(i), ImGuiWrapper::COL_ORANGE_LIGHT, + std::to_string(SceneRaycaster::decode_id(SceneRaycaster::EType::Gizmo, (*gizmo_raycasters)[i]->get_id())), ImGui::GetStyleColorVec4(ImGuiCol_Text), + to_string(Geometry::Transformation((*gizmo_raycasters)[i]->get_transform()).get_offset()), ImGui::GetStyleColorVec4(ImGuiCol_Text)); + } + ImGui::EndTable(); + } + } + imgui.end(); #endif // ENABLE_RAYCAST_PICKING_DEBUG } From b45ae31af3be42f5b04dd0c6ea87cb0db505c044 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 30 Nov 2022 11:58:02 +0100 Subject: [PATCH 78/89] Gizmo measure - Modified circle and edge with extra point selection Fixed conflicts during rebase to master --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 510 ++++++++++++++--------- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 18 +- 2 files changed, 320 insertions(+), 208 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 2de29087b8..43d55addda 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -20,15 +20,16 @@ namespace Slic3r { namespace GUI { -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 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 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 SELECTION_1_ID = 501; -static const int SELECTION_2_ID = 502; +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; @@ -164,6 +165,41 @@ static GLModel::Geometry init_torus_data(unsigned int primary_resolution, unsign return data; } +static bool is_feature_with_center(const Measure::SurfaceFeature& feature) +{ + const Measure::SurfaceFeatureType type = feature.get_type(); + return (type == Measure::SurfaceFeatureType::Circle || (type == Measure::SurfaceFeatureType::Edge && feature.get_extra_point().has_value())); +} + +static Vec3d get_feature_offset(const Measure::SurfaceFeature& feature) +{ + Vec3d ret; + switch (feature.get_type()) + { + case Measure::SurfaceFeatureType::Circle: + { + const auto [center, radius, normal] = feature.get_circle(); + ret = center; + break; + } + case Measure::SurfaceFeatureType::Edge: + { + std::optional p = feature.get_extra_point(); + assert(p.has_value()); + ret = *p; + break; + } + case Measure::SurfaceFeatureType::Point: + { + ret = feature.get_point(); + break; + } + default: { assert(false); } + } + + return ret; +} + class TransformHelper { struct Cache @@ -265,109 +301,125 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) // Ctrl is pressed or the mouse is not hovering a selected volume bool unlock_dragging = mouse_event.CmdDown() || (m_hover_id == -1 && !m_parent.get_selection().contains_volume(m_parent.get_first_hover_volume_idx())); // mode is not center selection or mouse is not hovering a center - unlock_dragging &= !mouse_event.ShiftDown() || (m_hover_id != SELECTION_1_ID && m_hover_id != SELECTION_2_ID && m_hover_id != POINT_ID); + unlock_dragging &= !mouse_event.ShiftDown() || (m_hover_id != SEL_SPHERE_1_ID && m_hover_id != SEL_SPHERE_2_ID && m_hover_id != POINT_ID); return !unlock_dragging; } else if (mouse_event.LeftDown()) { // let the event pass through to allow panning/rotating the 3D scene - if ((m_mode != EMode::CenterSelection && mouse_event.CmdDown()) || - (m_mode == EMode::CenterSelection && m_hover_id != SELECTION_1_ID && m_hover_id != SELECTION_2_ID && m_hover_id != POINT_ID)) { + if (mouse_event.CmdDown()) return false; - } if (m_hover_id != -1) { SelectedFeatures selected_features_old = m_selected_features; m_mouse_left_down = true; - auto item_from_feature = [this]() { + auto detect_current_item = [this]() { SelectedFeatures::Item item; - if (m_hover_id == SELECTION_1_ID && m_selected_features.first.feature.has_value()) - item = m_selected_features.first; - else if (m_hover_id == SELECTION_2_ID && m_selected_features.second.feature.has_value()) - item = m_selected_features.second; + if (m_hover_id == SEL_SPHERE_1_ID) { + if (m_selected_features.first.is_center) + // mouse is hovering over a selected center + item = { true, m_selected_features.first.source, { Measure::SurfaceFeature(get_feature_offset(*m_selected_features.first.source)) } }; + else if (is_feature_with_center(*m_selected_features.first.feature)) + // mouse is hovering over a unselected center + item = { true, m_selected_features.first.feature, { Measure::SurfaceFeature(get_feature_offset(*m_selected_features.first.feature)) } }; + else + // mouse is hovering over a point + item = m_selected_features.first; + } + else if (m_hover_id == SEL_SPHERE_2_ID) { + if (m_selected_features.second.is_center) + // mouse is hovering over a selected center + item = { true, m_selected_features.second.source, { Measure::SurfaceFeature(get_feature_offset(*m_selected_features.second.source)) } }; + else if (is_feature_with_center(*m_selected_features.second.feature)) + // mouse is hovering over a center + item = { true, m_selected_features.second.feature, { Measure::SurfaceFeature(get_feature_offset(*m_selected_features.second.feature)) } }; + else + // mouse is hovering over a point + item = m_selected_features.second; + } else { switch (m_mode) { - case EMode::FeatureSelection: - { - item = { surface_feature_type_as_string(m_curr_feature->get_type()), m_curr_feature }; - break; - } - case EMode::PointSelection: - { - item = { point_on_feature_type_as_string(m_curr_feature->get_type(), m_hover_id), Measure::SurfaceFeature(*m_curr_point_on_feature_position) }; - break; - } - case EMode::CenterSelection: - { - Vec3d position; - switch (m_curr_feature->get_type()) - { - case Measure::SurfaceFeatureType::Circle: - { - position = std::get<0>(m_curr_feature->get_circle()); - break; - } - case Measure::SurfaceFeatureType::Edge: - { - assert(m_curr_feature->get_extra_point().has_value()); - position = *m_curr_feature->get_extra_point(); - break; - } - default: { assert(false); break; } - } - - item = { center_on_feature_type_as_string(m_curr_feature->get_type()), Measure::SurfaceFeature(position) }; - break; - } + case EMode::FeatureSelection: { item = { false, m_curr_feature, m_curr_feature }; break; } + case EMode::PointSelection: { item = { false, m_curr_feature, Measure::SurfaceFeature(*m_curr_point_on_feature_position) }; break; } } } return item; }; - if (m_selected_features.first.feature.has_value()) { - auto it = std::find_if(m_selection_raycasters.begin(), m_selection_raycasters.end(), - [](std::shared_ptr item) { return SceneRaycaster::decode_id(SceneRaycaster::EType::Gizmo, item->get_id()) == SELECTION_2_ID; }); - if (it != m_selection_raycasters.end()) - m_selection_raycasters.erase(it); - m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, SELECTION_2_ID); + auto requires_sphere_raycaster_for_picking = [this](const SelectedFeatures::Item& item) { + if (m_mode == EMode::PointSelection) + return true; + else if (m_mode == EMode::FeatureSelection) { + if (is_feature_with_center(*item.feature)) + return true; + } + return false; + }; - const SelectedFeatures::Item item = item_from_feature(); + if (m_selected_features.first.feature.has_value()) { + const SelectedFeatures::Item item = detect_current_item(); if (m_selected_features.first != item) { - if (m_selected_features.second == item) - m_selected_features.second.reset(); - else { - m_selected_features.second = item; - if (m_mode == EMode::PointSelection || m_mode == EMode::CenterSelection) - m_selection_raycasters.push_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, SELECTION_2_ID, *m_sphere.mesh_raycaster)); - if (m_mode == EMode::CenterSelection) { - // Fake ctrl up event to exit the center selection mode - gizmo_event(SLAGizmoEventType::CtrlUp, Vec2d::Zero(), true, false, false); - // increase counter to avoid that keeping the ctrl key pressed triggers a ctrl down event - m_ctrl_kar_filter.increase_count(); + bool processed = false; + if (item.is_center) { + if (item.source == m_selected_features.first.feature) { + // switch 1st selection from feature to its center + m_selected_features.first = item; + processed = true; + } + else if (item.source == m_selected_features.second.feature) { + // switch 2nd selection from feature to its center + m_selected_features.second = item; + processed = true; + } + } + else if (is_feature_with_center(*item.feature)) { + if (m_selected_features.first.is_center && m_selected_features.first.source == item.feature) { + // switch 1st selection from center to its feature + m_selected_features.first = item; + processed = true; + } + else if (m_selected_features.second.is_center && m_selected_features.second.source == item.feature) { + // switch 2nd selection from center to its feature + m_selected_features.second = item; + processed = true; + } + } + + if (!processed) { + remove_selected_sphere_raycaster(SEL_SPHERE_2_ID); + if (m_selected_features.second == item) + // 2nd feature deselection + m_selected_features.second.reset(); + else { + // 2nd feature selection + m_selected_features.second = item; + if (requires_sphere_raycaster_for_picking(item)) + m_selected_sphere_raycasters.push_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, SEL_SPHERE_2_ID, *m_sphere.mesh_raycaster)); } } } else { - if (!m_selected_features.second.feature.has_value()) - m_selected_features.first.reset(); - else { + remove_selected_sphere_raycaster(SEL_SPHERE_1_ID); + if (m_selected_features.second.feature.has_value()) { + // promote 2nd feature to 1st feature + remove_selected_sphere_raycaster(SEL_SPHERE_2_ID); m_selected_features.first = m_selected_features.second; + if (requires_sphere_raycaster_for_picking(m_selected_features.first)) + m_selected_sphere_raycasters.push_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, SEL_SPHERE_1_ID, *m_sphere.mesh_raycaster)); m_selected_features.second.reset(); } + else + // 1st feature deselection + m_selected_features.first.reset(); } } else { - const SelectedFeatures::Item item = item_from_feature(); + // 1st feature selection + const SelectedFeatures::Item item = detect_current_item(); m_selected_features.first = item; - if (m_mode == EMode::PointSelection || m_mode == EMode::CenterSelection) - m_selection_raycasters.push_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, SELECTION_1_ID, *m_sphere.mesh_raycaster)); - if (m_mode == EMode::CenterSelection) { - // Fake ctrl up event to exit the center selection mode - gizmo_event(SLAGizmoEventType::CtrlUp, Vec2d::Zero(), true, false, false); - // increase counter to avoid that keeping the ctrl key pressed triggers a ctrl down event - m_ctrl_kar_filter.increase_count(); - } + if (requires_sphere_raycaster_for_picking(item)) + m_selected_sphere_raycasters.push_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, SEL_SPHERE_1_ID, *m_sphere.mesh_raycaster)); } if (m_selected_features != selected_features_old && m_selected_features.second.feature.has_value()) @@ -399,9 +451,8 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) } else if (mouse_event.RightDown()) { // let the event pass through to allow panning/rotating the 3D scene - if ((m_mode != EMode::CenterSelection && mouse_event.CmdDown()) || (m_mode == EMode::CenterSelection && m_hover_id != SELECTION_1_ID && m_hover_id != SELECTION_2_ID)) { + if (mouse_event.CmdDown()) return false; - } } else if (mouse_event.Leaving()) m_mouse_left_down = false; @@ -423,7 +474,7 @@ void GLGizmoMeasure::data_changed() } else m_selected_features.reset(); - m_selection_raycasters.clear(); + m_selected_sphere_raycasters.clear(); m_editing_distance = false; m_is_editing_distance_first_frame = true; } @@ -450,7 +501,7 @@ bool GLGizmoMeasure::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_po if (action == SLAGizmoEventType::ShiftDown) { if (m_shift_kar_filter.is_first()) { - m_mode = activate_center_selection(SLAGizmoEventType::ShiftDown) ? EMode::CenterSelection : EMode::PointSelection; + m_mode = EMode::PointSelection; disable_scene_raycasters(); } m_shift_kar_filter.increase_count(); @@ -460,33 +511,23 @@ bool GLGizmoMeasure::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_po m_mode = EMode::FeatureSelection; restore_scene_raycasters_state(); } - else if (action == SLAGizmoEventType::CtrlDown) { - if (m_ctrl_kar_filter.is_first()) { - if (activate_center_selection(SLAGizmoEventType::CtrlDown)) { - m_mode = EMode::CenterSelection; - disable_scene_raycasters(); - } - } - m_ctrl_kar_filter.increase_count(); - } - else if (action == SLAGizmoEventType::CtrlUp) { - m_ctrl_kar_filter.reset_count(); - m_mode = control_down ? EMode::PointSelection : EMode::FeatureSelection; - restore_scene_raycasters_state(); - } else if (action == SLAGizmoEventType::Delete) { m_selected_features.reset(); - m_selection_raycasters.clear(); + m_selected_sphere_raycasters.clear(); m_parent.request_extra_frame(); } else if (action == SLAGizmoEventType::Escape) { if (!m_selected_features.first.feature.has_value()) return false; else { - if (m_selected_features.second.feature.has_value()) - m_selected_features.second.feature.reset(); - else - m_selected_features.first.feature.reset(); + if (m_selected_features.second.feature.has_value()) { + remove_selected_sphere_raycaster(SEL_SPHERE_2_ID); + m_selected_features.second.feature.reset(); + } + else { + remove_selected_sphere_raycaster(SEL_SPHERE_1_ID); + m_selected_features.first.feature.reset(); + } } } @@ -503,7 +544,6 @@ void GLGizmoMeasure::on_set_state() { if (m_state == Off) { m_parent.toggle_sla_auxiliaries_visibility(true, nullptr, -1); - m_ctrl_kar_filter.reset_count(); m_shift_kar_filter.reset_count(); m_curr_feature.reset(); m_curr_point_on_feature_position.reset(); @@ -566,7 +606,7 @@ void GLGizmoMeasure::on_render() Vec3f normal_on_model; size_t model_facet_idx; const bool mouse_on_object = m_raycaster->unproject_on_mesh(m_mouse_pos, Transform3d::Identity(), camera, position_on_model, normal_on_model, nullptr, &model_facet_idx); - const bool is_hovering_on_feature = (m_mode == EMode::PointSelection || m_mode == EMode::CenterSelection) && m_hover_id != -1; + const bool is_hovering_on_feature = m_mode == EMode::PointSelection && m_hover_id != -1; auto update_circle = [this, inv_zoom]() { if (m_last_inv_zoom != inv_zoom || m_last_circle != m_curr_feature) { @@ -583,14 +623,13 @@ void GLGizmoMeasure::on_render() }; if (m_mode == EMode::FeatureSelection || m_mode == EMode::PointSelection) { - if ((m_hover_id == SELECTION_1_ID && boost::algorithm::istarts_with(m_selected_features.first.source, _u8L("Center"))) || - (m_hover_id == SELECTION_2_ID && boost::algorithm::istarts_with(m_selected_features.second.source, _u8L("Center")))) { - // Skip feature detection if hovering on a selected center - m_curr_feature.reset(); + if (m_hover_id == SEL_SPHERE_1_ID || m_hover_id == SEL_SPHERE_2_ID) { + // Skip feature detection if hovering on a selected point/center m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, POINT_ID); m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, EDGE_ID); m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, PLANE_ID); m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_ID); + m_curr_feature.reset(); m_curr_point_on_feature_position.reset(); } else { @@ -618,15 +657,12 @@ void GLGizmoMeasure::on_render() case Measure::SurfaceFeatureType::Edge: { m_raycasters.insert({ EDGE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, EDGE_ID, *m_cylinder.mesh_raycaster) }); - if (m_curr_feature->get_extra_point().has_value()) - m_raycasters.insert({ POINT_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, POINT_ID, *m_sphere.mesh_raycaster) }); break; } case Measure::SurfaceFeatureType::Circle: { update_circle(); m_raycasters.insert({ CIRCLE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_ID, *m_circle.mesh_raycaster) }); - m_raycasters.insert({ POINT_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, POINT_ID, *m_sphere.mesh_raycaster) }); break; } case Measure::SurfaceFeatureType::Plane: @@ -781,72 +817,69 @@ void GLGizmoMeasure::on_render() case Measure::SurfaceFeatureType::Circle: { const auto& [center, radius, normal] = feature.get_circle(); - // render center + // render circle + const Transform3d circle_matrix = Transform3d::Identity(); + set_matrix_uniforms(circle_matrix); if (update_raycasters_transform) { + set_emission_uniform(colors.front(), hover); + m_circle.model.set_color(colors.front()); + m_circle.model.render(); + auto it = m_raycasters.find(CIRCLE_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(circle_matrix); + } + else { + GLModel circle; + GLModel::Geometry circle_geometry = init_torus_data(64, 16, center.cast(), float(radius), 5.0f * inv_zoom, normal.cast(), Transform3f::Identity()); + circle.init_from(std::move(circle_geometry)); + set_emission_uniform(colors.front(), hover); + circle.set_color(colors.front()); + circle.render(); + } + // render center + if (colors.size() > 1) { const Transform3d center_matrix = Geometry::translation_transform(center) * Geometry::scale_transform(inv_zoom); set_matrix_uniforms(center_matrix); - set_emission_uniform(colors.front(), hover); - m_sphere.model.set_color(colors.front()); + set_emission_uniform(colors.back(), hover); + m_sphere.model.set_color(colors.back()); m_sphere.model.render(); auto it = m_raycasters.find(POINT_ID); if (it != m_raycasters.end() && it->second != nullptr) it->second->set_transform(center_matrix); } - // render circle - if (m_mode != EMode::CenterSelection) { - const Transform3d circle_matrix = Transform3d::Identity(); - set_matrix_uniforms(circle_matrix); - if (update_raycasters_transform) { - set_emission_uniform(colors.back(), hover); - m_circle.model.set_color(colors.back()); - m_circle.model.render(); - auto it = m_raycasters.find(CIRCLE_ID); - if (it != m_raycasters.end() && it->second != nullptr) - it->second->set_transform(circle_matrix); - } - else { - GLModel circle; - GLModel::Geometry circle_geometry = init_torus_data(64, 16, center.cast(), float(radius), 5.0f * inv_zoom, normal.cast(), Transform3f::Identity()); - circle.init_from(std::move(circle_geometry)); - set_emission_uniform(colors.back(), hover); - circle.set_color(colors.back()); - circle.render(); - } - } break; } case Measure::SurfaceFeatureType::Edge: { const auto& [from, to] = feature.get_edge(); - // render extra point + // render edge + const Transform3d edge_matrix = Geometry::translation_transform(from) * + Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), to - from) * + Geometry::scale_transform({ (double)inv_zoom, (double)inv_zoom, (to - from).norm() }); + set_matrix_uniforms(edge_matrix); + set_emission_uniform(colors.front(), hover); + m_cylinder.model.set_color(colors.front()); + m_cylinder.model.render(); if (update_raycasters_transform) { + auto it = m_raycasters.find(EDGE_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(edge_matrix); + } + + // render extra point + if (colors.size() > 1) { const std::optional extra = feature.get_extra_point(); if (extra.has_value()) { const Transform3d point_matrix = Geometry::translation_transform(*extra) * Geometry::scale_transform(inv_zoom); set_matrix_uniforms(point_matrix); - set_emission_uniform(colors.front(), hover); - m_sphere.model.set_color(colors.front()); + set_emission_uniform(colors.back(), hover); + m_sphere.model.set_color(colors.back()); m_sphere.model.render(); auto it = m_raycasters.find(POINT_ID); if (it != m_raycasters.end() && it->second != nullptr) it->second->set_transform(point_matrix); } } - // render edge - if (m_mode != EMode::CenterSelection) { - const Transform3d edge_matrix = Geometry::translation_transform(from) * - Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), to - from) * - Geometry::scale_transform({ (double)inv_zoom, (double)inv_zoom, (to - from).norm() }); - set_matrix_uniforms(edge_matrix); - set_emission_uniform(colors.back(), hover); - m_cylinder.model.set_color(colors.back()); - m_cylinder.model.render(); - if (update_raycasters_transform) { - auto it = m_raycasters.find(EDGE_ID); - if (it != m_raycasters.end() && it->second != nullptr) - it->second->set_transform(edge_matrix); - } - } break; } case Measure::SurfaceFeatureType::Plane: @@ -881,11 +914,31 @@ void GLGizmoMeasure::on_render() }; if (m_curr_feature.has_value()) { + // render hovered feature + std::vector colors; - if (m_selected_features.first.feature.has_value() && *m_curr_feature == *m_selected_features.first.feature) - colors.emplace_back(hovering_color()); - else if (m_selected_features.second.feature.has_value() && *m_curr_feature == *m_selected_features.second.feature) - colors.emplace_back(hovering_color()); + if (m_selected_features.first.feature.has_value() && *m_curr_feature == *m_selected_features.first.feature) { + // hovering over the 1st selected feature + if (m_selected_features.first.is_center) + // hovering over a center + colors = { NEUTRAL_COLOR, hovering_color() }; + else if (is_feature_with_center(*m_selected_features.first.feature)) + // hovering over a feature with center + colors = { hovering_color(), NEUTRAL_COLOR }; + else + colors = { hovering_color() }; + } + else if (m_selected_features.second.feature.has_value() && *m_curr_feature == *m_selected_features.second.feature) { + // hovering over the 2nd selected feature + if (m_selected_features.second.is_center) + // hovering over a center + colors = { NEUTRAL_COLOR, hovering_color() }; + else if (is_feature_with_center(*m_selected_features.second.feature)) + // hovering over a feature with center + colors = { hovering_color(), NEUTRAL_COLOR }; + else + colors = { hovering_color() }; + } else { switch (m_curr_feature->get_type()) { @@ -898,8 +951,12 @@ void GLGizmoMeasure::on_render() case Measure::SurfaceFeatureType::Edge: case Measure::SurfaceFeatureType::Circle: { - colors.emplace_back((m_hover_id == POINT_ID) ? hover_selection_color() : hovering_color()); - colors.emplace_back(hovering_color()); + if (m_selected_features.first.is_center && m_curr_feature == m_selected_features.first.source) + colors = { SELECTED_1ST_COLOR, NEUTRAL_COLOR }; + else if (m_selected_features.second.is_center && m_curr_feature == m_selected_features.second.source) + colors = { SELECTED_2ND_COLOR, NEUTRAL_COLOR }; + else + colors = { hovering_color(), hovering_color() }; break; } case Measure::SurfaceFeatureType::Plane: @@ -914,28 +971,76 @@ void GLGizmoMeasure::on_render() } if (m_selected_features.first.feature.has_value() && (!m_curr_feature.has_value() || *m_curr_feature != *m_selected_features.first.feature)) { - const std::vector colors = { SELECTED_1ST_COLOR }; - render_feature(*m_selected_features.first.feature, colors, inv_zoom, m_hover_id == SELECTION_1_ID, false); - if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Point) { - auto it = std::find_if(m_selection_raycasters.begin(), m_selection_raycasters.end(), - [](std::shared_ptr item) { return SceneRaycaster::decode_id(SceneRaycaster::EType::Gizmo, item->get_id()) == SELECTION_1_ID; }); - if (it != m_selection_raycasters.end()) - (*it)->set_transform(Geometry::translation_transform(m_selected_features.first.feature->get_point()) * Geometry::scale_transform(inv_zoom)); + // render 1st selected feature + + std::optional feature_to_render; + std::vector colors; + bool requires_raycaster_update = false; + if (m_hover_id == SEL_SPHERE_1_ID && (m_selected_features.first.is_center || is_feature_with_center(*m_selected_features.first.feature))) { + // hovering over a center + feature_to_render = m_selected_features.first.source; + colors = { NEUTRAL_COLOR, SELECTED_1ST_COLOR }; + requires_raycaster_update = true; + } + else if (is_feature_with_center(*m_selected_features.first.feature)) { + // hovering over a feature with center + feature_to_render = m_selected_features.first.feature; + colors = { SELECTED_1ST_COLOR, NEUTRAL_COLOR }; + requires_raycaster_update = true; + } + else { + feature_to_render = m_selected_features.first.feature; + colors = { SELECTED_1ST_COLOR }; + requires_raycaster_update = m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Point; + } + + render_feature(*feature_to_render, colors, inv_zoom, m_hover_id == SEL_SPHERE_1_ID, false); + + if (requires_raycaster_update) { + auto it = std::find_if(m_selected_sphere_raycasters.begin(), m_selected_sphere_raycasters.end(), + [](std::shared_ptr item) { return SceneRaycaster::decode_id(SceneRaycaster::EType::Gizmo, item->get_id()) == SEL_SPHERE_1_ID; }); + if (it != m_selected_sphere_raycasters.end()) + (*it)->set_transform(Geometry::translation_transform(get_feature_offset(*m_selected_features.first.feature)) * Geometry::scale_transform(inv_zoom)); } } + if (m_selected_features.second.feature.has_value() && (!m_curr_feature.has_value() || *m_curr_feature != *m_selected_features.second.feature)) { - const std::vector colors = { SELECTED_2ND_COLOR }; - render_feature(*m_selected_features.second.feature, colors, inv_zoom, m_hover_id == SELECTION_2_ID, false); - if (m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Point) { - auto it = std::find_if(m_selection_raycasters.begin(), m_selection_raycasters.end(), - [](std::shared_ptr item) { return SceneRaycaster::decode_id(SceneRaycaster::EType::Gizmo, item->get_id()) == SELECTION_2_ID; }); - if (it != m_selection_raycasters.end()) - (*it)->set_transform(Geometry::translation_transform(m_selected_features.second.feature->get_point()) * Geometry::scale_transform(inv_zoom)); + // render 2nd selected feature + + std::optional feature_to_render; + std::vector colors; + bool requires_raycaster_update = false; + if (m_hover_id == SEL_SPHERE_2_ID && (m_selected_features.second.is_center || is_feature_with_center(*m_selected_features.second.feature))) { + // hovering over a center + feature_to_render = m_selected_features.second.source; + colors = { NEUTRAL_COLOR, SELECTED_2ND_COLOR }; + requires_raycaster_update = true; + } + else if (is_feature_with_center(*m_selected_features.second.feature)) { + // hovering over a feature with center + feature_to_render = m_selected_features.second.feature; + colors = { SELECTED_2ND_COLOR, NEUTRAL_COLOR }; + requires_raycaster_update = true; + } + else { + feature_to_render = m_selected_features.second.feature; + colors = { SELECTED_2ND_COLOR }; + requires_raycaster_update = m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Point; + } + + render_feature(*feature_to_render, colors, inv_zoom, m_hover_id == SEL_SPHERE_2_ID, false); + + if (requires_raycaster_update) { + auto it = std::find_if(m_selected_sphere_raycasters.begin(), m_selected_sphere_raycasters.end(), + [](std::shared_ptr item) { return SceneRaycaster::decode_id(SceneRaycaster::EType::Gizmo, item->get_id()) == SEL_SPHERE_2_ID; }); + if (it != m_selected_sphere_raycasters.end()) + (*it)->set_transform(Geometry::translation_transform(get_feature_offset(*m_selected_features.second.feature)) * Geometry::scale_transform(inv_zoom)); } } if (is_hovering_on_feature && m_curr_point_on_feature_position.has_value()) { if (m_hover_id != POINT_ID) { + // render point on feature while SHIFT is pressed const Transform3d matrix = Geometry::translation_transform(*m_curr_point_on_feature_position) * Geometry::scale_transform(inv_zoom); set_matrix_uniforms(matrix); const ColorRGBA color = hover_selection_color(); @@ -1600,7 +1705,8 @@ static void add_strings_row_to_table(ImGuiWrapper& imgui, const std::string& col void GLGizmoMeasure::render_debug_dialog() { auto add_feature_data = [this](const SelectedFeatures::Item& item) { - add_strings_row_to_table(*m_imgui, "Type", ImGuiWrapper::COL_ORANGE_LIGHT, item.source, ImGui::GetStyleColorVec4(ImGuiCol_Text)); + const std::string text = (item.source == item.feature) ? surface_feature_type_as_string(item.feature->get_type()) : point_on_feature_type_as_string(item.source->get_type(), m_hover_id); + add_strings_row_to_table(*m_imgui, "Type", ImGuiWrapper::COL_ORANGE_LIGHT, text, ImGui::GetStyleColorVec4(ImGuiCol_Text)); switch (item.feature->get_type()) { case Measure::SurfaceFeatureType::Point: @@ -1646,7 +1752,6 @@ void GLGizmoMeasure::render_debug_dialog() { case EMode::FeatureSelection: { txt = "Feature selection"; break; } case EMode::PointSelection: { txt = "Point selection"; break; } - case EMode::CenterSelection: { txt = "Center selection"; break; } default: { assert(false); break; } } add_strings_row_to_table(*m_imgui, "Mode", ImGuiWrapper::COL_ORANGE_LIGHT, txt, ImGui::GetStyleColorVec4(ImGuiCol_Text)); @@ -1730,17 +1835,16 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit text = _u8L("Unselect feature"); color = SELECTED_2ND_COLOR; } - else if (m_hover_id == SELECTION_1_ID) { - text = (m_mode == EMode::CenterSelection) ? _u8L("Unselect center") : _u8L("Unselect point"); + else if (m_hover_id == SEL_SPHERE_1_ID) { + text = _u8L("Unselect point"); color = SELECTED_1ST_COLOR; } - else if (m_hover_id == SELECTION_2_ID) { - text = (m_mode == EMode::CenterSelection) ? _u8L("Unselect center") : _u8L("Unselect point"); + else if (m_hover_id == SEL_SPHERE_2_ID) { + text = _u8L("Unselect point"); color = SELECTED_2ND_COLOR; } else { - text = (m_mode == EMode::PointSelection) ? _u8L("Select point") : - (m_mode == EMode::CenterSelection) ? _u8L("Select center") : _u8L("Select feature"); + text = (m_mode == EMode::PointSelection) ? _u8L("Select point") : _u8L("Select feature"); color = SELECTED_2ND_COLOR; } } @@ -1750,14 +1854,13 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit text = _u8L("Unselect feature"); color = SELECTED_1ST_COLOR; } - else if (m_hover_id == SELECTION_1_ID) { - text = (m_mode == EMode::CenterSelection) ? _u8L("Unselect center") : _u8L("Unselect point"); + else if (m_hover_id == SEL_SPHERE_1_ID) { + text = _u8L("Unselect point"); color = SELECTED_1ST_COLOR; } } if (text.empty()) { - text = (m_mode == EMode::PointSelection) ? _u8L("Select point") : - (m_mode == EMode::CenterSelection) ? _u8L("Select center") : _u8L("Select feature"); + text = (m_mode == EMode::PointSelection) ? _u8L("Select point") : _u8L("Select feature"); color = m_selected_features.first.feature.has_value() ? SELECTED_2ND_COLOR : SELECTED_1ST_COLOR; } } @@ -1776,11 +1879,6 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit ++row_count; } - if (m_mode != EMode::CenterSelection && feature_has_center(m_curr_feature)) { - add_strings_row_to_table(*m_imgui, _u8L("Shift") + "+" + CTRL_STR, ImGuiWrapper::COL_ORANGE_LIGHT, _u8L("Enable center selection"), ImGui::GetStyleColorVec4(ImGuiCol_Text)); - ++row_count; - } - if (m_selected_features.first.feature.has_value()) { add_strings_row_to_table(*m_imgui, _u8L("Delete"), ImGuiWrapper::COL_ORANGE_LIGHT, _u8L("Restart selection"), ImGui::GetStyleColorVec4(ImGuiCol_Text)); ++row_count; @@ -1806,7 +1904,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit } // add dummy rows to keep dialog size fixed - for (unsigned int i = row_count; i < 5; ++i) { + for (unsigned int i = row_count; i < 4; ++i) { add_strings_row_to_table(*m_imgui, " ", ImGuiWrapper::COL_ORANGE_LIGHT, " ", ImGui::GetStyleColorVec4(ImGuiCol_Text)); } @@ -1819,17 +1917,20 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit ImGui::Separator(); const ImGuiTableFlags flags = ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersH; if (ImGui::BeginTable("Selection", 2, flags)) { - auto format_item_text = [use_inches, &units](const SelectedFeatures::Item& item) { - std::string txt = item.feature.has_value() ? item.source : _u8L("None"); - if (item.feature.has_value() && item.feature->get_type() == Measure::SurfaceFeatureType::Circle) { - auto [center, radius, normal] = item.feature->get_circle(); - const Vec3d on_circle = center + radius * Measure::get_orthogonal(normal, true); - radius = (on_circle - center).norm(); - if (use_inches) - radius = ObjectManipulation::mm_to_in * radius; - txt += " (" + _u8L("Diameter:") + " " + format_double(2.0 * radius) + units + ")"; - } - return txt; + auto format_item_text = [this, use_inches, &units](const SelectedFeatures::Item& item) { + if (!item.feature.has_value()) + return _u8L("None"); + + std::string text = (item.source == item.feature) ? surface_feature_type_as_string(item.feature->get_type()) : point_on_feature_type_as_string(item.source->get_type(), m_hover_id); + if (item.feature.has_value() && item.feature->get_type() == Measure::SurfaceFeatureType::Circle) { + auto [center, radius, normal] = item.feature->get_circle(); + const Vec3d on_circle = center + radius * Measure::get_orthogonal(normal, true); + radius = (on_circle - center).norm(); + if (use_inches) + radius = ObjectManipulation::mm_to_in * radius; + text += " (" + _u8L("Diameter:") + " " + format_double(2.0 * radius) + units + ")"; + } + return text; }; add_strings_row_to_table(*m_imgui, _u8L("Selection") + " 1:", ImGuiWrapper::to_ImVec4(SELECTED_1ST_COLOR), format_item_text(m_selected_features.first), @@ -1842,7 +1943,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit m_imgui->disabled_begin(!m_selected_features.first.feature.has_value()); if (m_imgui->button(_u8L("Restart selection"))) { m_selected_features.reset(); - m_selection_raycasters.clear(); + m_selected_sphere_raycasters.clear(); m_imgui->set_requires_extra_frame(); } m_imgui->disabled_end(); @@ -1938,7 +2039,16 @@ void GLGizmoMeasure::on_unregister_raycasters_for_picking() m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo); m_parent.set_raycaster_gizmos_on_top(false); m_raycasters.clear(); - m_selection_raycasters.clear(); + m_selected_sphere_raycasters.clear(); +} + +void GLGizmoMeasure::remove_selected_sphere_raycaster(int id) +{ + auto it = std::find_if(m_selected_sphere_raycasters.begin(), m_selected_sphere_raycasters.end(), + [id](std::shared_ptr item) { return SceneRaycaster::decode_id(SceneRaycaster::EType::Gizmo, item->get_id()) == id; }); + if (it != m_selected_sphere_raycasters.end()) + m_selected_sphere_raycasters.erase(it); + m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, id); } } // namespace GUI diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 1672e8b74e..1e4330e955 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -24,20 +24,19 @@ class GLGizmoMeasure : public GLGizmoBase enum class EMode : unsigned char { FeatureSelection, - PointSelection, - CenterSelection + PointSelection }; struct SelectedFeatures { struct Item { - std::string source; + bool is_center{ false }; + std::optional source; std::optional feature; bool operator == (const Item& other) const { - if (this->source != other.source) return false; - return this->feature == other.feature; + return this->is_center == other.is_center && this->source == other.source && this->feature == other.feature; } bool operator != (const Item& other) const { @@ -45,7 +44,8 @@ class GLGizmoMeasure : public GLGizmoBase } void reset() { - source.clear(); + is_center = false; + source.reset(); feature.reset(); } }; @@ -106,7 +106,8 @@ class GLGizmoMeasure : public GLGizmoBase std::vector m_plane_models_cache; std::map> m_raycasters; - std::vector> m_selection_raycasters; + // 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; struct SceneRaycasterState @@ -126,7 +127,6 @@ class GLGizmoMeasure : public GLGizmoBase Vec2d m_mouse_pos{ Vec2d::Zero() }; - KeyAutoRepeatFilter m_ctrl_kar_filter; KeyAutoRepeatFilter m_shift_kar_filter; SelectedFeatures m_selected_features; @@ -174,6 +174,8 @@ protected: virtual void on_render_input_window(float x, float y, float bottom_limit) override; virtual void on_register_raycasters_for_picking() override; virtual void on_unregister_raycasters_for_picking() override; + + void remove_selected_sphere_raycaster(int id); }; } // namespace GUI From 93a3ee501980c70e0a3805fe798c0392c601b24f Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 30 Nov 2022 12:51:37 +0100 Subject: [PATCH 79/89] Gizmo measure - Show radius of single selected circle, to allow for object scaling --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 105 ++++++++++++++--------- src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 1 + 2 files changed, 67 insertions(+), 39 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 43d55addda..27051a8e6d 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -422,8 +422,7 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) m_selected_sphere_raycasters.push_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, SEL_SPHERE_1_ID, *m_sphere.mesh_raycaster)); } - if (m_selected_features != selected_features_old && m_selected_features.second.feature.has_value()) - m_measurement_result = Measure::get_measurement(*m_selected_features.first.feature, *m_selected_features.second.feature, m_measuring.get()); + update_measurement_result(); m_imgui->set_requires_extra_frame(); @@ -469,7 +468,7 @@ void GLGizmoMeasure::data_changed() m_last_inv_zoom = 0.0f; m_last_plane_idx = -1; if (m_pending_scale) { - m_measurement_result = Measure::get_measurement(*m_selected_features.first.feature, *m_selected_features.second.feature, m_measuring.get()); + update_measurement_result(); m_pending_scale = false; } else @@ -517,8 +516,10 @@ bool GLGizmoMeasure::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_po m_parent.request_extra_frame(); } else if (action == SLAGizmoEventType::Escape) { - if (!m_selected_features.first.feature.has_value()) + if (!m_selected_features.first.feature.has_value()) { + update_measurement_result(); return false; + } else { if (m_selected_features.second.feature.has_value()) { remove_selected_sphere_raycaster(SEL_SPHERE_2_ID); @@ -528,6 +529,8 @@ bool GLGizmoMeasure::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_po remove_selected_sphere_raycaster(SEL_SPHERE_1_ID); m_selected_features.first.feature.reset(); } + + update_measurement_result(); } } @@ -1135,7 +1138,10 @@ void GLGizmoMeasure::render_dimensioning() { static SelectedFeatures last_selected_features; - if (!m_selected_features.first.feature.has_value() || !m_selected_features.second.feature.has_value()) + if (!m_selected_features.first.feature.has_value()) + return; + + if (!m_selected_features.second.feature.has_value() && m_selected_features.first.feature->get_type() != Measure::SurfaceFeatureType::Circle) return; GLShaderProgram* shader = wxGetApp().get_shader("flat"); @@ -1343,7 +1349,8 @@ void GLGizmoMeasure::render_dimensioning() const Vec3d new_center = selection.get_bounding_box().center(); const TrafoData trafo_data(ratio, old_center, new_center); scale_feature(*m_selected_features.first.feature, trafo_data); - scale_feature(*m_selected_features.second.feature, trafo_data); + if (m_selected_features.second.feature.has_value()) + scale_feature(*m_selected_features.second.feature, trafo_data); // update measure on next call to data_changed() m_pending_scale = true; @@ -1646,41 +1653,51 @@ void GLGizmoMeasure::render_dimensioning() glsafe(::glDisable(GL_DEPTH_TEST)); - if (m_selected_features.second.feature.has_value()) { - const bool has_distance = m_measurement_result.has_distance_data(); + const bool has_distance = m_measurement_result.has_distance_data(); - const Measure::SurfaceFeature* f1 = &(*m_selected_features.first.feature); - const Measure::SurfaceFeature* f2 = &(*m_selected_features.second.feature); - Measure::SurfaceFeatureType ft1 = f1->get_type(); - Measure::SurfaceFeatureType ft2 = f2->get_type(); - - // Order features by type so following conditions are simple. - if (ft1 > ft2) { - std::swap(ft1, ft2); - std::swap(f1, f2); - } - - // If there is an angle to show, draw the arc: - if (ft1 == Measure::SurfaceFeatureType::Edge && ft2 == Measure::SurfaceFeatureType::Edge) - arc_edge_edge(*f1, *f2); - else if (ft1 == Measure::SurfaceFeatureType::Edge && ft2 == Measure::SurfaceFeatureType::Plane) - arc_edge_plane(*f1, *f2); - else if (ft1 == Measure::SurfaceFeatureType::Plane && ft2 == Measure::SurfaceFeatureType::Plane) - arc_plane_plane(*f1, *f2); - - if (has_distance){ - // Where needed, draw the extension of the edge to where the dist is measured: - if (ft1 == Measure::SurfaceFeatureType::Point && ft2 == Measure::SurfaceFeatureType::Edge) - point_edge(*f1, *f2); - - // Render the arrow between the points that the backend passed: - const Measure::DistAndPoints& dap = m_measurement_result.distance_infinite.has_value() - ? *m_measurement_result.distance_infinite - : *m_measurement_result.distance_strict; - point_point(dap.from, dap.to, dap.dist); - } + const Measure::SurfaceFeature* f1 = &(*m_selected_features.first.feature); + const Measure::SurfaceFeature* f2 = nullptr; + std::unique_ptr temp_feature; + if (m_selected_features.second.feature.has_value()) + f2 = &(*m_selected_features.second.feature); + else { + assert(m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Circle); + temp_feature = std::make_unique(std::get<0>(m_selected_features.first.feature->get_circle())); + f2 = temp_feature.get(); } - + + if (!m_selected_features.second.feature.has_value() && m_selected_features.first.feature->get_type() != Measure::SurfaceFeatureType::Circle) + return; + + Measure::SurfaceFeatureType ft1 = f1->get_type(); + Measure::SurfaceFeatureType ft2 = f2->get_type(); + + // Order features by type so following conditions are simple. + if (ft1 > ft2) { + std::swap(ft1, ft2); + std::swap(f1, f2); + } + + // If there is an angle to show, draw the arc: + if (ft1 == Measure::SurfaceFeatureType::Edge && ft2 == Measure::SurfaceFeatureType::Edge) + arc_edge_edge(*f1, *f2); + else if (ft1 == Measure::SurfaceFeatureType::Edge && ft2 == Measure::SurfaceFeatureType::Plane) + arc_edge_plane(*f1, *f2); + else if (ft1 == Measure::SurfaceFeatureType::Plane && ft2 == Measure::SurfaceFeatureType::Plane) + arc_plane_plane(*f1, *f2); + + if (has_distance){ + // Where needed, draw the extension of the edge to where the dist is measured: + if (ft1 == Measure::SurfaceFeatureType::Point && ft2 == Measure::SurfaceFeatureType::Edge) + point_edge(*f1, *f2); + + // Render the arrow between the points that the backend passed: + const Measure::DistAndPoints& dap = m_measurement_result.distance_infinite.has_value() + ? *m_measurement_result.distance_infinite + : *m_measurement_result.distance_strict; + point_point(dap.from, dap.to, dap.dist); + } + glsafe(::glEnable(GL_DEPTH_TEST)); shader->stop_using(); @@ -2051,5 +2068,15 @@ void GLGizmoMeasure::remove_selected_sphere_raycaster(int id) m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, id); } +void GLGizmoMeasure::update_measurement_result() +{ + if (!m_selected_features.first.feature.has_value()) + m_measurement_result = Measure::MeasurementResult(); + else if (m_selected_features.second.feature.has_value()) + m_measurement_result = Measure::get_measurement(*m_selected_features.first.feature, *m_selected_features.second.feature, m_measuring.get()); + else if (!m_selected_features.second.feature.has_value() && m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Circle) + m_measurement_result = Measure::get_measurement(*m_selected_features.first.feature, Measure::SurfaceFeature(std::get<0>(m_selected_features.first.feature->get_circle())), m_measuring.get()); +} + } // namespace GUI } // namespace Slic3r diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 1e4330e955..4652a171b7 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -176,6 +176,7 @@ protected: virtual void on_unregister_raycasters_for_picking() override; void remove_selected_sphere_raycaster(int id); + void update_measurement_result(); }; } // namespace GUI From 6533eb2a53edf28313bd07da0526b66cbd0e9c60 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 30 Nov 2022 13:04:48 +0100 Subject: [PATCH 80/89] Fixed warnings --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 27051a8e6d..c1e153c886 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -487,17 +487,6 @@ static bool feature_has_center(std::optional feature) bool GLGizmoMeasure::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down) { - auto activate_center_selection = [this, shift_down, control_down](SLAGizmoEventType action) { - bool ret = false; - switch (action) - { - case SLAGizmoEventType::CtrlDown: { ret = shift_down && feature_has_center(m_curr_feature); break; } - case SLAGizmoEventType::ShiftDown: { ret = control_down && feature_has_center(m_curr_feature); break; } - default: { break; } - } - return ret; - }; - if (action == SLAGizmoEventType::ShiftDown) { if (m_shift_kar_filter.is_first()) { m_mode = EMode::PointSelection; @@ -598,8 +587,6 @@ void GLGizmoMeasure::on_render() // if (m_parent.is_mouse_dragging()) // return; - const Selection& selection = m_parent.get_selection(); - update_if_needed(); const Camera& camera = wxGetApp().plater()->get_camera(); From f0811873563e1d7f2923dccb4e7a7d4ff5f7ec71 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 30 Nov 2022 13:07:49 +0100 Subject: [PATCH 81/89] Fixed warning --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index c1e153c886..bf321bb785 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -310,7 +310,6 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) return false; if (m_hover_id != -1) { - SelectedFeatures selected_features_old = m_selected_features; m_mouse_left_down = true; auto detect_current_item = [this]() { From 220104dbe22dde4a82a4d84b5bef63bed2178a6a Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Thu, 1 Dec 2022 12:47:06 +0100 Subject: [PATCH 82/89] Measure gizmo - Fixed sychronization of imgui dialog with current hovering/selection state --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 94 +++++++++++++++++++++--- 1 file changed, 82 insertions(+), 12 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index bf321bb785..1ddd805b71 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -1831,22 +1831,61 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit ColorRGBA color; if (m_selected_features.second.feature.has_value()) { if (m_selected_features.first.feature == m_curr_feature && m_mode == EMode::FeatureSelection) { + // hovering over 1st selected feature text = _u8L("Unselect feature"); color = SELECTED_1ST_COLOR; } + else if (m_hover_id == SEL_SPHERE_1_ID) { + if (m_selected_features.first.is_center) { + // hovering over center selected as 1st feature + text = _u8L("Unselect center"); + color = SELECTED_1ST_COLOR; + } + else if (is_feature_with_center(*m_selected_features.first.feature)) { + // hovering over center of 1st selected feature + text = _u8L("Select center"); + color = SELECTED_1ST_COLOR; + } + else { + // hovering over point selected as 1st feature + text = _u8L("Unselect point"); + color = SELECTED_1ST_COLOR; + } + } + else if (m_selected_features.first.is_center && m_selected_features.first.source == m_curr_feature) { + // hovering over feature whose center is selected as 1st feature + text = _u8L("Select feature"); + color = SELECTED_1ST_COLOR; + } else if (m_selected_features.second.feature == m_curr_feature && m_mode == EMode::FeatureSelection) { + // hovering over 2nd selected feature text = _u8L("Unselect feature"); color = SELECTED_2ND_COLOR; } - else if (m_hover_id == SEL_SPHERE_1_ID) { - text = _u8L("Unselect point"); - color = SELECTED_1ST_COLOR; - } else if (m_hover_id == SEL_SPHERE_2_ID) { - text = _u8L("Unselect point"); + if (m_selected_features.second.is_center) { + // hovering over center selected as 2nd feature + text = _u8L("Unselect feature"); + color = SELECTED_2ND_COLOR; + } + else if (is_feature_with_center(*m_selected_features.second.feature)) { + // hovering over center of 2nd selected feature + text = _u8L("Select center"); + color = SELECTED_2ND_COLOR; + } + else { + // hovering over point selected as 2nd feature + text = _u8L("Unselect point"); + color = SELECTED_2ND_COLOR; + } + } + else if (m_selected_features.second.is_center && m_selected_features.second.source == m_curr_feature) { + // hovering over feature whose center is selected as 2nd feature + text = _u8L("Select feature"); color = SELECTED_2ND_COLOR; } else { + // 1st feature selected text = (m_mode == EMode::PointSelection) ? _u8L("Select point") : _u8L("Select feature"); color = SELECTED_2ND_COLOR; } @@ -1854,20 +1893,51 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit else { if (m_selected_features.first.feature.has_value()) { if (m_selected_features.first.feature == m_curr_feature && m_mode == EMode::FeatureSelection) { + // hovering over 1st selected feature text = _u8L("Unselect feature"); color = SELECTED_1ST_COLOR; } - else if (m_hover_id == SEL_SPHERE_1_ID) { - text = _u8L("Unselect point"); - color = SELECTED_1ST_COLOR; + else { + if (m_hover_id == SEL_SPHERE_1_ID) { + if (m_selected_features.first.is_center) { + // hovering over center selected as 1st feature + text = _u8L("Unselect feature"); + color = SELECTED_1ST_COLOR; + } + else if (is_feature_with_center(*m_selected_features.first.feature)) { + // hovering over center of 1st selected feature + text = _u8L("Select center"); + color = SELECTED_1ST_COLOR; + } + else { + // hovering over point selected as 1st feature + text = _u8L("Unselect point"); + color = SELECTED_1ST_COLOR; + } + } + else { + if (m_selected_features.first.is_center && m_selected_features.first.source == m_curr_feature) { + // hovering over feature whose center is selected as 1st feature + text = _u8L("Select feature"); + color = SELECTED_1ST_COLOR; + } + else { + // 1st feature selected + text = (m_mode == EMode::PointSelection) ? _u8L("Select point") : _u8L("Select feature"); + color = SELECTED_2ND_COLOR; + } + } } } - if (text.empty()) { + else { + // nothing is selected text = (m_mode == EMode::PointSelection) ? _u8L("Select point") : _u8L("Select feature"); - color = m_selected_features.first.feature.has_value() ? SELECTED_2ND_COLOR : SELECTED_1ST_COLOR; + color = SELECTED_1ST_COLOR; } } + assert(!text.empty()); + m_imgui->text_colored(ImGui::GetStyleColorVec4(ImGuiCol_Text), text); ImGui::SameLine(); const ImVec2 pos = ImGui::GetCursorScreenPos(); @@ -1985,7 +2055,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit if (use_inches) distance = ObjectManipulation::mm_to_in * distance; ImGui::PushID("ClipboardDistanceInfinite"); - add_measure_row_to_table(_u8L("Distance Infinite"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(distance) + units, + add_measure_row_to_table(_u8L("Distance"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(distance) + units, ImGui::GetStyleColorVec4(ImGuiCol_Text)); ++measure_row_count; ImGui::PopID(); @@ -1996,7 +2066,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit if (use_inches) distance = ObjectManipulation::mm_to_in * distance; ImGui::PushID("ClipboardDistanceStrict"); - add_measure_row_to_table(_u8L("Distance Strict"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(distance) + units, + add_measure_row_to_table(_u8L("Distance"), ImGuiWrapper::COL_ORANGE_LIGHT, format_double(distance) + units, ImGui::GetStyleColorVec4(ImGuiCol_Text)); ++measure_row_count; ImGui::PopID(); From eeea803be576f266cc2be36e10f55273cd3fa6ee Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Thu, 1 Dec 2022 13:31:22 +0100 Subject: [PATCH 83/89] Measurement: tweaking of the tolerances, ransacing the whole border --- src/libslic3r/Measure.cpp | 324 ++++++++++++++++++++------------------ 1 file changed, 175 insertions(+), 149 deletions(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index 37bf68e83d..3d96c351c5 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -18,7 +18,7 @@ static std::pair get_center_and_radius(const std::vector& { Vec2ds out; double z = 0.; - for (const Vec3d pt : points) { + for (const Vec3d& pt : points) { Vec3d pt_transformed = trafo * pt; z = pt_transformed.z(); out.emplace_back(pt_transformed.x(), pt_transformed.y()); @@ -29,6 +29,14 @@ static std::pair get_center_and_radius(const std::vector& return std::make_pair(trafo.inverse() * Vec3d(circle.center.x(), circle.center.y(), z), circle.radius); } +static bool circle_fit_is_ok(const std::vector& pts, const Vec3d& center, double radius) +{ + for (const Vec3d& pt : pts) + if (std::abs((pt - center).norm() - radius) > 0.05) + return false; + return true; +} + static std::array orthonormal_basis(const Vec3d& v) { std::array ret; @@ -246,10 +254,7 @@ void MeasuringImpl::update_planes() void MeasuringImpl::extract_features() { - auto are_angles_same = [](double a, double b) { return Slic3r::is_approx(a,b); }; - auto are_lengths_same = [](double a, double b) { return Slic3r::is_approx(a,b); }; - - std::vector angles; + std::vector angles; // placed in outer scope to prevent reallocations std::vector lengths; @@ -267,175 +272,196 @@ void MeasuringImpl::extract_features() if (border.size() <= 1) continue; - // Given an idx into border, return the index that is idx+offset position, - // while taking into account the need for warp-around and the fact that - // the first and last point are the same. - auto offset_to_index = [border_size = int(border.size())](int idx, int offset) -> int { - assert(std::abs(offset) < border_size); - int out = idx+offset; - if (out >= border_size) - out = out - border_size; - else if (out < 0) - out = border_size + out; + bool done = false; - return out; - }; + if (const auto& [center, radius] = get_center_and_radius(border, trafo); + (border.size()>4) && circle_fit_is_ok(border, center, radius)) { + // The whole border is one circle. Just add it into the list of features + // and we are done. - // First calculate angles at all the vertices. - angles.clear(); - lengths.clear(); - int first_different_angle_idx = 0; - for (int i=0; i M_PI) - angle = 2*M_PI - angle; + bool is_polygon = border.size()>4 && border.size()<=8; + bool lengths_match = std::all_of(border.begin()+2, border.end(), [is_polygon](const Vec3d& pt) { + return Slic3r::is_approx((pt - *((&pt)-1)).squaredNorm(), (*((&pt)-1) - *((&pt)-2)).squaredNorm(), is_polygon ? 0.01 : 0.01); + }); - angles.push_back(angle); - lengths.push_back(v2.norm()); - if (first_different_angle_idx == 0 && angles.size() > 1) { - if (! are_angles_same(angles.back(), angles[angles.size()-2])) - first_different_angle_idx = angles.size()-1; + if (lengths_match && (is_polygon || border.size() > 8)) { + if (is_polygon) { + // This is a polygon, add the separate edges with the center. + for (int j=0; j circles; - std::vector edges; - std::vector> circles_idxs; - //std::vector circles_lengths; - std::vector single_circle; // could be in loop-scope, but reallocations - double single_circle_length = 0.; - int first_pt_idx = offset_to_index(first_different_angle_idx, 1); - int i = first_pt_idx; - while (i != first_pt_idx || first_iter) { - if (are_angles_same(angles[i], angles[offset_to_index(i,-1)]) - && i != offset_to_index(first_pt_idx, -1) // not the last point - && i != start_idx ) { - // circle - if (! circle) { - circle = true; - single_circle.clear(); - single_circle_length = 0.; - start_idx = offset_to_index(i, -2); - single_circle = { border[start_idx], border[offset_to_index(start_idx,1)] }; - single_circle_length += lengths[offset_to_index(i, -1)]; + if (! done) { + // In this case, the border is not a circle and may contain circular + // segments. Try to find them and then add all remaining edges as edges. + + auto are_angles_same = [](double a, double b) { return Slic3r::is_approx(a,b,0.01); }; + auto are_lengths_same = [](double a, double b) { return Slic3r::is_approx(a,b,0.01); }; + + + // Given an idx into border, return the index that is idx+offset position, + // while taking into account the need for wrap-around and the fact that + // the first and last point are the same. + auto offset_to_index = [border_size = int(border.size())](int idx, int offset) -> int { + assert(std::abs(offset) < border_size); + int out = idx+offset; + if (out >= border_size) + out = out - border_size; + else if (out < 0) + out = border_size + out; + + return out; + }; + + // First calculate angles at all the vertices. + angles.clear(); + lengths.clear(); + int first_different_angle_idx = 0; + for (int i=0; i M_PI) + angle = 2*M_PI - angle; + + angles.push_back(angle); + lengths.push_back(v2.norm()); + if (first_different_angle_idx == 0 && angles.size() > 1) { + if (! are_angles_same(angles.back(), angles[angles.size()-2])) + first_different_angle_idx = angles.size()-1; } - single_circle.emplace_back(border[i]); - single_circle_length += lengths[i]; - } else { - if (circle && single_circle.size() >= 5) { // Less than 5 vertices? Not a circle. + } + assert(border.size() == angles.size()); + assert(border.size() == lengths.size()); + + // First go around the border and pick what might be circular segments. + // Save pair of indices to where such potential segments start and end. + // Also remember the length of these segments. + int start_idx = -1; + bool circle = false; + bool first_iter = true; + std::vector circles; + std::vector edges; + std::vector> circles_idxs; + //std::vector circles_lengths; + std::vector single_circle; // could be in loop-scope, but reallocations + double single_circle_length = 0.; + int first_pt_idx = offset_to_index(first_different_angle_idx, 1); + int i = first_pt_idx; + while (i != first_pt_idx || first_iter) { + if (are_angles_same(angles[i], angles[offset_to_index(i,-1)]) + && i != offset_to_index(first_pt_idx, -1) // not the last point + && i != start_idx ) { + // circle + if (! circle) { + circle = true; + single_circle.clear(); + single_circle_length = 0.; + start_idx = offset_to_index(i, -2); + single_circle = { border[start_idx], border[offset_to_index(start_idx,1)] }; + single_circle_length += lengths[offset_to_index(i, -1)]; + } single_circle.emplace_back(border[i]); single_circle_length += lengths[i]; + } else { + if (circle && single_circle.size() >= 5) { // Less than 5 vertices? Not a circle. + single_circle.emplace_back(border[i]); + single_circle_length += lengths[i]; - bool accept_circle = true; - { - // Check that lengths of internal (!!!) edges match. - int j = offset_to_index(start_idx, 3); - while (j != i) { - if (! are_lengths_same(lengths[offset_to_index(j,-1)], lengths[j])) { - accept_circle = false; - break; - } - j = offset_to_index(j, 1); - } - } - - if (accept_circle) { - const auto& [center, radius] = get_center_and_radius(single_circle, trafo); - - // Check that the fit went well. The tolerance is high, only to - // reject complete failures. - for (const Vec3d& pt : single_circle) { - if (std::abs((pt - center).norm() - radius) > 0.5) { - accept_circle = false; - break; + bool accept_circle = true; + { + // Check that lengths of internal (!!!) edges match. + int j = offset_to_index(start_idx, 3); + while (j != i) { + if (! are_lengths_same(lengths[offset_to_index(j,-1)], lengths[j])) { + accept_circle = false; + break; + } + j = offset_to_index(j, 1); } } - // If the segment subtends less than 90 degrees, throw it away. - accept_circle &= single_circle_length / radius > 0.9*M_PI/2.; - - // If this is all-around and 5 to 8 vertices, consider it a polygon. - bool is_polygon = start_idx == i && single_circle.size() <= 9 && single_circle.size() >= 6; - if (accept_circle) { - // Add the circle and remember indices into borders. - circles_idxs.emplace_back(start_idx, i); - if (is_polygon) { - for (int j=0; j<=i; ++j) // No wrap-around handling needed here. - edges.emplace_back(SurfaceFeature(SurfaceFeatureType::Edge, - border[j==0 ? border.size()-1 : j-1], border[j], - std::make_optional(center))); - } - else + const auto& [center, radius] = get_center_and_radius(single_circle, trafo); + + // Check that the fit went well. The tolerance is high, only to + // reject complete failures. + accept_circle &= circle_fit_is_ok(single_circle, center, radius); + + // If the segment subtends less than 90 degrees, throw it away. + accept_circle &= single_circle_length / radius > 0.9*M_PI/2.; + + if (accept_circle) { + // Add the circle and remember indices into borders. + circles_idxs.emplace_back(start_idx, i); circles.emplace_back(SurfaceFeature(SurfaceFeatureType::Circle, center, plane.normal, std::nullopt, radius)); + } } } + circle = false; } - circle = false; - } - // Take care of the wrap around. - first_iter = false; - i = offset_to_index(i, 1); - } - - // We have the circles. Now go around again and pick edges, while jumping over circles. - if (circles_idxs.empty()) { - // Just add all edges. - for (int i=1; i 1 || circles_idxs.front().first != circles_idxs.front().second) { + // There is at least one circular segment. Start at its end and add edges until the start of the next one. + int i = circles_idxs.front().second; + int circle_idx = 1; + while (true) { + i = offset_to_index(i, 1); + edges.emplace_back(SurfaceFeature(SurfaceFeatureType::Edge, border[offset_to_index(i,-1)], border[i])); + if (circle_idx < int(circles_idxs.size()) && i == circles_idxs[circle_idx].first) { + i = circles_idxs[circle_idx].second; + ++circle_idx; + } + if (i == circles_idxs.front().first) + break; } - if (i == circles_idxs.front().first) - break; } - } - // Merge adjacent edges where needed. - assert(std::all_of(edges.begin(), edges.end(), - [](const SurfaceFeature& f) { return f.get_type() == SurfaceFeatureType::Edge; })); - for (int i=edges.size()-1; i>=0; --i) { - const auto& [first_start, first_end] = edges[i==0 ? edges.size()-1 : i-1].get_edge(); - const auto& [second_start, second_end] = edges[i].get_edge(); + // Merge adjacent edges where needed. + assert(std::all_of(edges.begin(), edges.end(), + [](const SurfaceFeature& f) { return f.get_type() == SurfaceFeatureType::Edge; })); + for (int i=edges.size()-1; i>=0; --i) { + const auto& [first_start, first_end] = edges[i==0 ? edges.size()-1 : i-1].get_edge(); + const auto& [second_start, second_end] = edges[i].get_edge(); - if (Slic3r::is_approx(first_end, second_start) - && Slic3r::is_approx((first_end-first_start).normalized().dot((second_end-second_start).normalized()), 1.)) { - // The edges have the same direction and share a point. Merge them. - edges[i==0 ? edges.size()-1 : i-1] = SurfaceFeature(SurfaceFeatureType::Edge, first_start, second_end); - edges.erase(edges.begin() + i); + if (Slic3r::is_approx(first_end, second_start) + && Slic3r::is_approx((first_end-first_start).normalized().dot((second_end-second_start).normalized()), 1.)) { + // The edges have the same direction and share a point. Merge them. + edges[i==0 ? edges.size()-1 : i-1] = SurfaceFeature(SurfaceFeatureType::Edge, first_start, second_end); + edges.erase(edges.begin() + i); + } } - } - // Now move the circles and edges into the feature list for the plane. - assert(std::all_of(circles.begin(), circles.end(), [](const SurfaceFeature& f) { - return f.get_type() == SurfaceFeatureType::Circle; - })); - assert(std::all_of(edges.begin(), edges.end(), [](const SurfaceFeature& f) { - return f.get_type() == SurfaceFeatureType::Edge; - })); - plane.surface_features.insert(plane.surface_features.end(), std::make_move_iterator(circles.begin()), - std::make_move_iterator(circles.end())); - plane.surface_features.insert(plane.surface_features.end(), std::make_move_iterator(edges.begin()), - std::make_move_iterator(edges.end())); + // Now move the circles and edges into the feature list for the plane. + assert(std::all_of(circles.begin(), circles.end(), [](const SurfaceFeature& f) { + return f.get_type() == SurfaceFeatureType::Circle; + })); + assert(std::all_of(edges.begin(), edges.end(), [](const SurfaceFeature& f) { + return f.get_type() == SurfaceFeatureType::Edge; + })); + plane.surface_features.insert(plane.surface_features.end(), std::make_move_iterator(circles.begin()), + std::make_move_iterator(circles.end())); + plane.surface_features.insert(plane.surface_features.end(), std::make_move_iterator(edges.begin()), + std::make_move_iterator(edges.end())); + } } // The last surface feature is the plane itself. From 954cd105e03945d2cfc96a0df5c4bd24b8d6e1b2 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Thu, 1 Dec 2022 13:34:29 +0100 Subject: [PATCH 84/89] Fixed warnings --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 1ddd805b71..31cd005bec 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -82,17 +82,6 @@ static std::string point_on_feature_type_as_string(Measure::SurfaceFeatureType t return ret; } -static std::string center_on_feature_type_as_string(Measure::SurfaceFeatureType type) -{ - std::string ret; - switch (type) { - case Measure::SurfaceFeatureType::Edge: { ret = _u8L("Center of edge"); break; } - case Measure::SurfaceFeatureType::Circle: { ret = _u8L("Center of circle"); break; } - default: { assert(false); break; } - } - return ret; -} - static GLModel::Geometry init_plane_data(const indexed_triangle_set& its, const std::vector>& planes_triangles, int idx) { assert(0 <= idx && idx < (int)planes_triangles.size()); @@ -477,13 +466,6 @@ void GLGizmoMeasure::data_changed() m_is_editing_distance_first_frame = true; } -static bool feature_has_center(std::optional feature) -{ - return feature.has_value() ? - (feature->get_type() == Measure::SurfaceFeatureType::Circle || (feature->get_type() == Measure::SurfaceFeatureType::Edge && feature->get_extra_point().has_value())) - : false; -} - bool GLGizmoMeasure::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down) { if (action == SLAGizmoEventType::ShiftDown) { From 2f8e2c5e8006274d1bf89ca3e59be655e44faf85 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Thu, 1 Dec 2022 14:56:33 +0100 Subject: [PATCH 85/89] Measure gizmo - Fixed missing raycaster when promoting a point as 1st selected feature --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 31cd005bec..05da490825 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -336,7 +336,7 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) }; auto requires_sphere_raycaster_for_picking = [this](const SelectedFeatures::Item& item) { - if (m_mode == EMode::PointSelection) + if (m_mode == EMode::PointSelection || item.feature->get_type() == Measure::SurfaceFeatureType::Point) return true; else if (m_mode == EMode::FeatureSelection) { if (is_feature_with_center(*item.feature)) From cc8a6a3fff0280b99e947aa7f22c33b04e864bae Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 2 Dec 2022 07:56:11 +0100 Subject: [PATCH 86/89] Follow-up of 85195ac79fb2b7016b05ffff5eb33a483a4d06c2 - Fixed synch of selected features in imgui dialog --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 05da490825..4cb9682b6f 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -82,6 +82,17 @@ static std::string point_on_feature_type_as_string(Measure::SurfaceFeatureType t return ret; } +static std::string center_on_feature_type_as_string(Measure::SurfaceFeatureType type) +{ + std::string ret; + switch (type) { + case Measure::SurfaceFeatureType::Edge: { ret = _u8L("Center of edge"); break; } + case Measure::SurfaceFeatureType::Circle: { ret = _u8L("Center of circle"); break; } + default: { assert(false); break; } + } + return ret; +} + static GLModel::Geometry init_plane_data(const indexed_triangle_set& its, const std::vector>& planes_triangles, int idx) { assert(0 <= idx && idx < (int)planes_triangles.size()); @@ -1976,7 +1987,8 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit if (!item.feature.has_value()) return _u8L("None"); - std::string text = (item.source == item.feature) ? surface_feature_type_as_string(item.feature->get_type()) : point_on_feature_type_as_string(item.source->get_type(), m_hover_id); + std::string text = (item.source == item.feature) ? surface_feature_type_as_string(item.feature->get_type()) : + item.is_center ? center_on_feature_type_as_string(item.source->get_type()) : point_on_feature_type_as_string(item.source->get_type(), m_hover_id); if (item.feature.has_value() && item.feature->get_type() == Measure::SurfaceFeatureType::Circle) { auto [center, radius, normal] = item.feature->get_circle(); const Vec3d on_circle = center + radius * Measure::get_orthogonal(normal, true); From 456e61c7d3bafaed03d00b8b8e895470a8e5fa9c Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Fri, 2 Dec 2022 07:42:02 +0100 Subject: [PATCH 87/89] Measurement: Fixed edge detection on single-triangle planes --- src/libslic3r/Measure.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libslic3r/Measure.cpp b/src/libslic3r/Measure.cpp index 3d96c351c5..6368f30f57 100644 --- a/src/libslic3r/Measure.cpp +++ b/src/libslic3r/Measure.cpp @@ -227,7 +227,7 @@ void MeasuringImpl::update_planes() // In case of broken meshes, this loop might be infinite. Break // out in case it is clearly going bad. - if (last_border.size() > 3*facets.size()) + if (last_border.size() > 3*facets.size()+1) goto PLANE_FAILURE; } while (he != he_start); From 210273e12fc29c8274f9d17a991f83230c8d9470 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Fri, 2 Dec 2022 12:39:49 +0100 Subject: [PATCH 88/89] Fixed differences after rebase to master --- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 4cb9682b6f..a2d2518d6a 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -866,15 +866,12 @@ void GLGizmoMeasure::on_render() } case Measure::SurfaceFeatureType::Plane: { - // no need to render the plane in case it is rendered with the same color as the volume in the 3D scene - if (colors.front() != m_parent.get_selection().get_first_volume()->render_color) { - const auto& [idx, normal, pt] = feature.get_plane(); - assert(idx < m_plane_models_cache.size()); - set_matrix_uniforms(Transform3d::Identity()); - set_emission_uniform(colors.front(), hover); - m_plane_models_cache[idx].set_color(colors.front()); - m_plane_models_cache[idx].render(); - } + const auto& [idx, normal, pt] = feature.get_plane(); + assert(idx < m_plane_models_cache.size()); + set_matrix_uniforms(Transform3d::Identity()); + set_emission_uniform(colors.front(), hover); + m_plane_models_cache[idx].set_color(colors.front()); + m_plane_models_cache[idx].render(); if (update_raycasters_transform) { auto it = m_raycasters.find(PLANE_ID); if (it != m_raycasters.end() && it->second != nullptr) From e04e8c55cfc0498bb665f6fb515f3a8fcea64796 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Fri, 2 Dec 2022 14:21:18 +0100 Subject: [PATCH 89/89] Improved performance of GLModel::render: The way the OpenGL version was checked was quite inefficient --- src/slic3r/GUI/OpenGLManager.cpp | 47 +++++++++++++------------ src/slic3r/GUI/OpenGLManager.hpp | 13 ++++--- src/slic3r/GUI/SendSystemInfoDialog.cpp | 4 +-- 3 files changed, 35 insertions(+), 29 deletions(-) diff --git a/src/slic3r/GUI/OpenGLManager.cpp b/src/slic3r/GUI/OpenGLManager.cpp index 2924470e07..0366031d29 100644 --- a/src/slic3r/GUI/OpenGLManager.cpp +++ b/src/slic3r/GUI/OpenGLManager.cpp @@ -37,20 +37,20 @@ std::string gl_get_string_safe(GLenum param, const std::string& default_value) return std::string((value != nullptr) ? value : default_value); } -const std::string& OpenGLManager::GLInfo::get_version() const +const std::string& OpenGLManager::GLInfo::get_version_string() const { if (!m_detected) detect(); - return m_version; + return m_version_string; } -const std::string& OpenGLManager::GLInfo::get_glsl_version() const +const std::string& OpenGLManager::GLInfo::get_glsl_version_string() const { if (!m_detected) detect(); - return m_glsl_version; + return m_glsl_version_string; } const std::string& OpenGLManager::GLInfo::get_vendor() const @@ -71,7 +71,7 @@ const std::string& OpenGLManager::GLInfo::get_renderer() const bool OpenGLManager::GLInfo::is_mesa() const { - return boost::icontains(m_version, "mesa"); + return m_version_is_mesa; } int OpenGLManager::GLInfo::get_max_tex_size() const @@ -97,13 +97,19 @@ float OpenGLManager::GLInfo::get_max_anisotropy() const return m_max_anisotropy; } +static Semver parse_version_string(const std::string& version); + void OpenGLManager::GLInfo::detect() const { - *const_cast(&m_version) = gl_get_string_safe(GL_VERSION, "N/A"); - *const_cast(&m_glsl_version) = gl_get_string_safe(GL_SHADING_LANGUAGE_VERSION, "N/A"); + *const_cast(&m_version_string) = gl_get_string_safe(GL_VERSION, "N/A"); + *const_cast(&m_glsl_version_string) = gl_get_string_safe(GL_SHADING_LANGUAGE_VERSION, "N/A"); *const_cast(&m_vendor) = gl_get_string_safe(GL_VENDOR, "N/A"); *const_cast(&m_renderer) = gl_get_string_safe(GL_RENDERER, "N/A"); + *const_cast(&m_version) = parse_version_string(m_version_string); + *const_cast(&m_version_is_mesa) = boost::icontains(m_version_string, "mesa"); + *const_cast(&m_glsl_version) = parse_version_string(m_glsl_version_string); + int* max_tex_size = const_cast(&m_max_tex_size); glsafe(::glGetIntegerv(GL_MAX_TEXTURE_SIZE, max_tex_size)); @@ -119,16 +125,16 @@ void OpenGLManager::GLInfo::detect() const *const_cast(&m_detected) = true; } -static bool version_greater_or_equal_to(const std::string& version, unsigned int major, unsigned int minor) +static Semver parse_version_string(const std::string& version) { if (version == "N/A") - return false; + return Semver::invalid(); std::vector tokens; boost::split(tokens, version, boost::is_any_of(" "), boost::token_compress_on); if (tokens.empty()) - return false; + return Semver::invalid(); #if ENABLE_OPENGL_ES const std::string version_container = (tokens.size() > 1 && boost::istarts_with(tokens[1], "ES")) ? tokens[2] : tokens[0]; @@ -150,20 +156,15 @@ static bool version_greater_or_equal_to(const std::string& version, unsigned int if (numbers.size() > 1) gl_minor = ::atoi(numbers[1].c_str()); - if (gl_major < major) - return false; - else if (gl_major > major) - return true; - else - return gl_minor >= minor; + return Semver(gl_major, gl_minor, 0); } bool OpenGLManager::GLInfo::is_version_greater_or_equal_to(unsigned int major, unsigned int minor) const { if (!m_detected) detect(); - - return version_greater_or_equal_to(m_version, major, minor); + + return m_version >= Semver(major, minor, 0); } bool OpenGLManager::GLInfo::is_glsl_version_greater_or_equal_to(unsigned int major, unsigned int minor) const @@ -171,7 +172,7 @@ bool OpenGLManager::GLInfo::is_glsl_version_greater_or_equal_to(unsigned int maj if (!m_detected) detect(); - return version_greater_or_equal_to(m_glsl_version, major, minor); + return m_glsl_version >= Semver(major, minor, 0); } // If formatted for github, plaintext with OpenGL extensions enclosed into
. @@ -378,13 +379,13 @@ bool OpenGLManager::init_gl() wxString message = from_u8((boost::format( #if ENABLE_OPENGL_ES _utf8(L("PrusaSlicer requires OpenGL ES 2.0 capable graphics driver to run correctly, \n" - "while OpenGL version %s, render %s, vendor %s was detected."))) % s_gl_info.get_version() % s_gl_info.get_renderer() % s_gl_info.get_vendor()).str()); + "while OpenGL version %s, render %s, vendor %s was detected."))) % s_gl_info.get_version_string() % s_gl_info.get_renderer() % s_gl_info.get_vendor()).str()); #elif ENABLE_GL_CORE_PROFILE _utf8(L("PrusaSlicer requires OpenGL %s capable graphics driver to run correctly, \n" - "while OpenGL version %s, render %s, vendor %s was detected."))) % (s_gl_info.is_core_profile() ? "3.3" : "2.0") % s_gl_info.get_version() % s_gl_info.get_renderer() % s_gl_info.get_vendor()).str()); + "while OpenGL version %s, render %s, vendor %s was detected."))) % (s_gl_info.is_core_profile() ? "3.3" : "2.0") % s_gl_info.get_version_string() % s_gl_info.get_renderer() % s_gl_info.get_vendor()).str()); #else _utf8(L("PrusaSlicer requires OpenGL 2.0 capable graphics driver to run correctly, \n" - "while OpenGL version %s, render %s, vendor %s was detected."))) % s_gl_info.get_version() % s_gl_info.get_renderer() % s_gl_info.get_vendor()).str()); + "while OpenGL version %s, render %s, vendor %s was detected."))) % s_gl_info.get_version_string() % s_gl_info.get_renderer() % s_gl_info.get_vendor()).str()); #endif // ENABLE_OPENGL_ES message += "\n"; message += _L("You may need to update your graphics card driver."); @@ -423,7 +424,7 @@ bool OpenGLManager::init_gl() // WHQL: 4.6.14800 Compatibility Profile Context 22.6.1 30.0.21023.1015 // Non-WHQL: 4.6.0 Compatibility Profile Context 22.8.1.220810 std::regex version_rgx(R"(Compatibility\sProfile\sContext\s(\d+)\.(\d+)\.(\d+))"); - if (std::smatch matches; std::regex_search(gl_info.get_version(), matches, version_rgx) && matches.size() == 4) { + if (std::smatch matches; std::regex_search(gl_info.get_version_string(), matches, version_rgx) && matches.size() == 4) { int version_major = std::stoi(matches[1].str()); int version_minor = std::stoi(matches[2].str()); int version_patch = std::stoi(matches[3].str()); diff --git a/src/slic3r/GUI/OpenGLManager.hpp b/src/slic3r/GUI/OpenGLManager.hpp index 5c810d83ef..ece9009622 100644 --- a/src/slic3r/GUI/OpenGLManager.hpp +++ b/src/slic3r/GUI/OpenGLManager.hpp @@ -31,16 +31,21 @@ public: int m_max_tex_size{ 0 }; float m_max_anisotropy{ 0.0f }; - std::string m_version; - std::string m_glsl_version; + std::string m_version_string; + Semver m_version = Semver::invalid(); + bool m_version_is_mesa = false; + + std::string m_glsl_version_string; + Semver m_glsl_version = Semver::invalid(); + std::string m_vendor; std::string m_renderer; public: GLInfo() = default; - const std::string& get_version() const; - const std::string& get_glsl_version() const; + const std::string& get_version_string() const; + const std::string& get_glsl_version_string() const; const std::string& get_vendor() const; const std::string& get_renderer() const; diff --git a/src/slic3r/GUI/SendSystemInfoDialog.cpp b/src/slic3r/GUI/SendSystemInfoDialog.cpp index 298b3242d5..dfb442d18c 100644 --- a/src/slic3r/GUI/SendSystemInfoDialog.cpp +++ b/src/slic3r/GUI/SendSystemInfoDialog.cpp @@ -504,8 +504,8 @@ static std::string generate_system_info_json() #endif // _WIN32 pt::ptree opengl_node; - opengl_node.put("Version", OpenGLManager::get_gl_info().get_version()); - opengl_node.put("GLSLVersion", OpenGLManager::get_gl_info().get_glsl_version()); + opengl_node.put("Version", OpenGLManager::get_gl_info().get_version_string()); + opengl_node.put("GLSLVersion", OpenGLManager::get_gl_info().get_glsl_version_string()); opengl_node.put("Vendor", OpenGLManager::get_gl_info().get_vendor()); opengl_node.put("Renderer", OpenGLManager::get_gl_info().get_renderer()); // Generate list of OpenGL extensions: