Change the way how cut gizmo detects hits on cut plane:
it did not work well on meshes with overlapping surfaces
This commit is contained in:
parent
85ad56b43b
commit
595ef873ad
4 changed files with 40 additions and 88 deletions
|
@ -1144,11 +1144,11 @@ void GLGizmoCut3D::dragging_grabber_xy(const GLGizmoBase::UpdateData &data)
|
|||
void GLGizmoCut3D::dragging_connector(const GLGizmoBase::UpdateData &data)
|
||||
{
|
||||
CutConnectors& connectors = m_c->selection_info()->model_object()->cut_connectors;
|
||||
std::pair<Vec3d, Vec3d> pos_and_normal;
|
||||
Vec3d pos;
|
||||
Vec3d pos_world;
|
||||
|
||||
if (unproject_on_cut_plane(data.mouse_pos.cast<double>(), pos_and_normal, pos_world)) {
|
||||
connectors[m_hover_id - m_connectors_group_id].pos = pos_and_normal.first;
|
||||
if (unproject_on_cut_plane(data.mouse_pos.cast<double>(), pos, pos_world)) {
|
||||
connectors[m_hover_id - m_connectors_group_id].pos = pos;
|
||||
update_raycasters_for_picking_transform();
|
||||
}
|
||||
}
|
||||
|
@ -2006,44 +2006,41 @@ void GLGizmoCut3D::perform_cut(const Selection& selection)
|
|||
|
||||
// Unprojects the mouse position on the mesh and saves hit point and normal of the facet into pos_and_normal
|
||||
// Return false if no intersection was found, true otherwise.
|
||||
bool GLGizmoCut3D::unproject_on_cut_plane(const Vec2d& mouse_position, std::pair<Vec3d, Vec3d>& pos_and_normal, Vec3d& pos_world)
|
||||
bool GLGizmoCut3D::unproject_on_cut_plane(const Vec2d& mouse_position, Vec3d& pos, Vec3d& pos_world)
|
||||
{
|
||||
const float sla_shift = m_c->selection_info()->get_sla_shift();
|
||||
|
||||
const ModelObject* mo = m_c->selection_info()->model_object();
|
||||
const ModelInstance* mi = mo->instances[m_c->selection_info()->get_active_instance()];
|
||||
const Transform3d instance_trafo = sla_shift > 0.f ?
|
||||
translation_transform(sla_shift * Vec3d::UnitZ()) * mi->get_transformation().get_matrix() : mi->get_transformation().get_matrix();
|
||||
const Camera& camera = wxGetApp().plater()->get_camera();
|
||||
|
||||
int mesh_id = -1;
|
||||
for (const ModelVolume* mv : mo->volumes) {
|
||||
++mesh_id;
|
||||
if (!mv->is_model_part())
|
||||
continue;
|
||||
Vec3f normal;
|
||||
Vec3f hit;
|
||||
bool clipping_plane_was_hit = false;
|
||||
// Calculate intersection with the clipping plane.
|
||||
const ClippingPlane* cp = m_c->object_clipper()->get_clipping_plane(true);
|
||||
Vec3d point;
|
||||
Vec3d direction;
|
||||
Vec3d hit;
|
||||
MeshRaycaster::line_from_mouse_pos(mouse_position, Transform3d::Identity(), camera, point, direction);
|
||||
Vec3d normal = -cp->get_normal().cast<double>();
|
||||
double den = normal.dot(direction);
|
||||
if (den != 0.) {
|
||||
double t = (-cp->get_offset() - normal.dot(point))/den;
|
||||
hit = (point + t * direction);
|
||||
} else
|
||||
return false;
|
||||
|
||||
if (! m_c->object_clipper()->is_projection_inside_cut(hit))
|
||||
return false;
|
||||
|
||||
// const Transform3d volume_trafo = get_volume_transformation(mv);
|
||||
const Transform3d volume_trafo = mv->get_transformation().get_matrix();
|
||||
// recalculate hit to object's local position
|
||||
Vec3d hit_d = hit;
|
||||
hit_d -= mi->get_offset();
|
||||
hit_d[Z] -= sla_shift;
|
||||
|
||||
m_c->raycaster()->raycasters()[mesh_id]->unproject_on_mesh(mouse_position, instance_trafo * volume_trafo,
|
||||
camera, hit, normal, m_c->object_clipper()->get_clipping_plane(true),
|
||||
nullptr, &clipping_plane_was_hit);
|
||||
if (clipping_plane_was_hit) {
|
||||
// recalculate hit to object's local position
|
||||
Vec3d hit_d = hit.cast<double>();
|
||||
hit_d -= mi->get_offset();
|
||||
hit_d[Z] -= sla_shift;
|
||||
// Return both the point and the facet normal.
|
||||
pos = hit_d;
|
||||
pos_world = hit;
|
||||
|
||||
// Return both the point and the facet normal.
|
||||
pos_and_normal = std::make_pair(hit_d, normal.cast<double>());
|
||||
pos_world = hit.cast<double>();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void GLGizmoCut3D::clear_selection()
|
||||
|
@ -2139,17 +2136,13 @@ bool GLGizmoCut3D::add_connector(CutConnectors& connectors, const Vec2d& mouse_p
|
|||
if (!m_connectors_editing)
|
||||
return false;
|
||||
|
||||
std::pair<Vec3d, Vec3d> pos_and_normal;
|
||||
Vec3d pos;
|
||||
Vec3d pos_world;
|
||||
if (unproject_on_cut_plane(mouse_position.cast<double>(), pos_and_normal, pos_world)) {
|
||||
// check if pos is out of enabled clipping plane
|
||||
if (m_c->object_clipper() && !m_c->object_clipper()->is_projection_inside_cut(pos_world))
|
||||
return true;
|
||||
|
||||
if (unproject_on_cut_plane(mouse_position.cast<double>(), pos, pos_world)) {
|
||||
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Add connector"), UndoRedo::SnapshotType::GizmoAction);
|
||||
unselect_all_connectors();
|
||||
|
||||
connectors.emplace_back(pos_and_normal.first, m_rotation_m,
|
||||
connectors.emplace_back(pos, m_rotation_m,
|
||||
m_connector_size * 0.5f, m_connector_depth_ratio,
|
||||
m_connector_size_tolerance, m_connector_depth_ratio_tolerance,
|
||||
CutConnectorAttributes( CutConnectorType(m_connector_type),
|
||||
|
@ -2247,9 +2240,9 @@ bool GLGizmoCut3D::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_posi
|
|||
if (!m_connectors_editing) {
|
||||
if (0 && action == SLAGizmoEventType::LeftDown) {
|
||||
// disable / enable current contour
|
||||
std::pair<Vec3d, Vec3d> pos_and_normal;
|
||||
Vec3d pos;
|
||||
Vec3d pos_world;
|
||||
if (unproject_on_cut_plane(mouse_position.cast<double>(), pos_and_normal, pos_world)) {
|
||||
if (unproject_on_cut_plane(mouse_position.cast<double>(), pos, pos_world)) {
|
||||
// Following would inform the clipper about the mouse click, so it can
|
||||
// toggle the respective contour as disabled.
|
||||
m_c->object_clipper()->pass_mouse_click(pos_world);
|
||||
|
|
|
@ -155,7 +155,7 @@ public:
|
|||
GLGizmoCut3D(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id);
|
||||
|
||||
std::string get_tooltip() const override;
|
||||
bool unproject_on_cut_plane(const Vec2d& mouse_pos, std::pair<Vec3d, Vec3d>& pos_and_normal, Vec3d& pos_world);
|
||||
bool unproject_on_cut_plane(const Vec2d& mouse_pos, Vec3d& pos, Vec3d& pos_world);
|
||||
bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down);
|
||||
|
||||
bool is_in_editing_mode() const override { return m_connectors_editing; }
|
||||
|
|
|
@ -365,11 +365,8 @@ void MeshRaycaster::line_from_mouse_pos(const Vec2d& mouse_pos, const Transform3
|
|||
|
||||
bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera,
|
||||
Vec3f& position, Vec3f& normal, const ClippingPlane* clipping_plane,
|
||||
size_t* facet_idx, bool* was_clipping_plane_hit) const
|
||||
size_t* facet_idx) const
|
||||
{
|
||||
if (was_clipping_plane_hit)
|
||||
*was_clipping_plane_hit = false;
|
||||
|
||||
Vec3d point;
|
||||
Vec3d direction;
|
||||
line_from_mouse_pos(mouse_pos, trafo, camera, point, direction);
|
||||
|
@ -390,26 +387,9 @@ bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d&
|
|||
break;
|
||||
}
|
||||
|
||||
if (i==hits.size()) {
|
||||
// All hits are clipped.
|
||||
return false;
|
||||
}
|
||||
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 (was_clipping_plane_hit) {
|
||||
direction = direction + point;
|
||||
point = trafo * point; // transform to world coords
|
||||
direction = trafo * direction - point;
|
||||
|
||||
Vec3d normal = -clipping_plane->get_normal().cast<double>();
|
||||
double den = normal.dot(direction);
|
||||
if (den != 0.) {
|
||||
double t = (-clipping_plane->get_offset() - normal.dot(point))/den;
|
||||
position = (point + t * direction).cast<float>();
|
||||
*was_clipping_plane_hit = true;
|
||||
}
|
||||
}
|
||||
if (i==hits.size() || (hits.size()-i) % 2 != 0) {
|
||||
// All hits are either clipped, or there is an odd number of unclipped
|
||||
// hits - meaning the nearest must be from inside the mesh.
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -423,24 +403,7 @@ bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d&
|
|||
return true;
|
||||
}
|
||||
|
||||
bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera,
|
||||
Vec3d& position, Vec3d& normal) const
|
||||
{
|
||||
Vec3d point;
|
||||
Vec3d direction;
|
||||
line_from_mouse_pos(mouse_pos, trafo, camera, point, direction);
|
||||
|
||||
std::vector<AABBMesh::hit_result> hits = m_emesh.query_ray_hits(point, direction);
|
||||
|
||||
if (hits.empty())
|
||||
return false; // no intersection found
|
||||
|
||||
// Now stuff the points in the provided vector and calculate normals if asked about them:
|
||||
position = hits[0].position();
|
||||
normal = hits[0].normal();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MeshRaycaster::is_valid_intersection(Vec3d point, Vec3d direction, const Transform3d& trafo) const
|
||||
{
|
||||
|
|
|
@ -153,16 +153,12 @@ public:
|
|||
const Vec2d& mouse_pos,
|
||||
const Transform3d& trafo, // how to get the mesh into world coords
|
||||
const Camera& camera, // current camera position
|
||||
Vec3f& position, // where to save the positibon of the hit (mesh coords if mesh, world coords if clipping plane)
|
||||
Vec3f& position, // where to save the positibon of the hit (mesh coords)
|
||||
Vec3f& normal, // normal of the triangle that was hit
|
||||
const ClippingPlane* clipping_plane = nullptr, // clipping plane (if active)
|
||||
size_t* facet_idx = nullptr, // index of the facet hit
|
||||
bool* was_clipping_plane_hit = nullptr // is the hit on the clipping place cross section?
|
||||
size_t* facet_idx = nullptr // index of the facet hit
|
||||
) const;
|
||||
|
||||
// Given a mouse position, this returns true in case it is on the mesh.
|
||||
bool unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera, Vec3d& position, Vec3d& normal) const;
|
||||
|
||||
bool is_valid_intersection(Vec3d point, Vec3d direction, const Transform3d& trafo) const;
|
||||
|
||||
// Given a vector of points in woorld coordinates, this returns vector
|
||||
|
|
Loading…
Reference in a new issue