Track mixed paper and viewport dimension references

This commit is contained in:
Christopher Overbeck committed 2026-09-15 16:00:11 -05:00
1 parent bd00d679a9
commit 5424a19482
28 files changed
+823 -846

No files matched your search

+19
View File
@@ -0,0 +1,19 @@
<svg xmlns="http://www.w3.org/2000/svg" width="900" height="350" viewBox="0 0 900 350">
<style>text{font-family:Arial,sans-serif;fill:#263238} .title{font-size:22px;font-weight:600} .label{font-size:16px} .small{font-size:13px;fill:#54616a} .model{stroke:#1479b8;stroke-width:4;fill:none} .paper{stroke:#a94610;stroke-width:2;stroke-dasharray:9 5} .dim{stroke:#263238;stroke-width:1.5;fill:none}</style>
<defs><marker id="arrow" viewBox="0 0 8 8" refX="4" refY="4" markerWidth="6" markerHeight="6" orient="auto-start-reverse"><path d="M8 0L0 4L8 8" fill="#263238"/></marker></defs>
<rect width="900" height="350" rx="10" fill="white"/>
<text class="title" x="30" y="38">The dimension follows its paper-space centerline</text>
<rect x="30" y="65" width="400" height="220" fill="#f5f8fa" stroke="#c3ced5"/>
<rect x="470" y="65" width="400" height="220" fill="#f5f8fa" stroke="#c3ced5"/>
<text class="label" x="48" y="93">Before</text><text class="label" x="488" y="93">Centerline moved 1 paper unit right</text>
<path class="model" d="M85 160H385M525 160H825"/>
<circle cx="385" cy="160" r="5" fill="#1479b8"/><circle cx="825" cy="160" r="5" fill="#1479b8"/>
<path class="paper" d="M235 113V257M705 113V257"/>
<path class="dim" d="M385 171V244M825 171V244"/>
<path class="dim" d="M235 232H385" marker-start="url(#arrow)" marker-end="url(#arrow)"/>
<path class="dim" d="M705 232H825" marker-start="url(#arrow)" marker-end="url(#arrow)"/>
<rect x="291" y="217" width="38" height="28" fill="#f5f8fa"/><rect x="746" y="217" width="38" height="28" fill="#f5f8fa"/>
<text class="label" x="310" y="237" text-anchor="middle">50</text><text class="label" x="765" y="237" text-anchor="middle">40</text>
<text class="label" x="30" y="316">The model endpoint stays fixed. The dimension updates from 50 to 40.</text>
<text class="small" x="30" y="340">Association schematic; viewport 1:10, dimension style unit factor = 1, DIMASSOC = 2.</text>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

+22
View File
@@ -0,0 +1,22 @@
<svg xmlns="http://www.w3.org/2000/svg" width="900" height="350" viewBox="0 0 900 350">
<style>text{font-family:Arial,sans-serif;fill:#263238} .title{font-size:22px;font-weight:600} .label{font-size:16px} .small{font-size:13px;fill:#54616a} .model{stroke:#1479b8;stroke-width:4;fill:none} .paper{stroke:#a94610;stroke-width:2;stroke-dasharray:9 5} .dim{stroke:#263238;stroke-width:1.5;fill:none}</style>
<defs><marker id="arrow" viewBox="0 0 8 8" refX="4" refY="4" markerWidth="6" markerHeight="6" orient="auto-start-reverse"><path d="M8 0L0 4L8 8" fill="#263238"/></marker></defs>
<rect width="900" height="350" rx="10" fill="white"/>
<text class="title" x="30" y="38">Dimension from a paper centerline to a model endpoint</text>
<rect x="30" y="65" width="430" height="245" fill="#f5f8fa" stroke="#c3ced5"/>
<text class="small" x="45" y="89">Viewport 1:10</text>
<path class="model" d="M100 160H400"/>
<circle cx="400" cy="160" r="5" fill="#1479b8"/>
<path class="paper" d="M250 110V260"/>
<text class="small" x="100" y="144">Model geometry</text>
<path class="dim" d="M400 171V244"/>
<path class="dim" d="M250 232H400" marker-start="url(#arrow)" marker-end="url(#arrow)"/>
<rect x="306" y="217" width="38" height="28" fill="#f5f8fa"/>
<text class="label" x="325" y="237" text-anchor="middle">50</text>
<text class="small" x="45" y="290">Brown dashed line: paper-space centerline</text>
<text class="label" x="500" y="116">5 paper units between the picked points</text>
<text class="label" x="500" y="155">5 × 10 = 50 model units</text>
<text class="label" x="500" y="206">The viewport supplies the length scale.</text>
<text class="label" x="500" y="240">Either pick order gives the same value.</text>
<text class="small" x="30" y="336">Measurement schematic; dimension style unit factor = 1.</text>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

+57 -83
View File
@@ -1,100 +1,74 @@
# Dimensions through paper-space viewports
# Dimensions through layout viewports
Paper-space point commands can snap to displayed model geometry through a planar,
orthographic layout viewport. The acquired result retains the original model
coordinate, its paper coordinate, the viewport frame, and feature identity.
Ordinary selection continues to operate on the active drawing space.
In paper space, snap to model geometry displayed through a planar, orthographic
viewport. `DIMLINEAR`, `DIMALIGNED`, `DIMANGULAR`, `DIMRADIUS`, and `DIMDIAMETER`
also support their usual object-pick modes through these viewports.
`DIMLINEAR`, `DIMALIGNED`, `DIMANGULAR`, `DIMRADIUS`, and `DIMDIAMETER` use this
acquisition context. The supported object-pick modes also query viewport geometry.
Snapping and object picking share viewport draw order, visibility, and clipping
rules. Object picking uses the resident interaction index and applies block
instance transforms. Nonuniformly transformed circles and circular arcs are
declined as radial object picks because their displayed geometry is elliptical.
Array inserts without an addressable instance index are also declined; resolved
block geometry must remain within the original pick aperture.
## Measurement
## Input and measurement rules
- Model geometry supplies the viewport scale. A 100-unit model length displayed
at 1:10 measures 100, although it occupies 10 paper units.
- A paper-space centerline or free sheet point can be combined with model
geometry through one viewport, in either pick order. The paper-space span is
measured using that viewport's scale.
- Sheet-only dimensions measure paper units, even inside a viewport rectangle.
- Model picks from a second viewport are rejected without advancing the command.
Dimension-line and text placement do not change the measurement scale.
- The current dimension style's unit conversion is preserved. Angular dimensions
do not use length compensation. `DIMASSOC=0` explodes the compensated dimension.
- Free and typed sheet points measure paper units, including points inside a
viewport rectangle.
- Measuring points must all belong to the same space and, when applicable, the
same viewport. An incompatible pick leaves the command at its current step.
- Dimension-line and text placement do not change the measurement's space.
- Paper geometry takes priority over viewport geometry at an object pick.
- The final dimension style is applied before computing measurement scaling.
Length dimensions keep paper-space definition points and a negative `DIMLFAC`
override containing the effective user factor multiplied by `1 / viewport scale`.
Angular measurements do not use this length factor.
- `DIMASSOC=0` uses the same compensated value before exploding the annotation.
Snapping and object picking respect visibility, clipping, and viewport draw order.
Paper geometry has priority in object picks. Ordinary selection uses the active
drawing space. Object picks reuse the resident interaction index and resolve
nested block transforms.
## Persistent measurement data
![Measurement schematic: a five-unit sheet span measures 50 through a 1:10 viewport.](viewport-dimension-creation.svg)
`OCS_VIEWPORT_MEASUREMENT` XData stores three values: version `1` (integer16),
the positive user factor (real), and viewport compensation (real). This keeps the
user's unit conversion separate from viewport scale. The ordinary `DIMLFAC`
override remains sufficient for displaying the saved measurement in other CAD
readers. The data survives DXF/DWG saves and undo/redo.
## Saved scale
With `DIMASSOC=2`, acquired features attach a dimension to its viewport, each
block instance, and the source entity. Intersections retain both source chains.
Source edits and viewport changes update the definition points and recompute
compensation while preserving explicit user-positioned sheet text and dimension
style overrides. A successful update invalidates the saved picture block so the
new geometry and number are rendered and exported. Undo restores both the
reference data and the previous picture.
Length dimensions store paper-space definition points and a negative `DIMLFAC`
override: user unit factor multiplied by `1 / viewport scale`.
`OCS_VIEWPORT_MEASUREMENT` XData stores version `1` (integer16), the positive user
factor (real), and viewport compensation (real). Keeping the factors separate
allows compensation to change without losing the user's unit conversion.
Both the override and XData survive DXF/DWG saves and undo/redo.
Properties reports whether the dimension is associated, partially associated,
unresolved, broken, or nonassociative. A broken or unsupported required reference
preserves the entire dimension's last valid appearance and its original records.
Creating another dimension does not announce geometry changes to its sources.
## Associations
## Imported references and support limits
With `DIMASSOC=2`, acquired features retain their viewport, block-instance path,
source entity, and snap feature. Intersections retain both source chains.
Source edits and viewport changes update the dimension and its compensation,
preserving style overrides and user-positioned text on the sheet.
The resolver distinguishes the application's vertex/parameter convention from
imported edge references. Imported start/end and midpoint modes use their edge
marker and parameter together. The original regression drawing's first-edge
start/end pair now reproduces its `0.128` measurement. An imported polyline
endpoint beyond the first edge requires a usable stored point to validate the
marker; zero/sentinel data cannot establish that identity. Ambiguous imports
remain unresolved. Imported viewport scale is updated only when existing OCS
metadata or `ACAD_DIMASSOC_CALC_DIMLFAC` separates compensation from user scaling.
A sheet centerline stays on the sheet; a model endpoint follows its viewport.
Moving the viewport therefore changes the distance between them. Undo/redo and
DXF/DWG saves preserve the references.
Unsupported cases retain their saved data and appearance:
Properties shows association status. If a required reference is broken or cannot
be resolved, the entire dimension keeps its last valid geometry and reference
records. A successful refresh regenerates its displayed and exported geometry.
- Perspective/oblique viewport projections and malformed/missing reference chains.
- Ambiguous intersections within one batched block; they are not attached to a
guessed pair of children. Intersections between separate identified chains work.
- Array inserts without an addressable instance index, nesting beyond eight levels,
and radial measurements of nonuniformly transformed circular geometry.
- Imported quadrant references whose moved geometry no longer validates the stored
point; newly acquired circle/arc quadrants keep their source-local angle.
- Tangency with no verified solution, two dependent perpendicular/tangent references
requiring a coupled solve, unsupported snap modes, and imported measurement data that does not identify the old viewport compensation.
![Association schematic: moving the sheet centerline changes the dimension from 50 to 40.](viewport-dimension-association.svg)
The osnap codes and reference fields follow the
[Autodesk DIMASSOC reference](https://help.autodesk.com/cloudhelp/2024/ENU/AutoCAD-DXF/files/GUID-C0B96256-A911-4B4D-85E6-EB4AF2C91E27.htm).
The restricted imported-marker interpretation above is validated by fixtures;
it is not a claim that every exporter uses an interchangeable marker scheme.
## Limits
## Validation
Unsupported cases preserve saved dimensions:
`src/app/viewport_dimension_tests.rs` exercises snap-engine acquisition, command
commits for all five commands, object picks, input retries, active positive and
negative style factors, exploded dimensions, undo/redo, DXF/DWG persistence,
clipping, overlapping viewports, pan, scale, and twist. These are headless tests;
they do not establish visual acceptance in the desktop UI.
- Perspective or oblique views; missing or malformed reference chains.
- Array instances without an addressable instance index, nesting beyond eight
levels, and radial measurements of nonuniformly scaled circles or arcs.
- Intersections without two identifiable source chains inside a batched block.
- Ambiguous imported endpoint, midpoint, or quadrant markers. A stored point can
validate a feature; it cannot establish an otherwise unknown identity.
- Tangency without a verified solution, or two perpendicular/tangent references
requiring a coupled solve.
- Imported viewport scaling without OCS scale metadata or
`ACAD_DIMASSOC_CALC_DIMLFAC` identifying the saved compensation.
Association tests also exercise regeneration, nearest and quadrant parameters,
angular arc/polyline object picks, spline tangency,
perpendicularity under nonuniform block scale, nested paths, intersection source
edits, preserved overrides, erased sources, copy detachment, saved picture
invalidation, and history. The checked-in DXF fixture is exercised directly.
The original private drawing can be checked separately:
## Tests
```powershell
$env:OPENCAD_VIEWPORT_REGRESSION_DXF = 'C:\path\to\115448.dxf'
cargo test --locked --offline --lib viewport_dimension_original -- --ignored --nocapture
```
Do not treat passing headless checks as completed desktop visual acceptance.
Run `cargo test --locked --lib viewport_dimension`. Tests cover the five commands,
mixed sheet/model input, styles, clipping, object picks, source/viewport edits,
snap features, nested paths, intersections, preserved overrides, undo/redo, and
DXF/DWG persistence. The synthetic association fixture is in
`tests/fixtures/dim_assoc/`.