Extended Matrix

Extended Matrix Development Projects

← Back to Roadmap
DP-64

Viewport stratigraphic annotator on photogrammetric meshes (drag-to-link)

Tools v1.6 StratiGraph ↗ EMtoolss3Dgraphy

Description

The current authoring loop in EM Tools 1.5 has a small but daily friction. The modeller works inside the Blender viewport — placing Proxy Boxes on the photogrammetric mesh, Surface Areale projections on walls and floors, RM Manager assignments for the reconstructive geometry — and then, when it’s time to record that this proxy covers that proxy, leaves the viewport: either jumps to yEd to draw the relation as a temporal edge in the Matrix, or opens the Stratigraphy Manager panel and types the relation as a structured row. Both paths work; both break the spatial flow. The modeller has just been looking at the two proxies side by side on the photogrammetric mesh, seeing the contact between them — and now they’re typing text or dragging in a separate graph editor that has no idea where the proxies physically are.

DP-64 makes that recording a direct viewport gesture. The modeller clicks on proxy A, drags onto proxy B, picks the relation from a pie menu — and the canonical edge lands in s3dgraphy in the same instant. No context switch, no panel typing, no detour to yEd. The gesture is data-driven by the node_uuid linkage that already connects every proxy object to its s3dgraphy node; the relation is written through the canonical-edge API that the canonical-edges series (DP-62) standardised; the persistence story across GraphML d13 and pyArchInit rapporti is the same one already shipped in s3dgraphy 1.6.0.dev7+. Most of what makes this work is already there — DP-64 adds the gesture surface on top.

The architectural shape that makes the MVP cheap. A naive reading of the feature (“3D editor for stratigraphic edges in Blender”) suggests a big chunk of work — graph layout, persistence, multi-format export, multilingual labels, conflict resolution. None of that is in DP-64. The data layer that handles all of it was already moved to the right shape over the last two months: DP-62 made physical stratigraphic relations into first-class canonical edges in s3dgraphy, with byte-identical serialisation to GraphML and pyArchInit; PR #22 (s3dgraphy #21) generalised the recognition path to handle every UI language pyArchInit ships. The gesture is therefore a thin authoring layer that calls graph.add_edge(src=A.node_uuid, dst=B.node_uuid, edge_type='overlies') — and the rest of the EM machinery (canonical-edge dedup, temporal inference, palette mirroring, multilingual rapporti write-back) takes care of itself. The 1.6 MVP doesn’t need to invent any of that; it just needs to fire the right operator at the right moment.

Why temporal relations are out of scope on purpose. EM has a clean architectural rule that’s worth stating explicitly: temporal relations derive from physical relations, never the inverse. The 1.5 TemporalInferenceEngine already runs the Harris-Matrix logic that turns A overlies B into A is_after B; the GraphML exporter applies that transform at export time so the yEd Matrix shows the temporal collapse correctly. If DP-64 let the modeller author temporals directly in the viewport, there would be two authoring paths into the temporal layer — one derived from physical, one direct from gesture — and they would inevitably contradict each other in real data (a modeller draws A is_after B directly without first asserting the physical evidence; the inference engine derives B is_after A from a contradicting physical observation on the mesh; the graph now carries both with no clean rule for which to trust). The viewport annotator deliberately avoids that mess by staying at the physical layer — where the modeller has direct visual evidence on the photogrammetric mesh — and letting the temporal layer remain the derived view. The in-tool temporal Matrix work tracked under DP-19 (Canvas project) is the future home for direct temporal viewing; until then yEd holds it.

The MVP gesture, in concrete sequence. The modeller presses L (or clicks the Link button in the EM Bridge sidebar header) to enter Stratigraphic Linking mode. The cursor changes to a link icon over valid proxies, a red ban over photogrammetric mesh or other non-proxy objects. The modeller clicks on proxy A — A highlights with a subtle outline. They drag toward proxy B; a thin preview line follows the cursor. If multiple proxies sit under the cursor at the release point (common in stratified contexts), a small picker list near the cursor reads 1. US 24 (active) · 2. US 12 · 3. US 9 and Shift-click cycles through them. The modeller releases on the intended target — a 6-slice pie menu pops at the release point with slices labelled A Covers B, A Cuts B, A Fills B, A Abuts B, A Bonded to B, A Equal to B, each with a single-key accelerator. Power users hit C to pick Covers without aiming at the slice; everyone else click-selects. The pie menu footer reads will be added under <Activity X> / <Epoch Y> so the modeller sees the inherited context before commit. On commit, the canonical edge writes to s3dgraphy, a brief status-bar message confirms US 12 covers US 7 in Activity foundation_phase, and the operator exits. Ctrl+Z restores the graph to pre-gesture state.

