forked from 1b-agent/opencadstudio-upstream
feat(pick): select mesh entities by clicking their shaded faces
Mesh entities (PolyfaceMesh / PolygonMesh / SubD Mesh) could only be picked on their thin edges — click_hit tested wire segments, and the solid face pick only covers ACIS solids. When no edge is close, click_hit now also tests the mesh's fill_tris with the same projected-triangle containment mesh_click_hit uses for solids, so clicking a mesh's surface selects it, front-most first. Edge proximity still takes priority. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
67bcdb1731
commit
2bbd3cfcd2
1 file changed
+45
-1
@@ -90,7 +90,51 @@ pub fn click_hit<'a>(
|
||||
}
|
||||
}
|
||||
|
||||
best
|
||||
if best.is_some() {
|
||||
return best;
|
||||
}
|
||||
|
||||
// No edge close enough. Mesh entities (PolyfaceMesh / PolygonMesh / SubD
|
||||
// Mesh) carry their shaded faces as `fill_tris`; test those so a mesh is
|
||||
// selectable by clicking its surface — not only its thin edges — the way a
|
||||
// 3D solid is. Same projected-triangle containment as `mesh_click_hit`,
|
||||
// front-most wins.
|
||||
let mut best_fill: Option<(f32, &str)> = None;
|
||||
for wire in wires {
|
||||
if wire.fill_tris.is_empty() {
|
||||
continue;
|
||||
}
|
||||
let mut t = 0;
|
||||
while t + 2 < wire.fill_tris.len() {
|
||||
let mut sp = [Point::ORIGIN; 3];
|
||||
let mut depth = 0.0f32;
|
||||
for j in 0..3 {
|
||||
let k = t + j;
|
||||
let hi = wire.fill_tris[k];
|
||||
let lo = wire.fill_tris_low.get(k).copied().unwrap_or([0.0; 3]);
|
||||
let world = glam::DVec3::new(
|
||||
hi[0] as f64 + lo[0] as f64,
|
||||
hi[1] as f64 + lo[1] as f64,
|
||||
hi[2] as f64 + lo[2] as f64,
|
||||
);
|
||||
let ndc = view_rot.project_point3((world - eye).as_vec3());
|
||||
sp[j] = Point::new(
|
||||
(ndc.x + 1.0) * 0.5 * bounds.width,
|
||||
(1.0 - ndc.y) * 0.5 * bounds.height,
|
||||
);
|
||||
depth += ndc.z;
|
||||
}
|
||||
t += 3;
|
||||
if point_in_polygon(cursor, &sp) {
|
||||
let d = depth / 3.0;
|
||||
if best_fill.map_or(true, |(bd, _)| d < bd) {
|
||||
best_fill = Some((d, wire.name.as_str()));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
best_fill.map(|(_, n)| n)
|
||||
}
|
||||
|
||||
/// Like `click_hit` but returns every wire within the click threshold,
|
||||
|
||||
Reference in new issue
Block a user