Create, resolve and refresh associations through viewports

This wires the chain walker into the association system proper, and adds
the entry point PR2 calls.

Resolution. `resolve_reference_chain` walks the chain, evaluates the
osnap feature in the entity's own coordinates, lifts it to model space
through the block path, and — when the chain goes through a viewport —
projects it onto the sheet with that viewport's `ViewportFrame`. Both
points are kept: the dimension holds paper points, the value it displays
is a model length. `ChainMap` is the one place that conversion lives,
including a `map_radial` that carries a radial source's plane into the
dimension's space so the radius/diameter/arc paths need no viewport
special-casing of their own. Which space a stored osnap point was
written in is not recoverable from the record — our own writer used
model/WCS, AutoCAD's trans-space records use the dimension's space, and
both turn up in the same drawing — so both readings are mapped down to
the entity and the one that lands on the geometry wins. It is only ever
a hint that disambiguates candidates, never the answer.

Creation. `Scene::attach_viewport_dimension_association` takes one
`AcceptedSnap` per definition point and writes the whole chain: viewport
handle, block path, entity, osnap type, sub-entity marker and parameter,
plus `trans_space` on the association. Every link becomes a reactor
target, not just the innermost entity, so a change anywhere along a
chain reaches the refresh through the ordinary dependency index.

Refresh. `refresh_associative_dimensions` now matches a changed handle
anywhere in a chain (including the second chain of an intersection), so
a viewport change reaches the dimensions drawn through it. Perpendicular
and tangent references resolve in a second pass, measured from the other
definition point. A dimension carries its sheet annotation with it: the
dimension-line standoff and a user-dragged text position move by the
centroid shift of the points that actually moved, so a one-ended edit
keeps the dimension line centred instead of collapsing it. For a
trans-space linear or aligned dimension the displayed value is
recomputed from the model points and multiplied only by the user's
DIMLFAC (`MeasurementScale::model_factor`) — the viewport compensation
is inherent in having measured in model space, and applying it again is
the double-scaling this three-PR effort exists to stop.

Broken references. Brokenness is derived, never written: a reference
whose source was erased simply stops resolving, the dimension keeps its
last valid appearance, and the record is left byte-for-byte as it was.
An undo that restores the source restores the link with no extra
bookkeeping. `Scene::dimension_association_status` reports it per slot.
`dimension_is_associative` now walks the chain too, instead of accepting
any surviving handle in `xrefs` — which was true even for a trans-space
reference whose actual geometry had gone, because the viewport was still
there.

Undo. Creating an association journals the new object and every reactor
list it touches; refreshing a dimension journals the dimension's
before-image. Both were previously invisible to the delta recorder.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Christopher OverbeckandClaude Fable 5.1 committed 2026-09-15 12:46:03 -05:00
1 parent 64c534f511
commit 2697b60d21
2 files changed
+764 -23

No files matched your search

+4
View File
@@ -31,6 +31,10 @@ mod camera_ops;
pub(crate) mod centerline;
pub(crate) mod dimension_assoc;
pub(crate) mod dimension_assoc_chain;
// The association surface PR2, the UI and the tests address: create an
// association from accepted snaps, ask whether its references still
// resolve, and resolve one by hand.
pub use dimension_assoc::{ReferenceStatus, ResolvedReference};
pub(crate) mod centermark;
mod dwg_native_constraints;
mod entity;