fix(pick): catch a wide polyline on its band, not just its centreline
A wide polyline draws a solid band, but hit-testing only ever saw the centreline 8 px out, so a donut could only be selected by clicking the phantom circle inside the disc it paints. `self.hatches` — the map the hatch pick channel walks — is filled from HATCH and SOLID alone, so the band `wide_fills` produces was drawn (via `synced_hatch_models`) and never picked. The band rides in on `pick_tris`, the same channel a thickness wall uses: `wide_fills` already computes it, so it costs one tessellation and inherits the block transform. It ear clips rather than fans — an arc band is an annular sector, concave on its inner edge — reusing `triangulate_planar`. Wiring `pick_tris` through `Lines` alone was not enough: a plain wide polyline leaves `to_truck` as `Contour`, and a PLINEGEN=0 one as `SegmentedLines`. Both now carry it. This needs the wire's cullable box to cover the band, and it did not. `bounding_box()` boxes a polyline's stored vertices, knowing nothing of the width painted around them: a donut's two vertices sit on one horizontal line, so the box had zero height and rejected every click on the disc before any triangle was tested. Every site that stamps the entity box onto a wire now goes through `set_wire_aabb`, which widens it over `pick_tris` (a no-op for the entities that have none, which is nearly all), and the block cache chains `pick_tris` into its own box for the same reason. That box was already too small for the centreline itself — an arc leaves the vertex box — so a donut was unselectable at its top and bottom at enough zoom. Widening fixes that too. Verified end-to-end: tessellate a width-0.5 donut on a 0.05 centreline radius, then `click_hit` five points 20 px clear of the centreline — all land, and a click outside the disc still misses. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
07d7888b94
commit
4f1e710b35
9 changed files with 111 additions and 34 deletions
|
|
@ -311,6 +311,29 @@ impl BulgeArc {
|
|||
}
|
||||
}
|
||||
|
||||
/// Triangulate the solid bands a `wide_fills` returns into the flat WCS f64
|
||||
/// triangle list `TruckEntity::pick_tris` carries, so a wide polyline is
|
||||
/// selectable across the band it draws and not just along its centreline.
|
||||
///
|
||||
/// `origin` and `fills` are that function's own pair: 2-D offsets from the
|
||||
/// first vertex, which is the exact frame the band's `HatchModel` renders in
|
||||
/// (`world_origin` + boundary, no elevation). Building the pick geometry from
|
||||
/// the same numbers keeps hit-testing on whatever the fill actually drew.
|
||||
///
|
||||
/// An arc band is an annular sector — concave on its inner edge — so this ear
|
||||
/// clips rather than fans.
|
||||
pub(crate) fn wide_band_tris(origin: [f64; 2], fills: &[Vec<[f32; 2]>]) -> Vec<[f64; 3]> {
|
||||
let mut out = Vec::new();
|
||||
for poly in fills {
|
||||
let ring: Vec<[f64; 3]> = poly
|
||||
.iter()
|
||||
.map(|&[x, y]| [origin[0] + x as f64, origin[1] + y as f64, 0.0])
|
||||
.collect();
|
||||
out.extend(crate::entities::mesh::triangulate_planar(&ring));
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
/// Compute the filled boundary polygon for one polyline segment.
|
||||
/// For straight segments: a rectangle/trapezoid.
|
||||
/// For arc segments: an arc band (outer arc + reversed inner arc).
|
||||
|
|
@ -392,3 +415,4 @@ pub(crate) fn polyline_segment_fill(
|
|||
Some(boundary)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue