forked from 1b-agent/opencadstudio-upstream
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>