FIX:very small face can't be selected in assembly gizmo

jira: STUDIO-7594
Change-Id: Ibc2f0e80b9d5ef20de6997527b0dde09aee8d32b
This commit is contained in:
zhou.xu 2024-07-15 15:13:28 +08:00 committed by Lane.Wei
parent 2a7ee65e8b
commit 85aa6fddfc
4 changed files with 59 additions and 49 deletions

View File

@ -57,7 +57,7 @@ static std::tuple<Vec3d, double, double> get_center_and_radius(const std::vector
double error = std::numeric_limits<double>::max();
auto circle = Geometry::circle_ransac(out, iter, &error);
return std::make_tuple(trafo.inverse() * Vec3d(circle.center.x(), circle.center.y(), z), circle.radius, error);
}
@ -93,7 +93,7 @@ public:
bool features_extracted = false;
};
std::optional<SurfaceFeature> get_feature(size_t face_idx, const Vec3d& point, const Transform3d &world_tran);
std::optional<SurfaceFeature> get_feature(size_t face_idx, const Vec3d &point, const Transform3d &world_tran,bool only_select_plane);
int get_num_of_planes() const;
const std::vector<int>& get_plane_triangle_indices(int idx) const;
std::vector<int>* get_plane_tri_indices(int idx);
@ -184,7 +184,7 @@ void MeasuringImpl::update_planes()
m_planes.back().normal = normal_ptr->cast<double>();
std::sort(m_planes.back().facets.begin(), m_planes.back().facets.end());
}
// Check that each facet is part of one of the planes.
assert(std::none_of(m_face_to_plane.begin(), m_face_to_plane.end(), [](size_t val) { return val == size_t(-1); }));
@ -254,7 +254,7 @@ void MeasuringImpl::update_planes()
he = sm.opposite(he);
if (he.is_invalid())
goto PLANE_FAILURE;
Face_index fi = he.face();
auto face_it = std::lower_bound(facets.begin(), facets.end(), int(fi));
if (face_it == facets.end() || *face_it != int(fi)) // This indicates a broken mesh.
@ -526,7 +526,7 @@ void MeasuringImpl::extract_features(int plane_idx)
plane.features_extracted = true;
}
std::optional<SurfaceFeature> MeasuringImpl::get_feature(size_t face_idx, const Vec3d& point, const Transform3d &world_tran)
std::optional<SurfaceFeature> MeasuringImpl::get_feature(size_t face_idx, const Vec3d &point, const Transform3d &world_tran,bool only_select_plane)
{
if (face_idx >= m_face_to_plane.size())
return std::optional<SurfaceFeature>();
@ -544,46 +544,48 @@ std::optional<SurfaceFeature> MeasuringImpl::get_feature(size_t face_idx, const
assert(plane.surface_features.empty() || plane.surface_features.back().get_type() == SurfaceFeatureType::Plane);
for (size_t i=0; i<plane.surface_features.size() - 1; ++i) {
// The -1 is there to prevent measuring distance to the plane itself,
// which is needless and relatively expensive.
res = get_measurement(plane.surface_features[i], point_sf);
if (res.distance_strict) { // TODO: this should become an assert after all combinations are implemented.
double dist = res.distance_strict->dist;
if (dist < feature_hover_limit && dist < min_dist) {
min_dist = std::min(dist, min_dist);
closest_feature_idx = i;
if (!only_select_plane) {
for (size_t i = 0; i < plane.surface_features.size() - 1; ++i) {
// The -1 is there to prevent measuring distance to the plane itself,
// which is needless and relatively expensive.
res = get_measurement(plane.surface_features[i], point_sf);
if (res.distance_strict) { // TODO: this should become an assert after all combinations are implemented.
double dist = res.distance_strict->dist;
if (dist < feature_hover_limit && dist < min_dist) {
min_dist = std::min(dist, min_dist);
closest_feature_idx = i;
}
}
}
}
if (closest_feature_idx != size_t(-1)) {
const SurfaceFeature& f = plane.surface_features[closest_feature_idx];
if (f.get_type() == SurfaceFeatureType::Edge) {
// If this is an edge, check if we are not close to the endpoint. If so,
// we will include the endpoint as well. Close = 10% of the lenghth of
// the edge, clamped between 0.025 and 0.5 mm.
const auto& [sp, ep] = f.get_edge();
double len_sq = (ep-sp).squaredNorm();
double limit_sq = std::max(0.025*0.025, std::min(0.5*0.5, 0.1 * 0.1 * len_sq));
if ((point - sp).squaredNorm() < limit_sq) {
SurfaceFeature local_f(sp);
local_f.origin_surface_feature = std::make_shared<SurfaceFeature>(local_f);
local_f.translate(world_tran);
return std::make_optional(local_f);
if (closest_feature_idx != size_t(-1)) {
const SurfaceFeature &f = plane.surface_features[closest_feature_idx];
if (f.get_type() == SurfaceFeatureType::Edge) {
// If this is an edge, check if we are not close to the endpoint. If so,
// we will include the endpoint as well. Close = 10% of the lenghth of
// the edge, clamped between 0.025 and 0.5 mm.
const auto &[sp, ep] = f.get_edge();
double len_sq = (ep - sp).squaredNorm();
double limit_sq = std::max(0.025 * 0.025, std::min(0.5 * 0.5, 0.1 * 0.1 * len_sq));
if ((point - sp).squaredNorm() < limit_sq) {
SurfaceFeature local_f(sp);
local_f.origin_surface_feature = std::make_shared<SurfaceFeature>(local_f);
local_f.translate(world_tran);
return std::make_optional(local_f);
}
if ((point - ep).squaredNorm() < limit_sq) {
SurfaceFeature local_f(ep);
local_f.origin_surface_feature = std::make_shared<SurfaceFeature>(local_f);
local_f.translate(world_tran);
return std::make_optional(local_f);
}
}
if ((point - ep).squaredNorm() < limit_sq) {
SurfaceFeature local_f(ep);
local_f.origin_surface_feature = std::make_shared<SurfaceFeature>(local_f);
local_f.translate(world_tran);
return std::make_optional(local_f);
}
SurfaceFeature f_tran(f);
f_tran.origin_surface_feature = std::make_shared<SurfaceFeature>(f);
f_tran.translate(world_tran);
return std::make_optional(f_tran);
}
SurfaceFeature f_tran(f);
f_tran.origin_surface_feature = std::make_shared<SurfaceFeature>(f);
f_tran.translate(world_tran);
return std::make_optional(f_tran);
}
// Nothing detected, return the plane as a whole.
@ -646,8 +648,12 @@ Measuring::~Measuring() {}
std::optional<SurfaceFeature> Measuring::get_feature(size_t face_idx, const Vec3d &point, const Transform3d &world_tran) const {
return priv->get_feature(face_idx, point,world_tran);
std::optional<SurfaceFeature> Measuring::get_feature(size_t face_idx, const Vec3d &point, const Transform3d &world_tran, bool only_select_plane) const
{
if (face_idx == 7516 || face_idx == 7517) {
std::cout << "";
}
return priv->get_feature(face_idx, point, world_tran, only_select_plane);
}
@ -1005,7 +1011,7 @@ MeasurementResult get_measurement(const SurfaceFeature &a, const SurfaceFeature
const auto [c0, r0, n0] = f1.get_circle();
const auto [c1, r1, n1] = f2.get_circle();
// The following code is an adaptation of the algorithm found in:
// The following code is an adaptation of the algorithm found in:
// https://github.com/davideberly/GeometricTools/blob/master/GTE/Mathematics/DistCircle3Circle3.h
// and described in:
// https://www.geometrictools.com/Documentation/DistanceToCircle3.pdf
@ -1224,7 +1230,7 @@ MeasurementResult get_measurement(const SurfaceFeature &a, const SurfaceFeature
const double dist = (c0 - c1).norm();
result.distance_strict = std::make_optional(DistAndPoints{dist, c0, c1});
}
///////////////////////////////////////////////////////////////////////////
} else if (f2.get_type() == SurfaceFeatureType::Plane) {
const auto [center, radius, normal1] = f1.get_circle();
@ -1374,7 +1380,7 @@ void SurfaceFeature::translate(const Vec3d& displacement) {
}
}
void SurfaceFeature::translate(const Transform3d &tran)
void SurfaceFeature::translate(const Transform3d &tran)
{
switch (get_type()) {
case Measure::SurfaceFeatureType::Point: {

View File

@ -129,7 +129,7 @@ public:
// Given a face_idx where the mouse cursor points, return a feature that
// should be highlighted (if any).
std::optional<SurfaceFeature> get_feature(size_t face_idx, const Vec3d& point, const Transform3d & world_tran) const;
std::optional<SurfaceFeature> get_feature(size_t face_idx, const Vec3d& point, const Transform3d & world_tran,bool only_select_plane) const;
// Return total number of planes.
int get_num_of_planes() const;

View File

@ -472,6 +472,7 @@ void GLGizmoMeasure::on_set_state()
m_mode = EMode::FeatureSelection;
m_hover_id = -1;
m_show_reset_first_tip = false;
m_only_select_plane = false;
m_distance = Vec3d::Zero();
}
}
@ -669,7 +670,8 @@ void GLGizmoMeasure::on_render()
std::optional<Measure::SurfaceFeature> curr_feature = std::nullopt;
if (m_curr_measuring) {
curr_feature = wxGetMouseState().LeftIsDown() ? m_curr_feature :
mouse_on_object ? m_curr_measuring->get_feature(model_facet_idx, position_on_model, m_mesh_raycaster_map[m_last_hit_volume]->world_tran.get_matrix()) :
mouse_on_object ? m_curr_measuring->get_feature(model_facet_idx, position_on_model,
m_mesh_raycaster_map[m_last_hit_volume]->world_tran.get_matrix(), m_only_select_plane) :
std::nullopt;
}
if (m_measure_mode == EMeasureMode::ONLY_ASSEMBLY) {
@ -1802,6 +1804,7 @@ void GLGizmoMeasure::show_selection_ui()
const float feature_first_text_length = ImGui::CalcTextSize((_u8L(feature_first_text)).c_str()).x;
ImGui::AlignTextToFramePadding();
if (m_measure_mode == EMeasureMode::ONLY_ASSEMBLY) {
m_only_select_plane = m_assembly_mode == AssemblyMode::FACE_FACE ? true : false;
if (m_assembly_mode == AssemblyMode::FACE_FACE) {
m_imgui->text(_u8L("Select 2 faces on objects and \n make objects assemble together.")); // tip
} else if (m_assembly_mode == AssemblyMode::POINT_POINT) {
@ -2441,11 +2444,11 @@ void GLGizmoMeasure::set_distance(bool same_model_object, const Vec3d &displacem
m_pending_scale ++;
if (same_model_object == false) {
auto object_displacement = v->get_instance_transformation().get_matrix_no_offset().inverse() * displacement;
selection->translate(v->object_idx(), v->instance_idx(), object_displacement);
v->set_instance_transformation(v->get_instance_transformation().get_matrix() * Geometry::translation_transform(object_displacement));
} else {
Geometry::Transformation tran(v->world_matrix());
auto local_displacement = tran.get_matrix_no_offset().inverse() * displacement;
selection->translate(v->object_idx(), v->instance_idx(), v->volume_idx(), local_displacement);
v->set_volume_transformation(v->get_volume_transformation().get_matrix() * Geometry::translation_transform(local_displacement));
}
wxGetApp().plater()->canvas3D()->do_move("");
register_single_mesh_pick();

View File

@ -297,6 +297,7 @@ protected:
float m_space_size;
float m_input_size_max;
bool m_use_inches;
bool m_only_select_plane{false};
std::string m_units;
mutable bool m_same_model_object;
mutable unsigned int m_current_active_imgui_id;