fix(scene): hatch boundary + pattern precision for large-WCS drawings
Two precision problems were producing visibly wrong hatches on UTM-scale (and similarly-offset) drawings even after world_offset was correct: 1. **Boundary tessellation** — `hatch_model_from_dxf`'s polyline-bulge arc tessellation ran the whole arc-center computation in f32. With vertices at WCS magnitude ~1e5 the f32 ULP is ~1 cm, which propagated into the sampled arc points and showed up as visibly wavy / jagged hatch boundaries on edges that crossed the long axis of the drawing. Re-run the full bulge → arc math in f64; only cast at the to_xy call that feeds the (also f64) boundary buffer. 2. **Pattern phase** — the per-fragment `perp / perp_step` modulo blew precision when `xz` was at offset-rel WCS magnitude and perp_step was sub-cm. Move the precision-critical bits out of f32 by keeping each hatch's anchor in f64 on the model side: `HatchModel` now carries a `world_origin: [f64; 2]` and the `boundary: [f32; 2]` vertices are stored as small offsets from it. The GPU vertex shader adds `origin` back inside the view_proj multiply for clip position (sub-pixel-lossy at large hatches but invisible); the `xz` varying that the fragment shader uses for in_polygon + pattern math stays in hatch-local space at full f32 precision. For pattern alignment across adjacent hatches with the same family, the GPU pipeline snaps the anchor to the family's perp/along grid in f64 before sending it down. Snap uses the same QCAD-PAT convention (`fam.dy = perp_step`, `fam.dx = along_step`) the shader's check_family uses — an earlier attempt used the world-frame `(-dx*sin + dy*cos)` formula, which produced a meaningless grid and no alignment. Trade-off: pattern phase is "global modulo per-family-grid" rather than tied to WCS (0,0). Same hatches still align with each other; the absolute phase relative to the WCS origin may differ from the pre-fix behaviour on small drawings. Consumers that read `model.boundary` directly (hit_test, paper_canvas, add_hatch round-trip) reconstruct WCS via `boundary[i] + world_origin`. The hatch wgsl bind-group entry for binding 0 was bumped to `VERTEX | FRAGMENT` because the vertex shader now reads `h.origin`. The fragment-shader hatch LOD substitute + sub-pixel skip frome7675beand the scissor plumbing fromfbbac42still work — those touched different fields of the same struct. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
dc80968023
commit
172c538159
8 changed files with 238 additions and 63 deletions
|
|
@ -43,8 +43,22 @@ pub enum HatchPattern {
|
|||
/// A hatched region defined by a closed polygon boundary.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct HatchModel {
|
||||
/// World XY coordinates of the boundary polygon vertices.
|
||||
/// Arc so HatchModel::clone() is a pointer bump rather than a full Vec copy.
|
||||
/// World XY anchor (in the same offset-relative coordinate space as
|
||||
/// the rest of the scene — `world_offset` already subtracted, but
|
||||
/// kept at f64 precision). Boundary vertices are stored as f32
|
||||
/// offsets from this anchor so that:
|
||||
/// 1) hit-test / paper_canvas can still read small-magnitude f32
|
||||
/// coords without precision loss from the f64 → f32 cast that
|
||||
/// would otherwise happen at large drawing extents (UTM, etc.).
|
||||
/// 2) the GPU pipeline can pre-shift the quad in hatch-local
|
||||
/// space (so the fragment shader's `xz` varying stays small)
|
||||
/// and add `world_origin` back inside the view_proj multiply.
|
||||
/// Reconstruct WCS-relative coords as `(world_origin.x + v.x as f64,
|
||||
/// world_origin.y + v.y as f64)`.
|
||||
pub world_origin: [f64; 2],
|
||||
/// World-XY coordinates of the boundary polygon vertices, stored as
|
||||
/// f32 offsets from `world_origin`. NaN-NaN sentinels separate
|
||||
/// disconnected paths and must be preserved un-shifted by consumers.
|
||||
pub boundary: Arc<Vec<[f32; 2]>>,
|
||||
/// Fill pattern.
|
||||
pub pattern: HatchPattern,
|
||||
|
|
|
|||
Loading…
Reference in a new issue