feat(pick): select frame-like entities by clicking inside them

Images, OLE frames, wipeouts, underlays, paper-space viewports and
drawing-view borders were selectable only on their outline. Each now
carries an interior pick surface (pick_tris over its rectangle, or the
triangulated clip polygon for a clipped underlay), ranked below edge
and fill hits so content drawn inside still wins the click. The
layout's own sheet ("overall") viewport is excluded — identified by
the Layout object's viewport link, since DWG files carry viewport
id = 0 and some center the sheet viewport off-origin — or it would
swallow every click over the real viewports beneath it. Drawing-view
borders draw nothing normally; they emit an invisible pick-only wire
whose rect outline appears while selected.

Co-Authored-By: Claude Fable 5 <[email protected]>
This commit is contained in:
Hakan SevenandClaude Fable 5 committed 2026-07-21 09:28:07 +03:00
1 parent 84adb71cee
commit e1a4ddef5e
6 files changed
+116 -10

No files matched your search

+7
View File
@@ -119,6 +119,13 @@ pub fn format_angle(value_rad: f64) -> String {
}
}
/// Two interior triangles covering a quad (flat list, 6 vertices) — the
/// click-anywhere pick surface for frame-like entities (image, OLE frame,
/// underlay, wipeout). Corners in ring order.
pub fn quad_pick_tris(c: &[[f64; 3]; 4]) -> Vec<[f64; 3]> {
vec![c[0], c[1], c[2], c[0], c[2], c[3]]
}
pub fn square_grip(id: usize, world: glam::DVec3) -> GripDef {
GripDef {
id,
+8 -1
View File
@@ -43,7 +43,14 @@ fn to_truck(ole: &Ole2Frame) -> TruckEntity {
];
let center = glam::DVec3::new(cx, cy, z);
TruckEntity {
pick_tris: Vec::new(),
// Interior pick surface: the frame selects on a click anywhere
// inside, not just on its border.
pick_tris: crate::entities::common::quad_pick_tris(&[
[x0, y0, z],
[x1, y0, z],
[x1, y1, z],
[x0, y1, z],
]),
object: TruckObject::Lines(pts),
snap_pts: vec![(center, SnapHint::Center)],
tangent_geoms: vec![],
+7 -3
View File
@@ -136,7 +136,9 @@ impl TruckConvertible for RasterImage {
path.is_empty() || crate::scene::model::image_model::resolve_image(path).is_some();
if resolvable {
return Some(TruckEntity {
pick_tris: Vec::new(),
// Interior pick surface: the image selects on a click anywhere
// inside its frame, not just on the border.
pick_tris: crate::entities::common::quad_pick_tris(&corners),
object: TruckObject::Lines(pts),
snap_pts: vec![],
tangent_geoms: vec![],
@@ -223,7 +225,7 @@ impl TruckConvertible for RasterImage {
}
Some(TruckEntity {
pick_tris: Vec::new(),
pick_tris: crate::entities::common::quad_pick_tris(&corners),
object: TruckObject::Text(groups),
snap_pts: vec![],
tangent_geoms: vec![],
@@ -457,7 +459,9 @@ impl TruckConvertible for Wipeout {
};
Some(TruckEntity {
pick_tris: Vec::new(),
// Interior pick surface — a wipeout reads as a solid patch, so a
// click anywhere on it should select it.
pick_tris: crate::entities::common::quad_pick_tris(&corners),
object: TruckObject::Lines(pts),
snap_pts: vec![],
tangent_geoms: vec![],
+5 -1
View File
@@ -52,8 +52,12 @@ impl TruckConvertible for Underlay {
}
// Insertion grip.
let key: Vec<[f64; 3]> = pts.clone();
// Interior pick surface over the clip polygon so the underlay
// selects on a click anywhere inside, not just on its outline.
let ring: Vec<[f64; 3]> = world_verts.iter().map(|v| [v.x, v.y, v.z]).collect();
let pick_tris = crate::entities::mesh::triangulate_planar(&ring);
Some(TruckEntity {
pick_tris: Vec::new(),
pick_tris,
object: TruckObject::Lines(pts),
snap_pts: vec![(glam::DVec3::new(self.insertion_point.x, self.insertion_point.y, self.insertion_point.z), SnapHint::Node)],
tangent_geoms: vec![],