Measurement: moving arrow-drawing functions from frontend to the backend (1/4)

This commit is contained in:
Lukas Matena 2022-09-29 11:22:23 +02:00
parent ee088bf798
commit 5ad4fafbf1
4 changed files with 92 additions and 72 deletions

View File

@ -349,7 +349,7 @@ std::optional<SurfaceFeature> MeasuringImpl::get_feature(size_t face_idx, const
// which is needless and relatively expensive. // which is needless and relatively expensive.
res = get_measurement(plane.surface_features[i], point_sf); res = get_measurement(plane.surface_features[i], point_sf);
if (res.distance_strict) { // TODO: this should become an assert after all combinations are implemented. if (res.distance_strict) { // TODO: this should become an assert after all combinations are implemented.
double dist = *res.distance_strict; double dist = res.distance_strict->dist;
if (dist < feature_hover_limit && dist < min_dist) { if (dist < feature_hover_limit && dist < min_dist) {
min_dist = std::min(dist, min_dist); min_dist = std::min(dist, min_dist);
closest_feature_idx = i; closest_feature_idx = i;
@ -455,8 +455,9 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature&
if (f1.get_type() == SurfaceFeatureType::Point) { if (f1.get_type() == SurfaceFeatureType::Point) {
if (f2.get_type() == SurfaceFeatureType::Point) { if (f2.get_type() == SurfaceFeatureType::Point) {
Vec3d diff = (f2.get_point() - f1.get_point()); Vec3d diff = (f2.get_point() - f1.get_point());
result.distance_strict = diff.norm(); result.distance_strict = std::make_optional(DistAndPoints{diff.norm(), f1.get_point(), f2.get_point()});
result.distance_xyz = diff; result.distance_xyz = diff;
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
} else if (f2.get_type() == SurfaceFeatureType::Edge) { } else if (f2.get_type() == SurfaceFeatureType::Edge) {
const auto& [s,e] = f2.get_edge(); const auto& [s,e] = f2.get_edge();
@ -468,11 +469,12 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature&
double dist_end_sq = (proj-e).squaredNorm(); double dist_end_sq = (proj-e).squaredNorm();
if (dist_start_sq < len_sq && dist_end_sq < len_sq) { if (dist_start_sq < len_sq && dist_end_sq < len_sq) {
// projection falls on the line - the strict distance is the same as infinite // projection falls on the line - the strict distance is the same as infinite
result.distance_strict = std::make_optional(dist_inf); result.distance_strict = std::make_optional(DistAndPoints{dist_inf, f1.get_point(), proj}); // TODO
} else { // the result is the closer of the endpoints } else { // the result is the closer of the endpoints
result.distance_strict = std::make_optional(std::sqrt(std::min(dist_start_sq, dist_end_sq) + dist_inf)); bool s_is_closer = dist_start_sq < dist_end_sq;
result.distance_strict = std::make_optional(DistAndPoints{std::sqrt(std::min(dist_start_sq, dist_end_sq) + dist_inf), f1.get_point(), s_is_closer ? s : e});
} }
result.distance_infinite = std::make_optional(dist_inf); result.distance_infinite = std::make_optional(DistAndPoints{dist_inf, f1.get_point(), proj}); // TODO
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
} else if (f2.get_type() == SurfaceFeatureType::Circle) { } else if (f2.get_type() == SurfaceFeatureType::Circle) {
// Find a plane containing normal, center and the point. // Find a plane containing normal, center and the point.
@ -482,12 +484,13 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature&
double dist = std::sqrt(std::pow((proj - c).norm() - radius, 2.) + double dist = std::sqrt(std::pow((proj - c).norm() - radius, 2.) +
(f1.get_point() - proj).squaredNorm()); (f1.get_point() - proj).squaredNorm());
result.distance_strict = std::make_optional(dist); const Vec3d p_on_circle = c + radius * (circle_plane.projection(f1.get_point()) - c).normalized();
result.distance_strict = std::make_optional(DistAndPoints{dist, f1.get_point(), p_on_circle}); // TODO
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
} else if (f2.get_type() == SurfaceFeatureType::Plane) { } else if (f2.get_type() == SurfaceFeatureType::Plane) {
const auto& [idx, normal, pt] = f2.get_plane(); const auto& [idx, normal, pt] = f2.get_plane();
Eigen::Hyperplane<double, 3> plane(normal, pt); Eigen::Hyperplane<double, 3> plane(normal, pt);
result.distance_infinite = plane.absDistance(f1.get_point()); result.distance_infinite = std::make_optional(DistAndPoints{plane.absDistance(f1.get_point()), f1.get_point(), plane.projection(f1.get_point())}); // TODO
// TODO: result.distance_strict = // TODO: result.distance_strict =
} }
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
@ -495,18 +498,23 @@ 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) { if (f2.get_type() == SurfaceFeatureType::Edge) {
result.distance_infinite = std::make_optional(DistAndPoints{0., Vec3d::Zero(), Vec3d::Zero()}); // TODO
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
} else if (f2.get_type() == SurfaceFeatureType::Circle) { } else if (f2.get_type() == SurfaceFeatureType::Circle) {
result.distance_infinite = std::make_optional(DistAndPoints{0., Vec3d::Zero(), Vec3d::Zero()}); // TODO
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
} else if (f2.get_type() == SurfaceFeatureType::Plane) { } else if (f2.get_type() == SurfaceFeatureType::Plane) {
result.distance_infinite = std::make_optional(DistAndPoints{0., Vec3d::Zero(), Vec3d::Zero()}); // TODO
} }
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
} else if (f1.get_type() == SurfaceFeatureType::Circle) { } else if (f1.get_type() == SurfaceFeatureType::Circle) {
if (f2.get_type() == SurfaceFeatureType::Circle) { if (f2.get_type() == SurfaceFeatureType::Circle) {
result.distance_infinite = std::make_optional(DistAndPoints{0., Vec3d::Zero(), Vec3d::Zero()}); // TODO
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
} else if (f2.get_type() == SurfaceFeatureType::Plane) { } else if (f2.get_type() == SurfaceFeatureType::Plane) {
result.distance_infinite = std::make_optional(DistAndPoints{0., Vec3d::Zero(), Vec3d::Zero()}); // TODO
} }
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
@ -521,7 +529,7 @@ MeasurementResult get_measurement(const SurfaceFeature& a, const SurfaceFeature&
if (normal1.isApprox(normal2)) { if (normal1.isApprox(normal2)) {
// The planes are parallel, calculate distance. // The planes are parallel, calculate distance.
Eigen::Hyperplane<double, 3> plane(normal1, pt1); Eigen::Hyperplane<double, 3> plane(normal1, pt1);
result.distance_infinite = plane.absDistance(pt2); result.distance_infinite = std::make_optional(DistAndPoints{plane.absDistance(pt2), Vec3d::Zero(), Vec3d::Zero()});
} else { } else {
// Planes are not parallel, calculate angle. // Planes are not parallel, calculate angle.
angle = std::acos(std::abs(normal1.dot(normal2))); angle = std::acos(std::abs(normal1.dot(normal2)));

View File

@ -110,12 +110,16 @@ private:
}; };
struct DistAndPoints {
double dist;
Vec3d from;
Vec3d to;
};
struct MeasurementResult { struct MeasurementResult {
std::optional<double> angle; std::optional<double> angle;
std::optional<double> distance_infinite; std::optional<DistAndPoints> distance_infinite;
std::optional<double> distance_strict; std::optional<DistAndPoints> distance_strict;
std::optional<Vec3d> distance_xyz; std::optional<Vec3d> distance_xyz;
bool has_any_data() const { bool has_any_data() const {

View File

@ -72,13 +72,6 @@ static std::string point_on_feature_type_as_string(Measure::SurfaceFeatureType t
return ret; return ret;
} }
static std::tuple<double, Vec3d, Vec3d> distance_point_plane(const Vec3d& v, const Plane& p)
{
const auto& [idx, normal, origin] = p;
const Eigen::Hyperplane<double, 3> plane(normal, origin);
return std::make_tuple(plane.absDistance(v), v, plane.projection(v));
}
static Vec3d vector_direction(const Vec3d& from, const Vec3d& to) static Vec3d vector_direction(const Vec3d& from, const Vec3d& to)
{ {
return (to - from).normalized(); return (to - from).normalized();
@ -89,21 +82,13 @@ static Vec3d edge_direction(const Edge& e)
return vector_direction(e.first, e.second); return vector_direction(e.first, e.second);
} }
// returns: distance, 1st vertex, 2nd vertex
static std::tuple<double, Vec3d, Vec3d> distance_point_edge(const Vec3d& v, const Edge& e)
{
const Eigen::ParametrizedLine<double, 3> line = Eigen::ParametrizedLine<double, 3>::Through(e.first, e.second);
return std::make_tuple(line.distance(v), v, line.projection(v));
}
// returns: distance, 1st vertex, 2nd vertex
static std::tuple<double, Vec3d, Vec3d> distance_point_circle(const Vec3d& v, const Circle& c)
{
const auto& [center, radius, normal] = c;
const Eigen::Hyperplane<double, 3> plane(normal, center); /*
const Vec3d p_on_circle = center + radius * vector_direction(center, plane.projection(v));
return std::make_tuple((v - p_on_circle).norm(), v, p_on_circle);
}
// returns: distance, 1st vertex, 2nd vertex // returns: distance, 1st vertex, 2nd vertex
static std::tuple<double, Vec3d, Vec3d> distance_edge_edge(const Edge& e1, const Edge& e2) static std::tuple<double, Vec3d, Vec3d> distance_edge_edge(const Edge& e1, const Edge& e2)
@ -165,6 +150,34 @@ static std::tuple<double, Vec3d, Vec3d> distance_plane_plane(const Plane& p1, co
return (std::abs(std::abs(normal1.dot(normal2)) - 1.0) < EPSILON) ? distance_point_plane(origin2, p1) : return (std::abs(std::abs(normal1.dot(normal2)) - 1.0) < EPSILON) ? distance_point_plane(origin2, p1) :
std::make_tuple(0.0, Vec3d::Zero(), Vec3d::Zero()); std::make_tuple(0.0, Vec3d::Zero(), Vec3d::Zero());
} }
*/
// returns: angle in rad, center of arc, radius of arc, whether or not the edges are coplanar // returns: angle in rad, center of arc, radius of arc, whether or not the edges are coplanar
// After return, the edges are oriented so that they point away from their intersection point // After return, the edges are oriented so that they point away from their intersection point
@ -278,6 +291,9 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event)
} }
else if (mouse_event.LeftDown()) { else if (mouse_event.LeftDown()) {
if (m_hover_id != -1) { if (m_hover_id != -1) {
SelectedFeatures selected_features_old = m_selected_features;
m_mouse_left_down = true; m_mouse_left_down = true;
auto item_from_feature = [this]() { auto item_from_feature = [this]() {
@ -319,6 +335,10 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event)
if (m_mode == EMode::ExtendedSelection) if (m_mode == EMode::ExtendedSelection)
m_selection_raycasters.push_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, SELECTION_1_ID, *m_sphere.mesh_raycaster)); m_selection_raycasters.push_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, SELECTION_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);
return true; return true;
} }
@ -963,8 +983,11 @@ void GLGizmoMeasure::render_dimensioning()
m_dimensioning.triangle.render(); m_dimensioning.triangle.render();
}; };
auto point_edge = [this, shader, point_point](const Vec3d& v, const Edge& e) { auto point_edge = [this, shader, point_point](const Vec3d& v, const Edge& e) {
const auto [distance, v1, v_proj] = distance_point_edge(v, e); const double distance = m_measurement_result.distance_infinite->dist;
const Vec3d v1 = m_measurement_result.distance_infinite->from;
const Vec3d v_proj = m_measurement_result.distance_infinite->to;
point_point(v1, v_proj); point_point(v1, v_proj);
const Vec3d e1e2 = e.second - e.first; const Vec3d e1e2 = e.second - e.first;
@ -997,16 +1020,7 @@ void GLGizmoMeasure::render_dimensioning()
} }
}; };
auto point_plane = [point_point](const Vec3d& v, const Plane& p) { /*
const auto [distance, v1, v2] = distance_point_plane(v, p);
point_point(v1, v2);
};
auto point_circle = [point_point](const Vec3d& v, const Circle& c) {
const auto [distance, v1, v2] = distance_point_circle(v, c);
point_point(v1, v2);
};
auto arc_edge_edge = [this, shader](const Edge& e1, const Edge& e2, const double* const force_radius = nullptr) { auto arc_edge_edge = [this, shader](const Edge& e1, const Edge& e2, const double* const force_radius = nullptr) {
Edge e1copy = e1; Edge e1copy = e1;
Edge e2copy = e2; Edge e2copy = e2;
@ -1130,7 +1144,7 @@ void GLGizmoMeasure::render_dimensioning()
auto plane_plane = [point_point](const Plane& p1, const Plane& p2) { auto plane_plane = [point_point](const Plane& p1, const Plane& p2) {
const auto [distance, v1, v2] = distance_plane_plane(p1, p2); const auto [distance, v1, v2] = distance_plane_plane(p1, p2);
point_point(v1, v2); point_point(v1, v2);
}; };*/
shader->start_using(); shader->start_using();
@ -1174,26 +1188,26 @@ void GLGizmoMeasure::render_dimensioning()
glsafe(::glDisable(GL_DEPTH_TEST)); glsafe(::glDisable(GL_DEPTH_TEST));
// point-point // Render the arrow between the points that the backend passed:
if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Point && if (m_selected_features.second.feature.has_value()) {
m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Point) { const Measure::DistAndPoints& dap = m_measurement_result.distance_infinite.has_value()
point_point(m_selected_features.first.feature->get_point(), m_selected_features.second.feature->get_point()); ? *m_measurement_result.distance_infinite
: *m_measurement_result.distance_strict;
point_point(dap.from, dap.to);
} }
// Now if one of the features is an edge, draw also the extension of the edge to where the dist is measured:
// TODO...
// point-edge // point-edge
else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Point && else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Point &&
m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Edge) { m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Edge) {
point_edge(m_selected_features.first.feature->get_point(), m_selected_features.second.feature->get_edge()); point_edge(m_selected_features.first.feature->get_point(), m_selected_features.second.feature->get_edge());
} }
// point-plane
else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Point &&
m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Plane) { /*
point_plane(m_selected_features.first.feature->get_point(), m_selected_features.second.feature->get_plane());
}
// point-circle
else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Point &&
m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Circle) {
point_circle(m_selected_features.first.feature->get_point(), m_selected_features.second.feature->get_circle());
}
// edge-point // edge-point
else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Edge && else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Edge &&
m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Point) { m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Point) {
@ -1214,11 +1228,6 @@ void GLGizmoMeasure::render_dimensioning()
m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Circle) { m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Circle) {
edge_circle(m_selected_features.first.feature->get_edge(), m_selected_features.second.feature->get_circle()); edge_circle(m_selected_features.first.feature->get_edge(), m_selected_features.second.feature->get_circle());
} }
// plane-point
else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Plane &&
m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Point) {
point_plane(m_selected_features.second.feature->get_point(), m_selected_features.first.feature->get_plane());
}
// plane-edge // plane-edge
else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Plane && else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Plane &&
m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Edge) { m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Edge) {
@ -1229,16 +1238,12 @@ void GLGizmoMeasure::render_dimensioning()
m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Plane) { m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Plane) {
plane_plane(m_selected_features.first.feature->get_plane(), m_selected_features.second.feature->get_plane()); plane_plane(m_selected_features.first.feature->get_plane(), m_selected_features.second.feature->get_plane());
} }
// circle-point
else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Circle &&
m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Point) {
point_circle(m_selected_features.second.feature->get_point(), m_selected_features.first.feature->get_circle());
}
// circle-edge // circle-edge
else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Circle && else if (m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Circle &&
m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Edge) { m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Edge) {
edge_circle(m_selected_features.second.feature->get_edge(), m_selected_features.first.feature->get_circle()); edge_circle(m_selected_features.second.feature->get_edge(), m_selected_features.first.feature->get_circle());
} }
*/
glsafe(::glEnable(GL_DEPTH_TEST)); glsafe(::glEnable(GL_DEPTH_TEST));
@ -1520,7 +1525,8 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit
}; };
if (m_selected_features.second.feature.has_value()) { if (m_selected_features.second.feature.has_value()) {
const Measure::MeasurementResult measure = Measure::get_measurement(*m_selected_features.first.feature, *m_selected_features.second.feature); const Measure::MeasurementResult& measure = m_measurement_result;
ImGui::Separator(); ImGui::Separator();
if (measure.has_any_data()) { if (measure.has_any_data()) {
m_imgui->text(_u8L("Measure") + ":"); m_imgui->text(_u8L("Measure") + ":");
@ -1532,7 +1538,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit
ImGui::PopID(); ImGui::PopID();
} }
if (measure.distance_infinite.has_value()) { if (measure.distance_infinite.has_value()) {
double distance = *measure.distance_infinite; double distance = measure.distance_infinite->dist;
if (use_inches) if (use_inches)
distance = ObjectManipulation::mm_to_in * distance; distance = ObjectManipulation::mm_to_in * distance;
ImGui::PushID((void*)(intptr_t)2); ImGui::PushID((void*)(intptr_t)2);
@ -1541,7 +1547,7 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit
ImGui::PopID(); ImGui::PopID();
} }
if (measure.distance_strict.has_value()) { if (measure.distance_strict.has_value()) {
double distance = *measure.distance_strict; double distance = measure.distance_strict->dist;
if (use_inches) if (use_inches)
distance = ObjectManipulation::mm_to_in * distance; distance = ObjectManipulation::mm_to_in * distance;
ImGui::PushID((void*)(intptr_t)3); ImGui::PushID((void*)(intptr_t)3);

View File

@ -70,7 +70,9 @@ class GLGizmoMeasure : public GLGizmoBase
}; };
EMode m_mode{ EMode::BasicSelection }; EMode m_mode{ EMode::BasicSelection };
std::unique_ptr<Measure::Measuring> m_measuring; Measure::MeasurementResult m_measurement_result;
std::unique_ptr<Measure::Measuring> m_measuring; // PIMPL
PickingModel m_sphere; PickingModel m_sphere;
PickingModel m_cylinder; PickingModel m_cylinder;