Gizmo measure - Modified circle and edge with extra point selection

This commit is contained in:
enricoturri1966 2022-11-30 11:58:02 +01:00
parent 5a3f36da01
commit 2a82f1d396
2 changed files with 320 additions and 208 deletions

View File

@ -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<Vec3d> 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<SceneRaycasterItem> 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>(), float(radius), 5.0f * inv_zoom, normal.cast<float>(), 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>(), float(radius), 5.0f * inv_zoom, normal.cast<float>(), 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<double>::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<Vec3d> 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<double>::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<ColorRGBA> 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<ColorRGBA> 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<SceneRaycasterItem> 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<Measure::SurfaceFeature> feature_to_render;
std::vector<ColorRGBA> 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<SceneRaycasterItem> 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<ColorRGBA> 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<SceneRaycasterItem> 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<Measure::SurfaceFeature> feature_to_render;
std::vector<ColorRGBA> 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<SceneRaycasterItem> 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<SceneRaycasterItem> 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

View File

@ -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<Measure::SurfaceFeature> source;
std::optional<Measure::SurfaceFeature> 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<GLModel> m_plane_models_cache;
std::map<int, std::shared_ptr<SceneRaycasterItem>> m_raycasters;
std::vector<std::shared_ptr<SceneRaycasterItem>> m_selection_raycasters;
// used to keep the raycasters for point/center spheres
std::vector<std::shared_ptr<SceneRaycasterItem>> m_selected_sphere_raycasters;
std::optional<Measure::SurfaceFeature> m_curr_feature;
std::optional<Vec3d> 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