The GPU scissors floating-viewport content to the viewport rectangle, but
the CPU hit-test/snap wire set runs past it (the frustum cull keeps a
margin and lines extend beyond the rect), so box selection, lasso, click
and object snap could reach geometry clipped out of the viewport.
Reject candidates whose projected screen point falls outside `bounds` (the
pane rectangle), mirroring the scissor. `bounds` is the full canvas in
model space, so every change is a no-op there.
- snap: reject out-of-bounds points in try_pt, the grid block and tangent.
- click_hit / click_hits_all: no hit when the cursor is off-pane.
- box_hit: clamp the selection box to the pane rectangle.
- poly_hit: drop wire points projected off-pane.
- hatch click: no hit when the cursor is off-pane.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Replace the leaky paper-projection approach to MSPACE editing with one
coordinate adapter that routes all interaction through the viewport's own
camera — the exact camera+rect the GPU draws the content with.
- Add Scene::viewport_edit_frame(canvas) -> (camera_for_viewport,
viewport_screen_rect): the unified adapter. Inside a floating viewport
the viewport is the active pane, so snap/pick/grip/preview/DYN run in
model space and land on the pixels the GPU draws. Tracks pan/zoom/twist
exactly (twist handled by camera_from_view); crop is pixel-preserving so
full-rect projection + cursor offset matches.
- Route snap-move, click-pick, grip-drag, grip hit-test, grip render,
hover (HoverDwellTick), selection (single/box/poly/cycle) and command
entity-pick through it via pick_view / cursor_model_point helpers and an
edit_cam-aware "active pane = viewport rect" override, so the existing
tile offset plumbing just works. Fixes wrong-object hover/selection and
stale snap after pan/zoom.
- DYN: project anchors with the viewport camera and shift to canvas space
so the guide/labels sit correctly (also fixes a latent tiled-model bug).
- Separate grid snap from object snap entirely: new Snapper.grid_snap_on
flag, Grid removed from the osnap mode set, evaluated independently of
the osnap master. Object snap never catches grid; grid corners are
picked only when grid snap is on, at lowest priority. Default off.
- grip.rs: project_rte + grips_to_screen_rte / find_hit_grip_rte taking
(view_rot, eye) so grips project through the composed view.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Selection projected wire vertices from points (the double-single HIGH half)
alone, ignoring points_low, so at UTM scale every selection test ran against
coordinates ~0.5 m off — box/crossing/window edges and click hit-tests missed
or grabbed the wrong entities, worsening with zoom.
hit_test now reconstructs each vertex's absolute f64 from points + points_low
(wp64) before projecting, across click_hit, click_hits_all, box_hit and
poly_hit (lasso). Hatch hit-tests use the f64 world_origin instead of an
f32-cast, and mesh hit-tests (click/box/lasso face picking) reconstruct from
verts + verts_low. world_to_screen now takes the f64 point directly.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Clipped blocks were broken at UTM and lost their clip when pasted into
another drawing.
- Clip geometry: world_clip_polygon_f64 keeps the boundary in absolute f64;
clip_wires now clips in a frame relative to the boundary's first vertex
(small coords → exact f32 Sutherland–Hodgman) and re-splits the result
into the double-single high/low pair the relative-to-eye renderer needs,
so the clipped block draws correctly and no longer poisons ZOOM Extents.
- ZOOM Extents (fit_all): the outlier reject compared absolute UTM
coordinates against a centre-RELATIVE span (local_extent_max), rejecting
the whole drawing → no-op. Made the reject distance-from-median-centre.
- Cross-drawing paste: clipboard now snapshots each copied entity's whole
xdictionary object graph (ClipboardDeps.ext_objects) and recreates it on
paste with fresh handles + remapped references, re-pointing the pasted
entity's xdictionary at the new root. Wired into PASTECLIP and PASTEORIG.
Fixed handle allocation (allocate_handle, not the non-advancing
next_handle) so the dictionary chain doesn't collapse onto one handle.
- Updated hit_test / plugin_host tests for the eye-relative + DVec3 signatures.
Known gaps: PASTEBLOCK does not yet carry the clip (clip would need to live
inside the new wrapper block definition); hatch-clip path still f32.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Whole command/snap/grip/cursor chain now builds on f64 DVec3 end to end,
so picked points, snaps and grip drags stay precise at UTM-scale
coordinates instead of quantizing to ~0.5 m through f32.
- All ~80 command files migrated: draw (line/circle/arc/ellipse/shapes
in full f64; others via point methods), modify, annotate, insert, view,
inquiry, layers, groups, clipboard, layout.
- Entity apply_grip impls updated for GripApply::{Absolute,Translate}(DVec3).
- Construction sites (EntityTransform/CmdResult/DynAnchor) emit DVec3;
wire-preview boundaries cast to f32 only at the GPU edge.
- Modify/annotate commands keep internal Vec3 geometry where precision is
non-critical, casting at the DVec3 boundary; key draw commands store f64.
Builds clean (no warnings). Visual verification of crosshair/snap/grip at
extreme UTM zoom pending.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Route the remaining absolute-coordinate CPU projection through the
relative-to-eye path so it no longer multiplies by a view_proj matrix
carrying a ~1e7 translation (which cancels catastrophically in f32 after
world_offset removal):
- camera pick_on_plane / pick_on_target_plane delegate to
unproject_on_plane_f64 (rotation-only inverse + f64 eye)
- snapper (world_to_screen), hit_test (click_hit / mesh / hatch), the
scene mesh/solid hit methods, grid + UCS axes, and polar_constrain_near
all take view_rot + eye and project relative-to-eye
- compute_grid_step measures the per-unit scale via the rotation-only
matrix (no eye term needed)
view_proj remains only for conservative CPU frustum-cull / scissor and the
screen-space viewcube / UCS-icon directions. NOTE: SnapResult.world and
the command-point chain are still Vec3 (f32) — a ~0.5 m quantization at
extreme UTM zoom remains; the command layer goes f64 next.
Co-Authored-By: Claude Opus 4.7 <[email protected]>
Route the on-screen chrome that projects absolute world coordinates
through the f64 relative-to-eye helpers so it stays glued/jitter-free at
UTM scale after the world_offset removal: grips (grips_to_screen) and
grip hit-testing (find_hit_grip) now project from the f64 GripDef.world
via Camera::project_f64; the model grid and its UCS axes carry the camera
eye (DVec3) + rotation-only matrix and a f64 origin, projecting each line
relative to the eye. Snap-marker / OST-point / compute_grid_step still use
the f32 path (single points / spacing — negligible) and can follow.
Co-Authored-By: Claude Opus 4.7 <[email protected]>
WireModel/LocalWire/BatchEntry key_vertices are now Vec<[f64; 3]>;
tessellation keeps them in f64 (no f32 cast at offset subtraction),
producers (dimension, leader, multileader) build them from the acadrust
f64 source, the block-cache transform keeps f64, and the face3d Face3D
quad path splits them into the double-single (high, low) pair. Consumers
(snap endpoint/midpoint, xclip) read via f32 at the leaf. Still
offset-relative (inert); endpoint/midpoint snap is no longer f32-capped.
Co-Authored-By: Claude Opus 4.7 <[email protected]>
WireModel/LocalWire/TruckEntity snap buffers and the producers/consumers
now carry snap candidates as DVec3 (offset_snap_pts, dimension/multileader
producers, block-cache transform, pick/xclip, snap module). Still
offset-relative, so behaviour is unchanged — this just lets the snap
transport survive the upcoming switch to absolute coordinates without an
extra f32 quantization. The snap module still resolves in f32 (as_vec3 at
entry), matching today's precision.
Co-Authored-By: Claude Opus 4.7 <[email protected]>
Box, window, crossing and lasso selection only tested wires and hatches, so
3D solids (which render as meshes) could never be selected that way. Add
mesh_box_hit / mesh_poly_hit that project the solid mesh and test it against
the box / lasso (window = all vertices inside, crossing = any vertex inside
or the region sitting inside the solid), and wire them into the selection
paths.
Also re-tessellate solids after a move/rotate/scale/mirror/copy: the entity
moved but its cached mesh didn't, so the solid stayed drawn at its old
position. Rebuild the mesh caches when a transformed/copied handle is an
ACIS volume.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Move the 30 flat modules under src/scene/ into six folders by role:
convert (entity→geometry), text (fonts/shaping), model (render models),
pick (hit-test/selection/grips/xclip), view (camera/transform/render),
cache (block + property caches). pipeline/ is unchanged.
Full path migration — all `scene::X` references become
`scene::<group>::X`, no compatibility re-exports. render.rs items that
were `pub(super)` (parent was scene) become `pub(in crate::scene)` to
keep their original scene-wide visibility.
No behavior change; build and tests are green.
Co-Authored-By: Claude Opus 4.8 <[email protected]>