refactor(scene): reference-only designation becomes a scene-scoped set (API v9)

Per the upstream review of the XDATA-based storage: the host no longer writes
its own state into the saved file. The marker record under the host-owned OCS
APPID, the on-first-use APPID registration and the verbatim-EED rewrite
handling are removed; the single source of truth is a scene-scoped in-memory
set of entity handles (Scene::reference_only) that dies with the drawing tab,
so a reopened file starts undesignated and the owning plugin re-marks on the
document-opened notification.

All behaviour sites are unchanged, driven by the set: the wire stamp moves
from an XDATA read to a set lookup threaded through the tessellation
pipelines (tessellate_entity and the dimension text path take the handle set
as a plain parameter), and the pick filters, selection retains and
update/erase refusals read Scene::is_reference_only.

Undo keeps the entity-write contract: set mutations are recorded as explicit
first-touch before/after values on each history delta (the parametric-
constraints channel pattern). A designation inside a plugin push_undo scope
joins it, a scope-less change is one step of its own, an idempotent re-mark
records nothing, erasing a designated entity drops the set entry with the
entity, and undo/redo restores entity and designation together.

The round-trip test is inverted: reference_only_designation_is_not_written_
to_dwg_or_dxf now asserts the marker appears in neither format's bytes, that
no OCS APPID or marker record survives a reload, and that the designation
stays live in memory.
This commit is contained in:
Sebastian committed 2026-10-14 21:12:17 +02:00
1 parent 06ee0798a8
commit 50db12b169
17 files changed
+623 -232

No files matched your search

+16 -2
View File
@@ -473,6 +473,7 @@ fn section_symbol_wires(
/// so it picks up the standard text LOD ladder (baseline / greek / full),
/// then re-color the returned wires with the dimension's resolved text colour
/// (so DIMCLRT / DIMSTYLE colours win over the synthetic Text's defaults).
#[allow(clippy::too_many_arguments)]
pub(crate) fn tessellate_entity_dim_text(
document: &codec::CadDocument,
selected: &HashSet<Handle>,
@@ -483,6 +484,7 @@ pub(crate) fn tessellate_entity_dim_text(
view_aabb: Option<[f32; 4]>,
world_per_pixel: Option<f32>,
text_color: [f32; 4],
reference_only: &HashSet<Handle>,
) -> Vec<WireModel> {
let mut wires = tessellate_entity(
document,
@@ -496,6 +498,7 @@ pub(crate) fn tessellate_entity_dim_text(
view_aabb,
world_per_pixel,
false,
reference_only,
);
for w in &mut wires {
// Synth dim text carries no real entity colour — paint everything
@@ -508,6 +511,7 @@ pub(crate) fn tessellate_entity_dim_text(
}
wires
}
#[allow(clippy::too_many_arguments)]
pub(crate) fn tessellate_entity(
document: &codec::CadDocument,
selected: &HashSet<Handle>,
@@ -520,6 +524,7 @@ pub(crate) fn tessellate_entity(
view_aabb: Option<[f32; 4]>,
world_per_pixel: Option<f32>,
paper_space: bool,
reference_only: &HashSet<Handle>,
) -> Vec<WireModel> {
let mut wires = tessellate_entity_inner(
document,
@@ -533,6 +538,7 @@ pub(crate) fn tessellate_entity(
view_aabb,
world_per_pixel,
paper_space,
reference_only,
);
let layer_plottable = document
@@ -550,8 +556,10 @@ pub(crate) fn tessellate_entity(
// Reference-only entities (API v9) render and snap normally but must not
// be picked by the built-in edit paths; the pick-side wire filters in
// `scene::pick::hit_test` and the selection-gather retains consume the
// flag.
if crate::scene::reference_only::entity_is_reference_only(e) {
// flag. The stamp is driven by the scene's in-memory designation set —
// outside `Scene` this stays pure data, so the parallel tessellation
// workers only need the handle set, not scene access.
if reference_only.contains(&e.common().handle) {
for wire in &mut wires {
wire.reference_only = true;
}
@@ -559,6 +567,7 @@ pub(crate) fn tessellate_entity(
wires
}
#[allow(clippy::too_many_arguments)]
fn tessellate_entity_inner(
document: &codec::CadDocument,
selected: &HashSet<Handle>,
@@ -577,6 +586,10 @@ fn tessellate_entity_inner(
// Retained through recursive INSERT expansion; PSLTSCALE itself is applied
// by the viewport's GPU uniform so it never changes resident wire content.
_paper_space: bool,
// The scene's reference-only designation set (API v9): drives the
// `WireModel::reference_only` stamp for dimensions' synthesis paths that
// bypass the wrapper's post-stamp.
reference_only: &HashSet<Handle>,
) -> Vec<WireModel> {
let contextual = crate::scene::annotative::entity_for_annotation_context(
document,
@@ -1029,6 +1042,7 @@ fn tessellate_entity_inner(
bg_color,
view_aabb,
world_per_pixel,
reference_only,
);
for w in &mut wires {
w.aci = aci;