What 1.7 adds. Once the MVP gesture is mature and stressed on real StratiGraph excavation data, the 1.7 cycle picks up two extensions: the 3D edge overlay draws every canonical physical relation as a colour-coded curve between proxy centroids in viewport (toggled in Visual Manager, drawn via GPU shader so no permanent scene objects pile up), and edit-on-edge lets the modeller click on a visible overlay edge to change its type, reverse its direction, or delete it. Together those two pieces close the read+edit loop without leaving the viewport. The overlay also doubles as a visual sanity check during fieldwork: looking at the 3D stratigraphy as authored, the modeller can immediately spot misordered units (an overlies arrow pointing the wrong way) or missing relations (a proxy floating without any edges into its surroundings) and fix them with the same gesture that created them in the first place.

Scope discipline for 1.6. The MVP intentionally excludes the 3D overlay and edit-on-edge. Without the overlay, the modeller’s only confirmation of a created edge is the status-bar message + the eventual GraphML export to yEd for visual inspection; with the overlay (1.7), the confirmation is immediate and spatial. This is a pragmatic trade: shipping the gesture in 1.6 even without overlay still cuts the authoring loop dramatically (no more panel typing for the daily 30+ proxy-to-proxy relations on an active excavation), and the overlay is a meaningful enough piece to deserve its own 1.7 cycle rather than being squeezed into 1.6 as a rushed addition. The StratiGraph excavations active during the 1.6 cycle are the natural beta testers — high proxy volume, multilingual workflows (the MVP works on Italian / English / German / Spanish / French / Romanian / Greek / Arabic sites by construction, since PR #22 already canonicalises the recognition path), and a real need to reduce the cognitive cost of stratigraphic authoring across long sessions.

Status

Concept — 1.6 MVP, 1.7 full

Target EM Version

1.6

Impacts

EMtoolss3Dgraphy

Components

  • Modal Blender operator (`bpy.types.Operator` with `modal()` event loop) capturing mouse-down → drag → mouse-up between two scene objects. Active in a dedicated *Stratigraphic Linking* mode toggled by a header button + keyboard shortcut. Cursor adapts (link icon on valid proxy, red ban on photogrammetric mesh or non-proxy geometry).
  • Endpoint validation: any Blender object whose `node_uuid` custom property maps to a US-family node in the active s3dgraphy graph qualifies as a valid drag endpoint. Includes both Proxy Box Creator outputs (DP-46) and Surface Areale geometries (DP-50). Non-proxy meshes (the photogrammetric base layer, decorative objects, scene helpers) are silently filtered out.
  • Picker list for z-overlap: when the cursor sits above multiple proxies (common in stratified excavations where a later unit visually overlaps an earlier one), Shift-click cycles through candidates in depth order. A small floating list near the cursor reads ‘1. US 24 (active) · 2. US 12 · 3. US 9’ — the first entry wins on plain click; the cycle index resets per gesture.
  • Pie menu (radial 6-slice) for relation choice, anchored at mouse position on release. Slices = the six canonical physical relations of the EM 1.5 vocabulary (`Covers`, `Cuts`, `Fills`, `Abuts`, `Bonded to`, `Equal to`), each with a single-key accelerator (`C` / `T` / `R` / `A` / `B` / `E`) for power users. Each slice label reads ‘<A> Covers <B>’ etc. with the two proxy names interpolated, so the direction is unambiguous before commit.
  • Direction semantics: the drag direction is the relation direction. Drag A→B + pick *Covers* = the canonical edge `A overlies B` (s3dgraphy edge type `overlies`). The reciprocal (`B is_overlain_by A`) is structural — DP-62's canonical edge model treats each direction as a separate edge type, so only one edge needs creating; the inverse direction is the same fact viewed from the other endpoint and is implicit in graph traversal.
  • Activity / epoch context inheritance: the new edge silently inherits the active Activity from the Activity Manager (DP-43) and the current epoch from the CronoFilter horizon (DP-10), so the relation lands in the right slice of the multi-graph / multi-epoch scene without prompting. A subtle indicator in the pie menu footer reads ‘will be added under <Activity X> / <Epoch Y>’ — visible but non-blocking. Power-user override: hold Ctrl during the drag to skip inheritance and prompt explicitly.
  • Write-through to s3dgraphy via the existing `sync.rapporti` machinery (DP-62). The gesture calls `graph.add_edge(src=A.node_uuid, dst=B.node_uuid, edge_type=…)`; persistence to GraphML d13 packed string + pyArchInit `us_table.rapporti` column on reverse export comes for free through the canonical-edges series shipped in s3dgraphy 1.6.0.dev7+. Multi-language site? PR #22's `UNITA_TIPO_CANONICAL` aliasing already covers the recognition path; the gesture works identically on Italian / English / German / Spanish / French / Romanian / Greek / Arabic sites.
  • Undo support: every gesture-created edge is one Blender undo step (Ctrl+Z restores the graph to its pre-gesture state, including any inferred reciprocal). Standard Blender idiom — the operator declares `bl_options = {'REGISTER', 'UNDO'}`.
  • (1.7 — full) 3D edge overlay layer: every canonical physical edge in the active graph is drawn in viewport as a thin curve / cylinder between proxy centroids, colour-coded by relation type (Harris Matrix conventions — solid for overlies/cuts/fills, dashed for abuts/bonded, double-solid for equal). Drawn via GPU shader callback so no permanent scene objects accumulate. Toggle in Visual Manager (DP-35) alongside the existing chronology / author / license overlays.
  • (1.7 — full) Click-to-edit on existing edges: clicking on a visible overlay edge opens a context menu with *Change relation type… / Reverse direction / Delete*. Each operation writes through the same `sync.rapporti` API and respects the same undo discipline as the MVP gesture.
  • (post-1.7, stretch) Point-pick mode: instead of centroid-to-centroid drag, an explicit point-pick on proxy A and proxy B records the spatial anchor of the relation (e.g. ‘US 12 covers US 7 at this specific point on the contact surface’). Useful for richly annotated reconstructive workflows where the geometric anchor is itself a documentary fact. Requires a Spatial-anchor extension to the canonical edge metadata — out of scope until the EM language layer formalises it.

Key Study

Needed — pick an active StratiGraph excavation with ≥100 proxies and a non-Italian UI, so the MVP gets stressed both on volume and on the multilingual write-through path

Notes

Triggered by the 2026-06 conversation about reducing the cognitive cost of stratigraphic authoring: in EM 1.5 the modeller can SEE two proxies on the photogrammetric mesh but has to switch to yEd or to the Stratigraphy Manager panel to RECORD that one covers the other. DP-64 closes that gap by making the gesture a direct viewport operation. Sequencing decision: ship a tight MVP in EM 1.6 (gesture + picker list + pie menu + write-through + activity inheritance, no 3D overlay, no edit-on-edge) so the workflow lands quickly and gets stressed on real StratiGraph data; the 3D overlay layer and edit-on-edge tooling follow in 1.7 once the MVP gesture has matured. Architectural why-this-is-cheap: the canonical-edges series (DP-62) already moved the data layer to the right shape — gesture writes to `graph.add_edge(...)` and persistence to all three serializations (in-memory canonical edges, GraphML d13 packed string, pyArchInit `rapporti` column) flows through the existing `sync.rapporti` machinery without new wire-format work. Same multilingual coverage as PR #22 (s3dgraphy #21) by construction — the gesture is data-driven by `node_uuid` linkage to s3dgraphy nodes, language of the row's `rapporti` term is preserved on write-back. Why physical-only (no temporal): temporal relations in EM 1.6 derive from the physical layer via the `TemporalInferenceEngine` (1.5 vintage — runs the Harris-Matrix logic that turns `A covers B` into `A is_after B`), never the inverse. Authoring temporal directly in the viewport would create a second authoring path that bypasses the inference and risks contradiction with the physical layer. The viewport annotator focuses on the observable evidence (the physical contact between two proxies as seen on the mesh); the temporal Matrix stays the derived view in yEd until the in-tool Matrix work in DP-19 (Canvas project) lands. Open decisions to flag at the review call: (1) shortcut to enter linking mode — proposing `L` (free key in EM Tools today) with the EM Bridge sidebar header button as the discoverable alternative; (2) cursor / picker list visuals — Blender's modal operators have limited cursor customisation, so the picker list might need a small modal overlay drawn via GPU shader rather than a true native cursor swap; (3) what happens when the gesture targets a proxy already linked to A via the same relation — silent no-op? Visual flash? Pie menu shows the existing relation greyed-out? Proposal: silent no-op with a brief status-bar message (no popup, no break in the modelling flow). Cross-refs: DP-46 (Proxy Box Creator) — proxy-creation precondition, the gesture only fires on objects DP-46 produced; DP-50 (Surface Areale System) — alternative proxy-creation source, same gesture endpoint applies; DP-62 (PyArchInit canonical-edges) — the canonical edge data layer the gesture writes to + the multilingual recognition layer from PR #22; DP-43 (Group Nodes — Time Branch, Activity, Paradata) — the activity inheritance context; DP-35 (UI/UX refactoring + Visual Manager) — where the 3D edge overlay toggle lives in 1.7; DP-19 (Canvas project) — eventual home of the in-tool temporal Matrix that DP-64 deliberately does NOT duplicate.