diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 2a856fb830..2c040c9c3b 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -55,8 +55,7 @@ GLGizmoMeasure::GLGizmoMeasure(GLCanvas3D& parent, const std::string& icon_filen bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event) { - m_mouse_pos_x = mouse_event.GetX(); - m_mouse_pos_y = mouse_event.GetY(); + m_mouse_pos = { double(mouse_event.GetX()), double(mouse_event.GetY()) }; if (mouse_event.Moving()) { // only for sure @@ -106,7 +105,7 @@ bool GLGizmoMeasure::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_po { if (action == SLAGizmoEventType::CtrlDown) { if (m_ctrl_kar_filter.is_first()) { - if (!m_features.empty()) + if (m_curr_feature.has_value()) m_mode = EMode::ExtendedSelection; } @@ -171,80 +170,84 @@ void GLGizmoMeasure::on_render() Vec3f pos; Vec3f normal; size_t facet_idx; - m_c->raycaster()->raycasters().front()->unproject_on_mesh(Vec2d(m_mouse_pos_x, m_mouse_pos_y), model_matrix, camera, pos, normal, nullptr, &facet_idx); + m_c->raycaster()->raycasters().front()->unproject_on_mesh(m_mouse_pos, model_matrix, camera, pos, normal, nullptr, &facet_idx); - std::vector features; - if (m_mode == EMode::BasicSelection) { - std::optional feat = m_measuring->get_feature(facet_idx, pos.cast()); - if (feat.has_value()) - features.emplace_back(*feat); - } + std::optional curr_feature; + if (m_mode == EMode::BasicSelection) + curr_feature = m_measuring->get_feature(facet_idx, pos.cast()); if (m_mode == EMode::BasicSelection) { - if (m_features != features) { + if (m_curr_feature != curr_feature) { GLGizmoMeasure::on_unregister_raycasters_for_picking(); - m_features = features; - if (m_features.empty()) + m_curr_feature = curr_feature; + if (!m_curr_feature.has_value()) return; - for (const Measure::SurfaceFeature& feature : m_features) { - switch (feature.get_type()) { - 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) }); - break; - } - case Measure::SurfaceFeatureType::Circle: - { - const auto& [center, radius, n] = feature.get_circle(); - m_circle.reset(); - GLModel::Geometry circle_geometry = smooth_torus(64, 16, float(radius), 5.0f * inv_zoom); - m_circle.mesh_raycaster = std::make_unique(std::make_shared(std::move(circle_geometry.get_as_indexed_triangle_set()))); - m_circle.model.init_from(std::move(circle_geometry)); + switch (m_curr_feature->get_type()) { + 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) }); + break; + } + case Measure::SurfaceFeatureType::Circle: + { + const auto& [center, radius, n] = m_curr_feature->get_circle(); - m_raycasters.insert({ CIRCLE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_ID, *m_circle.mesh_raycaster) }); - m_raycasters.insert({ CIRCLE_CENTER_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_CENTER_ID, *m_sphere.mesh_raycaster) }); - break; - } - case Measure::SurfaceFeatureType::Plane: - { - const auto& [idx, normal, pt] = feature.get_plane(); - const std::vector> planes_triangles = m_measuring->get_planes_triangle_indices(); - const std::vector& triangle_indices = planes_triangles[idx]; + // TODO: check for changed inv_zoom - const indexed_triangle_set its = (m_old_model_volume != nullptr) ? m_old_model_volume->mesh().its : m_old_model_object->volumes.front()->mesh().its; - GLModel::Geometry init_data; - init_data.format = { GUI::GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 }; - unsigned int i = 0; - for (int idx : triangle_indices) { - const Vec3f& v0 = its.vertices[its.indices[idx][0]]; - const Vec3f& v1 = its.vertices[its.indices[idx][1]]; - const Vec3f& v2 = its.vertices[its.indices[idx][2]]; + m_circle.reset(); + GLModel::Geometry circle_geometry = smooth_torus(64, 16, float(radius), 5.0f * inv_zoom); + m_circle.mesh_raycaster = std::make_unique(std::make_shared(std::move(circle_geometry.get_as_indexed_triangle_set()))); + m_circle.model.init_from(std::move(circle_geometry)); - const Vec3f n = (v1 - v0).cross(v2 - v0).normalized(); - init_data.add_vertex(v0, n); - init_data.add_vertex(v1, n); - init_data.add_vertex(v2, n); - init_data.add_triangle(i, i + 1, i + 2); - i += 3; - } + m_raycasters.insert({ CIRCLE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_ID, *m_circle.mesh_raycaster) }); + m_raycasters.insert({ CIRCLE_CENTER_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_CENTER_ID, *m_sphere.mesh_raycaster) }); + break; + } + case Measure::SurfaceFeatureType::Plane: + { + const auto& [idx, normal, pt] = m_curr_feature->get_plane(); - m_plane.reset(); - m_plane.mesh_raycaster = std::make_unique(std::make_shared(std::move(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; - } + // TODO: check for changed idx + + const std::vector> planes_triangles = m_measuring->get_planes_triangle_indices(); + const std::vector& triangle_indices = planes_triangles[idx]; + + const indexed_triangle_set its = (m_old_model_volume != nullptr) ? m_old_model_volume->mesh().its : m_old_model_object->volumes.front()->mesh().its; + GLModel::Geometry init_data; + init_data.format = { GUI::GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 }; + unsigned int i = 0; + for (int idx : triangle_indices) { + const Vec3f& v0 = its.vertices[its.indices[idx][0]]; + const Vec3f& v1 = its.vertices[its.indices[idx][1]]; + const Vec3f& v2 = its.vertices[its.indices[idx][2]]; + + const Vec3f n = (v1 - v0).cross(v2 - v0).normalized(); + init_data.add_vertex(v0, n); + init_data.add_vertex(v1, n); + init_data.add_vertex(v2, n); + init_data.add_triangle(i, i + 1, i + 2); + i += 3; } + + m_plane.reset(); + m_plane.mesh_raycaster = std::make_unique(std::make_shared(std::move(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_curr_feature.has_value()) + return; + GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light"); if (shader == nullptr) return; @@ -265,84 +268,84 @@ void GLGizmoMeasure::on_render() case EMode::ExtendedSelection: { color = LOCK_COLOR; break; } } - for (const Measure::SurfaceFeature& feature : m_features) { - switch (feature.get_type()) { - case Measure::SurfaceFeatureType::Point: - { - const Vec3d& position = feature.get_point(); - const Transform3d feature_matrix = model_matrix * Geometry::translation_transform(position) * Geometry::scale_transform(inv_zoom); - const Transform3d view_model_matrix = view_matrix * feature_matrix; - shader->set_uniform("view_model_matrix", view_model_matrix); - const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * feature_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); - shader->set_uniform("view_normal_matrix", view_normal_matrix); - m_sphere.model.set_color(color); - m_sphere.model.render(); - 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, n] = feature.get_circle(); - // render center - const Transform3d center_matrix = model_matrix * Geometry::translation_transform(center) * Geometry::scale_transform(inv_zoom); - const Transform3d center_view_model_matrix = view_matrix * center_matrix; - shader->set_uniform("view_model_matrix", center_view_model_matrix); - const Matrix3d center_view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * center_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); - shader->set_uniform("view_normal_matrix", center_view_normal_matrix); - m_sphere.model.set_color(color); - m_sphere.model.render(); - auto it = m_raycasters.find(CIRCLE_CENTER_ID); - if (it != m_raycasters.end() && it->second != nullptr) - it->second->set_transform(center_matrix); - - const Transform3d circle_matrix = model_matrix * Geometry::translation_transform(center); - const Transform3d circle_view_model_matrix = view_matrix * circle_matrix; - shader->set_uniform("view_model_matrix", circle_view_model_matrix); - const Matrix3d circle_view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * circle_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); - shader->set_uniform("view_normal_matrix", circle_view_normal_matrix); - m_circle.model.set_color(color); - m_circle.model.render(); - it = m_raycasters.find(CIRCLE_ID); - if (it != m_raycasters.end() && it->second != nullptr) - it->second->set_transform(circle_matrix); - break; - } - case Measure::SurfaceFeatureType::Edge: - { - const auto& [start, end] = feature.get_edge(); - auto q = Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), end - start); - const Transform3d feature_matrix = model_matrix * Geometry::translation_transform(start) * q * - Geometry::scale_transform({ (double)inv_zoom, (double)inv_zoom, (end - start).norm() }); - const Transform3d view_model_matrix = view_matrix * feature_matrix; - shader->set_uniform("view_model_matrix", view_model_matrix); - const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * feature_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); - shader->set_uniform("view_normal_matrix", view_normal_matrix); - m_cylinder.model.set_color(color); - m_cylinder.model.render(); - auto it = m_raycasters.find(EDGE_ID); - if (it != m_raycasters.end() && it->second != nullptr) - it->second->set_transform(feature_matrix); - break; - } - case Measure::SurfaceFeatureType::Plane: - { - const auto& [idx, normal, pt] = feature.get_plane(); - assert(idx < m_plane_models_cache.size()); - 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); - m_plane_models_cache[idx].set_color(color); - m_plane_models_cache[idx].render(); - auto it = m_raycasters.find(PLANE_ID); - if (it != m_raycasters.end() && it->second != nullptr) - it->second->set_transform(model_matrix); - break; - } - } + switch (m_curr_feature->get_type()) { + case Measure::SurfaceFeatureType::Point: + { + const Vec3d& position = m_curr_feature->get_point(); + const Transform3d feature_matrix = model_matrix * Geometry::translation_transform(position) * Geometry::scale_transform(inv_zoom); + const Transform3d view_model_matrix = view_matrix * feature_matrix; + shader->set_uniform("view_model_matrix", view_model_matrix); + const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * feature_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); + shader->set_uniform("view_normal_matrix", view_normal_matrix); + m_sphere.model.set_color(color); + m_sphere.model.render(); + 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, n] = m_curr_feature->get_circle(); + // render center + const Transform3d center_matrix = model_matrix * Geometry::translation_transform(center) * Geometry::scale_transform(inv_zoom); + const Transform3d center_view_model_matrix = view_matrix * center_matrix; + shader->set_uniform("view_model_matrix", center_view_model_matrix); + const Matrix3d center_view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * center_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); + shader->set_uniform("view_normal_matrix", center_view_normal_matrix); + m_sphere.model.set_color(color); + m_sphere.model.render(); + auto it = m_raycasters.find(CIRCLE_CENTER_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(center_matrix); + + // render circle + const Transform3d circle_matrix = model_matrix * Geometry::translation_transform(center); + const Transform3d circle_view_model_matrix = view_matrix * circle_matrix; + shader->set_uniform("view_model_matrix", circle_view_model_matrix); + const Matrix3d circle_view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * circle_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); + shader->set_uniform("view_normal_matrix", circle_view_normal_matrix); + m_circle.model.set_color(color); + m_circle.model.render(); + it = m_raycasters.find(CIRCLE_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(circle_matrix); + break; + } + case Measure::SurfaceFeatureType::Edge: + { + const auto& [start, end] = m_curr_feature->get_edge(); + auto q = Eigen::Quaternion::FromTwoVectors(Vec3d::UnitZ(), end - start); + const Transform3d feature_matrix = model_matrix * Geometry::translation_transform(start) * q * + Geometry::scale_transform({ (double)inv_zoom, (double)inv_zoom, (end - start).norm() }); + const Transform3d view_model_matrix = view_matrix * feature_matrix; + shader->set_uniform("view_model_matrix", view_model_matrix); + const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * feature_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); + shader->set_uniform("view_normal_matrix", view_normal_matrix); + m_cylinder.model.set_color(color); + m_cylinder.model.render(); + auto it = m_raycasters.find(EDGE_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(feature_matrix); + break; + } + case Measure::SurfaceFeatureType::Plane: + { + const auto& [idx, normal, pt] = m_curr_feature->get_plane(); + assert(idx < m_plane_models_cache.size()); + 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); + m_plane_models_cache[idx].set_color(color); + m_plane_models_cache[idx].render(); + auto it = m_raycasters.find(PLANE_ID); + if (it != m_raycasters.end() && it->second != nullptr) + it->second->set_transform(model_matrix); + break; + } + } + shader->stop_using(); } } @@ -426,7 +429,8 @@ void GLGizmoMeasure::update_if_needed() void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit) { - static Measure::SurfaceFeature last_feature = Measure::SurfaceFeature(Measure::SurfaceFeatureType::Undef, Vec3d::Zero(), Vec3d::Zero(), std::nullopt, 0.0); + static std::optional last_feature; + static EMode last_mode = EMode::BasicSelection; static float last_y = 0.0f; static float last_h = 0.0f; @@ -446,31 +450,27 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit last_y = y; } - if (m_features.empty()) + if (!m_curr_feature.has_value()) m_imgui->text(_u8L("Select features to measure")); + else { + auto add_row_to_table = [this](const wxString& label, const std::string& value) { + ImGui::TableNextRow(); + ImGui::TableSetColumnIndex(0); + m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, label); + ImGui::TableSetColumnIndex(1); + m_imgui->text(value); + }; - auto add_row_to_table = [this](const wxString& label, const std::string& value) { - ImGui::TableNextRow(); - ImGui::TableSetColumnIndex(0); - m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, label); - ImGui::TableSetColumnIndex(1); - m_imgui->text(value); - }; - - const Transform3d volume_matrix = m_parent.get_selection().get_first_volume()->world_matrix(); - Measure::SurfaceFeature curr_feature = Measure::SurfaceFeature(Measure::SurfaceFeatureType::Undef, Vec3d::Zero(), Vec3d::Zero(), std::nullopt, 0.0); - for (size_t i = 0; i < m_features.size(); ++i) { - curr_feature = m_features[i]; - const Measure::SurfaceFeatureType type = curr_feature.get_type(); + const Transform3d volume_matrix = m_parent.get_selection().get_first_volume()->world_matrix(); + const Measure::SurfaceFeatureType type = m_curr_feature->get_type(); if (type != Measure::SurfaceFeatureType::Undef) { - const std::string header = surface_feature_type_as_string(type) + std::string("##") + std::to_string(i); - if (ImGui::CollapsingHeader(header.c_str(), ImGuiTreeNodeFlags_DefaultOpen)) { + if (ImGui::CollapsingHeader(surface_feature_type_as_string(type).c_str(), ImGuiTreeNodeFlags_DefaultOpen)) { if (ImGui::BeginTable("Data", 2)) { switch (type) { case Measure::SurfaceFeatureType::Point: { - const Vec3d position = volume_matrix * curr_feature.get_point(); + const Vec3d position = volume_matrix * m_curr_feature->get_point(); char buf[1024]; sprintf(buf, "X: %.3f, Y: %.3f, Z: %.3f", position.x(), position.y(), position.z()); add_row_to_table(_u8L("Position") + ":", std::string(buf)); @@ -478,7 +478,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit } case Measure::SurfaceFeatureType::Edge: { - auto [from, to] = curr_feature.get_edge(); + auto [from, to] = m_curr_feature->get_edge(); from = volume_matrix * from; to = volume_matrix * to; char buf[1024]; @@ -490,7 +490,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit } case Measure::SurfaceFeatureType::Circle: { - auto [center, radius, normal] = curr_feature.get_circle(); + auto [center, radius, normal] = m_curr_feature->get_circle(); center = volume_matrix * center; normal = volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal; char buf[1024]; @@ -504,7 +504,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit } case Measure::SurfaceFeatureType::Plane: { - auto [idx, normal, origin] = curr_feature.get_plane(); + auto [idx, normal, origin] = m_curr_feature->get_plane(); origin = volume_matrix * origin; normal = volume_matrix.matrix().block(0, 0, 3, 3).inverse().transpose() * normal; char buf[1024]; @@ -521,14 +521,15 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit } } - if (last_feature != curr_feature) { + if (last_feature != m_curr_feature || last_mode != m_mode) { // the dialog may have changed its size, ask for an extra frame to render it properly - last_feature = curr_feature; + last_feature = m_curr_feature; + last_mode = m_mode; m_imgui->set_requires_extra_frame(); } - if (!m_features.empty()) { - static const std::string ctrl = + if (m_curr_feature.has_value() && m_mode == EMode::BasicSelection) { + static const std::string ctrl = #ifdef __APPLE__ "⌘" #else diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 13c46a48d9..093584c7f4 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -41,7 +41,7 @@ class GLGizmoMeasure : public GLGizmoBase std::vector m_plane_models_cache; std::map> m_raycasters; - std::vector m_features; + std::optional m_curr_feature; // This holds information to decide whether recalculation is necessary: std::vector m_volumes_matrices; @@ -50,13 +50,10 @@ class GLGizmoMeasure : public GLGizmoBase Vec3d m_first_instance_mirror{ Vec3d::Ones() }; bool m_mouse_left_down = false; // for detection left_up of this gizmo - bool m_planes_valid = false; const ModelObject* m_old_model_object = nullptr; const ModelVolume* m_old_model_volume = nullptr; - std::vector instances_matrices; - int m_mouse_pos_x; - int m_mouse_pos_y; + Vec2d m_mouse_pos{ Vec2d::Zero() }; KeyAutoRepeatFilter m_ctrl_kar_filter;