a6c2c04736
Vollständige Bestandsaufnahme der Codebasis als neue STATUS.md (Kennzahlen, Feature-Inventar, Mist-Liste: toter Code, verwaiste WASM-Crates, Doku-Widersprüche). ARCHITECTURE.md/README.md/CONVENTIONS.md waren noch auf dem Tag-1-Planungsstand (Electron/Three.js/OpenCascade/Zustand/HLR-Worker) und beschrieben nicht mehr, was tatsächlich gebaut wurde (eigene Rust/WASM-Engines, eigener Store, analytische Rust-Schnitt-Pipeline, Tauri auf macOS + Electron auf Linux). ROADMAP.md und HANDOVER.md als historisch markiert (Hinweis-Box), Inhalt unverändert.
391 lines
20 KiB
Markdown
391 lines
20 KiB
Markdown
# Architektur — Dossier (Desktop-CAAD)
|
|
|
|
> Stand: 2026-07-21 (grundlegend überarbeitet — siehe [STATUS.md](STATUS.md) für
|
|
> die volle Bestandsaufnahme inkl. Mist-Liste, die diese Überarbeitung begründet).
|
|
> Vision/Phasen (historisch, Tag-1-Stand): [ROADMAP.md](ROADMAP.md). Konventionen:
|
|
> [CONVENTIONS.md](CONVENTIONS.md). Detail-Designs (teils ebenfalls veraltet,
|
|
> siehe Hinweis in [docs/README.md](docs/README.md)): [docs/design/](docs/design/).
|
|
|
|
Dieses Dokument beschreibt, **wie** Dossier tatsächlich gebaut ist — nicht wie
|
|
es am ersten Tag geplant war. Dossier ist die eigenständige Neuimplementierung
|
|
des Rhino-Plugins [DOSSIER](https://git.openbureau.ch/karim/dossier): dieselbe
|
|
Denkweise (Geschosse, Kategorie-Ebenen, mehrschichtige Bauteile,
|
|
Prioritäts-Verschneidung), aber als **native Desktop-App** mit einem **eigenen
|
|
typisierten Datenmodell in TypeScript** und **zwei eigenen Rust/WASM-Rendering-
|
|
Engines** („Nordstern") statt Rhino-Dokument/IronPython.
|
|
|
|
**Desktop-Rahmen (plattformabhängig, wegen WebGPU):** auf **macOS Tauri**
|
|
(WKWebView unterstützt WebGPU), auf **Linux Electron/Chromium** (Tauris
|
|
Linux-Webview WebKitGTK unterstützt WebGPU nicht zuverlässig — die
|
|
render2d/render3d-Engines brauchen es). Beide teilen dieselbe React-App und
|
|
randlose Titelleiste; Laufzeit-Erkennung über `window.__TAURI__` bzw.
|
|
`window.dossierWindow` (Electron-`contextBridge`). Details: STATUS.md §2.7.
|
|
|
|
Alle Bezeichner im Code sind **englisch**; Prosa und UI-Texte sind deutsch.
|
|
Einheiten intern in **Metern**.
|
|
|
|
---
|
|
|
|
## 0. Leitprinzip — ein Modell, viele Darstellungen
|
|
|
|
Das semantische Gebäudemodell (`Project`) ist die **einzige Wahrheit**. Jede
|
|
Sicht (3D, Grundriss, Schnitt, Ansicht) ist eine **reine Ableitung** daraus.
|
|
Darstellung (Detailgrad, Stile, Schraffuren, Overrides) wird **beim Rendern**
|
|
angewandt, nie in die Geometrie eingebacken. Dieses Prinzip hat sich über drei
|
|
Wochen und ~125.000 Zeilen Code bewährt und wird strikt gehalten — es ist der
|
|
einzige Teil der ursprünglichen Architektur-Vision, der **unverändert** Bestand
|
|
hat. Alle konkreten Technologie-Entscheidungen darunter (Rendering-Engine,
|
|
State-Store, Schnitt-Mechanismus) sind anders gelaufen als am Tag 1 geplant;
|
|
Details dazu in [STATUS.md](STATUS.md) §5.
|
|
|
|
```
|
|
┌──────────────────────────────────────────┐
|
|
│ Project (semantisches Modell, JSON) │ ← einzige Wahrheit
|
|
│ resources · types · drawingLevels · │
|
|
│ layers · walls/doors/openings/stairs/… │
|
|
└──────────────┬───────────────────────────┘
|
|
│ pure derive()
|
|
┌───────────────────────┼────────────────────────────┬───────────────┐
|
|
▼ ▼ ▼ ▼
|
|
3D-Viewport 2D-Plan (generatePlan) 3D-Live-Schnitt Export
|
|
Viewport3D (three.js) PlanView (SVG) · glPlan (GL2) render3d/section IFC/DXF/
|
|
ODER Wasm3DViewport ODER render2d (Rust/WGSL) (Rust, analytisch)PDF/STL
|
|
(Rust/wgpu, Default)
|
|
│ │ │ │
|
|
└────────── alle lesen dieselben joins/components/styles ─────────────┘
|
|
```
|
|
|
|
---
|
|
|
|
## 1. Repo-Struktur (IST-Zustand)
|
|
|
|
```
|
|
src/
|
|
model/ Project-Schema (types.ts, ~2500 LOC), joins.ts (Wand-Gehrung/
|
|
-Prio-Stösse), parametricWalls.ts, roomStamp.ts, terrain.ts,
|
|
geoRebase.ts, sampleProject.ts
|
|
geometry/ 2D-Kernel (kernel2d.ts: offset/trim/fillet/split — LIVE, siehe
|
|
§3), ceiling/opening/roomArea/roomBoundary/stair/roof/column.ts,
|
|
polygonHoles.ts
|
|
commands/ Rhino-artiges Kommandosystem: types/registry/engine/parseInput.ts
|
|
+ cmds/ (ein Modul je Kommando: wall, opening, stair, roof,
|
|
column, room, line/rect/circle/arc, move/mirror/copy/offset/
|
|
trim/join, extrude, import, terrain, measure, georef, …)
|
|
tools/ Interaktive Zeichenwerkzeuge, snapping.ts, transform.ts (Grips)
|
|
compute/ Compute-Boundary: leitet Ops (aktuell nur computeJoins) unter
|
|
Tauri via `invoke` an Rust weiter, sonst TS-Fallback
|
|
plan/ generatePlan.ts (2D-Ableitung), PlanView.tsx (SVG + Pan/Zoom/
|
|
Grips), glPlan/ (eigener WebGL2-Renderer), toSection.ts/
|
|
toElevation.ts (Schnitt/Ansicht-Ableitung), toWalls3d.ts,
|
|
toRenderScene.ts (Szene für Rust-render2d), wallMeshCut.ts
|
|
viewport/ Viewport3D.tsx (three.js, „Free") UND Wasm3DViewport.tsx
|
|
(Rust/wgpu „Nordstern", Default/editierbar), raycast3d.ts
|
|
section/ TOTER Code (OCCT-WASM-HLR-Spike, keine Aufrufer mehr) — Schnitt
|
|
läuft über render3d/section.rs, siehe §4.3
|
|
export/ exportIfc.ts (IFC4), exportDxf.ts/dxfWriter.ts, exportPdf.ts,
|
|
layoutPdf.ts (Mehrseiten-PDF pro Ordner), exportMesh.ts (STL/OBJ),
|
|
exportSchedule.ts (CSV-Bauteilliste), sceneToPrintSvg.ts
|
|
materials/ ambientcg.ts (Live-Suche ambientCG-API), library.ts (13
|
|
gebündelte Starter-Materialien), runtime.ts (PBR-Material aus
|
|
ComponentMaterial via three.js TextureLoader)
|
|
io/ DXF/DWG-Import, Swisstopo (swissBUILDINGS3D/-ALTI3D/SWISSIMAGE,
|
|
LV95↔WGS84), OSM-Overpass, .lin/.pat-Parser, projectFile.ts
|
|
(.obp Speichern/Laden, Tauri-Lock)
|
|
overrides/ Regelbasierte Override-Engine (Bedingung → Aktion)
|
|
state/ Eigener Store auf `useSyncExternalStore` (KEIN Zustand/Redux):
|
|
store.ts + Slices (project/history/selection/view/layout/site/
|
|
notify), appStore.ts komponiert sie
|
|
panels/ Dock-/Floating-Panel-System (Dock/FloatingPanel/TabStrip/
|
|
registry/layout) + Panels (Tools, Attributes, ObjectInfo, Layers,
|
|
DrawingLevels, Site, RoomBalance, Elements, ViewSnapshots, Layouts)
|
|
ui/ App.tsx (Shell, **7.130 LOC — noch nicht auf dünne Shell
|
|
reduziert**, siehe STATUS.md §4.3), TopBar, ResourceManager.tsx
|
|
(Material-/Hatch-/Line-/Typ-Editoren, natives Fenster),
|
|
ContextMenu, CommandLine.tsx, LayoutSheet/-Menu, ribbon/
|
|
native/ NUR Tauri: native Fenster (Resources/Settings/DrawingLevels/
|
|
LayerSettings/ContextImport), macOS-Menüleiste, Fenster-Chrome —
|
|
jede Funktion no-opt via `isTauriRuntime()` im Browser
|
|
editors/ booleanOps.ts (2D-Boolean via polygon-clipping), splitJoin.ts
|
|
text/ Rich-Text (richText.ts, RichTextEditor.tsx, renderHtml.ts)
|
|
theme/ Hell/Dunkel, Akzentfarben
|
|
i18n/ de.ts/en.ts Wörterbücher, eigener t()-Mechanismus
|
|
engine/ Reine WASM-Lade-Glue: engine3d.ts (pkg3d), truckSolid.ts
|
|
(pkgTruck), plan/useWasmPlanRenderer.ts (pkg) — pkgGeometry und
|
|
pkgDwgImport sind gebaut, aber unbenutzt (siehe STATUS.md §4.1)
|
|
|
|
src-tauri/
|
|
src/ Tauri-Host (Fenster, native Dialoge, fs4-Exklusiv-Lock)
|
|
render2d/ 2D-Plan-GPU-Renderer (wgpu/WGSL, + glyphon-Text), auch → WASM
|
|
render3d/ „Nordstern" 3D-Engine (wgpu/WGSL): Wandextrusion + Schicht-
|
|
bänder + Gehrung, LIVE 2D=3D-Schnitt (section*.rs, analytisch,
|
|
kein HLR), Kanten-Extraktion, Materialtextur-Arrays,
|
|
Aerial-Drape, Render-Styles (Shaded/White/Textured/Wireframe/
|
|
Hidden/ShadedEdges) — auch → WASM
|
|
kernel2d/ Rust-Port von geometry/kernel2d.ts — NUR Paritätstest, nicht
|
|
produktiv (WASM war < 100 Wänden langsamer als TS)
|
|
geometry/ Wand-Join-Mathe — Rust-Port, UNBENUTZT (kein Aufrufer)
|
|
trucksolid/ CSG/Extrusion (`truck`-Crate + `csgrs`-Booleans) → WASM,
|
|
genutzt vom Extrude-Kommando; Boolean NICHT an Wände/
|
|
Öffnungen angeschlossen
|
|
dwgimport/ DXF-Parser-Spike (`acadrust`) → WASM, UNBENUTZT (DWG-Import
|
|
läuft über npm `@mlightcad/libredwg-web`)
|
|
```
|
|
|
|
Jedes Crate unter `src-tauri/` ausser dem Host ist ein **eigenständiges
|
|
Cargo-Package** (kein gemeinsamer Workspace), das sowohl headless
|
|
(`cargo test`) als auch per `wasm-pack --features web` baut und dann via
|
|
`src/engine/pkg*/` von der TS-Seite geladen wird (`npm run build:engine{,3d,
|
|
Geometry,Kernel2d,DwgImport}`/`build:truck`).
|
|
|
|
---
|
|
|
|
## 2. Datenmodell
|
|
|
|
### 2.1 Zwei unabhängige Achsen (unverändert gegenüber der Vision)
|
|
|
|
1. **Zeichnungsebenen** (`DrawingLevel`) — Geschoss (`kind:"floor"`,
|
|
`floorHeight`/`cutHeight`/`baseElevation`), Schnitt/Ansicht
|
|
(`kind:"section"|"elevation"`), oder freie Zeichnung (`kind:"drawing"`).
|
|
2. **Ebenen** (`LayerCategory`) — das Grafik-Kategorie-Schema (Baum,
|
|
`{code, name, color, lw, visible, locked, hatch?, children}`), in jedem
|
|
Geschoss gültig. Codes 1:1 aus DOSSIER (`00 Raster · 01 Vermessung ·
|
|
20 Wände (└21 Türen/Fenster, 25 Stützen) · 30 Decken · 31 Dächer ·
|
|
40 Treppen · 50 Text · 60 Räume · 80 Plangrafik …`).
|
|
|
|
### 2.2 Elemente — typisierte Arrays statt `Element[]`-Union
|
|
|
|
Anders als ursprünglich geplant hält `Project` (`src/model/types.ts:2095`)
|
|
**pro Bauteiltyp ein eigenes (meist optionales) Array**:
|
|
|
|
```ts
|
|
interface Project {
|
|
walls: Wall[];
|
|
ceilings?: Ceiling[];
|
|
roofs?: Roof[];
|
|
doors: Door[]; // ÄLTER — siehe openings; bewusste Doppelspur
|
|
openings?: Opening[]; // NEUER, allgemeiner: kind:"window"|"door"
|
|
stairs?: Stair[];
|
|
rooms?: Room[];
|
|
columns?: Column[];
|
|
extrudedSolids?: ExtrudedSolid[];
|
|
drawings2d: Drawing2D[];
|
|
context?: ContextObject[]; // Terrain/Importe — NICHT semantisch
|
|
parametricWalls?: ParametricWall[];
|
|
overrideRules?: OverrideRule[];
|
|
viewSnapshots?: ViewSnapshot[];
|
|
viewSnapshotFolders?: ViewSnapshotFolder[];
|
|
layouts?: Layout[];
|
|
masterLayouts?: MasterLayout[];
|
|
layoutFolders?: LayoutFolder[];
|
|
// + Bibliotheken: lineStyles, hatches, components, wallTypes, roofTypes?,
|
|
// doorTypes?, windowTypes?, stairTypes?, ceilingTypes?
|
|
// + drawingLevels, layers, geoAnchor?, referenceElevationMasl?
|
|
}
|
|
```
|
|
|
|
Ein `Element`-Typalias existiert noch (`kind:"door"|"window"` etc.), wird aber
|
|
nirgends im Code referenziert — Selektion/Element-Baum arbeiten direkt auf den
|
|
typisierten Arrays. `doors`/`openings` sind eine **bekannte, noch nicht
|
|
konsolidierte Doppelspur** (PENDENZEN.md).
|
|
|
|
### 2.3 Ressourcen & Aufbauten (unverändert gegenüber der Vision)
|
|
|
|
```ts
|
|
interface Resources { lineStyles: LineStyle[]; hatches: Hatch[]; components: Component[]; }
|
|
interface WallType { id; name; layers: { componentId; thickness }[]; }
|
|
```
|
|
|
|
`joinPriority` sitzt am `Component` (Daten statt Hardcode) und steuert die
|
|
Prioritäts-T-/X-Verschneidung — **fertig implementiert**, inklusive Rust-Port
|
|
für den 3D-Live-Schnitt (`section_boolean.rs` = Port von
|
|
`toSection.ts::subtractDominantBands`).
|
|
|
|
### 2.4 Layouts / Ausschnitte
|
|
|
|
`ViewSnapshot` (Kamera/Massstab/Detailgrad/Sichtbarkeiten/Override-Preset) in
|
|
`ViewSnapshotFolder`-Bäumen; `Layout` (Papierformat, mehrere
|
|
`LayoutViewport`s, freie `LayoutAnnotation`s, optionale `MasterLayout`-Vererbung)
|
|
in `LayoutFolder`-Bäumen. Beide gehören ins Dokument (nicht LocalStorage).
|
|
|
|
---
|
|
|
|
## 3. State, Persistenz, Undo/Redo
|
|
|
|
### 3.1 Store — eigener `useSyncExternalStore`, nicht Zustand
|
|
|
|
Entgegen der ursprünglichen Empfehlung (Zustand-Library) wurde ein
|
|
**abhängigkeitsfreier Store** gebaut (`src/state/store.ts`, gleiches Muster wie
|
|
`src/i18n`): `createStore()` komponiert Slice-Fabriken über eine gemeinsame
|
|
`RootState`. `appStore.ts` fügt zusammen: `projectSlice` (Projekt + Undo/Redo,
|
|
`setProject` als einziger Mutations-Einstiegspunkt), `historySlice`,
|
|
`selectionSlice`, `viewSlice`, `layoutSlice`, `siteSlice`, `notifySlice`
|
|
(Toast/Confirm-Ersatz für `window.alert`, in Tauris WKWebView deaktiviert).
|
|
Komponenten lesen über `useStore(selector)`.
|
|
|
|
**Nicht umgesetzt** (geplant in `docs/design/state-architecture.md`): die
|
|
Extraktion von View-Routing nach `src/views/` und Kontextmenü-Aufbau nach
|
|
`src/menus/` — beide Ordner existieren nicht, diese Logik liegt weiterhin
|
|
inline in `App.tsx` (7.130 Zeilen). Siehe STATUS.md §4.3.
|
|
|
|
### 3.2 Persistenz
|
|
|
|
- **Datei:** eigenes `.obp`-Format (`src/io/projectFile.ts`), unter Tauri über
|
|
native Speichern/Öffnen-Dialoge (`plugin-fs`/`plugin-dialog`), im Browser
|
|
Blob-Fallback. Ältere `.json`-Projekte bleiben ladbar.
|
|
OS-Level-Exklusiv-Lock (`fs4`-Crate, `src-tauri/src/lock.rs`) verhindert
|
|
Doppelöffnen desselben Projekts.
|
|
- **Compute-Boundary:** `src/compute/index.ts` leitet einzelne Operationen
|
|
(aktuell nur `computeJoins`) unter Tauri via `invoke` an eine native Rust-
|
|
Implementierung weiter; im Browser bzw. für nicht migrierte Ops (Room-
|
|
Detection, DWG-Parsing) läuft die TS-Implementierung.
|
|
|
|
### 3.3 Undo/Redo
|
|
|
|
Eigener History-Ring im `projectSlice` (kein DOSSIER-Sticky-Bus, kein
|
|
Cache-Stale-Problem, da alle Sichten pure Ableitungen sind).
|
|
|
|
---
|
|
|
|
## 4. Rendering
|
|
|
|
### 4.1 Zwei 3D-Viewports
|
|
|
|
- **`Viewport3D.tsx`** — three.js, die „Free"-Stufe.
|
|
- **`Wasm3DViewport.tsx`** — Rust/wgpu, „Nordstern", editierbar, **Default**.
|
|
Ein Settings-Schalter wählt die Engine; WebGL2/three.js nur noch als
|
|
explizite Wahl oder Fallback.
|
|
|
|
`render3d` (10.246 LOC) baut Wandextrusion inkl. Schichtbändern und
|
|
Prioritäts-Gehrung (`compute_wall_miters`), Materialtextur-Arrays (pro
|
|
Wandschicht) + separate Aerial-Drape-Textur, Render-Styles (Shaded/White/
|
|
Textured/Wireframe/Hidden/ShadedEdges via Kanten-Extraktion mit
|
|
Crease-Erkennung). **Dächer/Treppen/Stützen haben KEINE eigene Rust-Geometrie**
|
|
— sie werden vollständig in TypeScript erzeugt (`geometry/roof.ts`,
|
|
`emitRoofs`/`emitColumns`) und Rust nur als vorberechnetes Dreiecks-Mesh
|
|
(`MeshInput`/`append_context_mesh`, derselbe generische Importpfad wie für
|
|
swissBUILDINGS3D/DXF) übergeben.
|
|
|
|
### 4.2 Grundriss = drei koexistierende Renderer
|
|
|
|
1. **`PlanView.tsx`** (SVG) — bleibt immer im DOM (Hit-Testing/Grips),
|
|
unabhängig vom aktiven Zeichenpfad.
|
|
2. **`plan/glPlan/`** — eigener TypeScript-WebGL2-Renderer.
|
|
3. **`useWasmPlanRenderer.ts`** → Rust-`render2d` (WGSL, wgpu nativ,
|
|
WebGPU/WebGL2-Fallback im Web, echtes Text-Rendering via `glyphon`).
|
|
|
|
Beide GPU-Pfade fallen bei Init-Fehler still auf SVG zurück.
|
|
|
|
### 4.3 Schnitt/Ansicht — analytische Rust-Pipeline, KEIN HLR
|
|
|
|
Der ursprünglich geplante OCCT-WASM-HLR-Pfad (`src/section/hlr.ts`/`occt.ts`)
|
|
ist **toter Code** (keine Aufrufer mehr). Der tatsächlich funktionierende
|
|
Live-Schnitt nutzt aus, dass jedes Bauteil ein Prisma mit konstantem
|
|
Querschnitt ist — eine Schnittebene liefert dadurch **immer** ein
|
|
achsparalleles Rechteck, nie ein Trapez, wodurch HLR unnötig wird:
|
|
|
|
```
|
|
App.tsx (section3dCutId/section3dPlane)
|
|
→ Wasm3DViewport.tsx (section3d-Prop → setSectionPlane)
|
|
→ src-tauri/render3d/src/{section.rs, section_boolean.rs, section_fill.rs}
|
|
```
|
|
|
|
`section_boolean.rs` ist ein 1:1-Port von `toSection.ts::subtractDominantBands`
|
|
— 2D-Plan-Schnitt und 3D-Live-Schnitt nutzen dieselbe Prioritäts-Logik und
|
|
stimmen dadurch exakt überein. Kein Worker, kein Comlink (beides war geplant,
|
|
existiert nirgends im Projekt) — läuft synchron GPU-seitig.
|
|
|
|
### 4.4 Öffnungen als Löcher (kein Mesh-Boolean)
|
|
|
|
Fenster/Türen schneiden echte achsparallele Rechteck-Löcher aus dem Wandkörper
|
|
(`plan/toWalls3d.ts` `subtractSpans`, gespiegelt in `render3d::mesh.rs`).
|
|
Ein generisches Mesh-CSG-Boolean existiert bereits (`trucksolid::boolean_mesh`,
|
|
`csgrs`, für das Extrude-Kommando genutzt), ist aber nicht an die
|
|
Wand/Öffnungs-Pipeline angeschlossen.
|
|
|
|
### 4.5 Materialien
|
|
|
|
`materials/library.ts` (13 gebündelte PBR-Starter, ambientCG CC0) +
|
|
`materials/ambientcg.ts` (Live-Suche der kompletten ambientCG-Bibliothek,
|
|
1K/2K/4K-Auflösungswahl, On-Demand-Download via `jszip`, Proxy wegen CORS) →
|
|
`materials/runtime.ts` baut daraus gecachte `THREE.MeshStandardMaterial`s mit
|
|
physisch korrekter Kachelgrösse (UV in Weltmetern).
|
|
|
|
---
|
|
|
|
## 5. React-Panel-Struktur
|
|
|
|
Dock-/Floating-Panel-System (`src/panels/`: Dock, FloatingPanel, TabStrip,
|
|
Registry) mit eingebauten Panels: Tools, Attributes, ObjectInfo,
|
|
DrawingLevels, Layers, Site (Kontext/Terrain-Import), RoomBalance
|
|
(SIA-416-CSV), Elements (Bauteilbaum), ViewSnapshots, Layouts.
|
|
|
|
Der **Resource Manager läuft bewusst NICHT als Dock-Panel**, sondern als
|
|
eigenständiges (unter Tauri natives) Fenster — ebenso Settings,
|
|
DrawingLevels-Detaileditor, LayerSettings und ContextImport
|
|
(`src/native/*Window.ts` + `*WindowApp.tsx`), jeweils mit
|
|
`isTauriRuntime()`-Gate und ohne separate Browser-Variante (im Browser bleibt
|
|
die entsprechende In-App-Overlay-Variante aktiv, wo vorhanden).
|
|
|
|
**Werkzeug-System:** `Tool`-Interface (`src/tools/types.ts`) für Zeichenwerkzeuge
|
|
mit Snap-Engine; daneben das umfangreichere **Kommandosystem** (`src/commands/`)
|
|
für Rhino-artige getippte Eingabe (`5,3`/`r5,3`/`5<45`, Tab-Feld-Zyklus in
|
|
`CommandLine.tsx`) — beide koexistieren, decken unterschiedliche
|
|
Interaktionsstile ab.
|
|
|
|
---
|
|
|
|
## 6. Rhino → Dossier — Mapping-Tabelle (Kernkonzepte)
|
|
|
|
| DOSSIER (Rhino-Plugin) | Dossier (Tauri) | Anmerkung |
|
|
|---|---|---|
|
|
| Rhino `RhinoDoc` | `Project` (TS-Objekt im eigenen Store) | einzige Wahrheit |
|
|
| `doc.Strings[key]=json` | Feld im `Project`-JSON | persistiert in `.obp` |
|
|
| `.3dm`-Datei | **`.obp`**-Datei (Tauri `plugin-fs`) | + Blob-Fallback im Browser |
|
|
| `sc.sticky` (cross-modul Bus) | eigener `useSyncExternalStore`-Store | kein Polling |
|
|
| Rhino Layer-Tabelle | `LayerCategory[]`-Baum, Sichtbarkeit als `.visible`-Flag | pro Renderer umgesetzt |
|
|
| Clipping-Plane (`AddClippingPlane`) | `render3d::section.rs` (analytisch, Rechteck-Subtraktion) | KEIN HLR |
|
|
| `HLRBRep` | — (ungenutzt; OCCT-Spike ist toter Code) | ersetzt durch obiges |
|
|
| `Rhino.Geometry.Brep`-Booleans | `trucksolid::boolean_mesh` (csgrs) | existiert, nicht an Wände angeschlossen |
|
|
| Rhino-Grips + DisplayConduit | Pointer-Events + Grip-Overlay (2D vollständig, 3D nur Basis, kein Snap) | siehe STATUS.md §4.7 |
|
|
| Swisstopo via .NET HttpClient | `fetch()` (CORS-offen) | radiusgenau zugeschnitten (nicht ganze STAC-Kachel) |
|
|
| IronPython-Laufzeit-Risiken | entfällt | TS/Rust |
|
|
|
|
---
|
|
|
|
## 7. Was übernommen wurde — und was bewusst anders lief
|
|
|
|
**Übernommen (Prinzipien, bewährt):**
|
|
- Zwei-Achsen-Dokumentmodell, Layer-Codes 1:1, Component/Hatch/Line-Manager
|
|
mit `joinPriority`, LoD (grob/mittel/fein), regelbasierte Overrides,
|
|
Ausschnitte, SIA-416-Räume, Norden-Rotation.
|
|
- Pure-Ableitungs-Architektur (kein Cache-Stale, kein Sticky-Bus).
|
|
|
|
**Anders gelaufen als geplant (siehe STATUS.md §5 für die volle Tabelle):**
|
|
- Eigene Rust/WASM-Rendering-Engines statt Three.js/OpenCascade.js/web-ifc.
|
|
- Typisierte Arrays pro Bauteiltyp statt `Element[]`-Union.
|
|
- Eigener Store statt Zustand-Library.
|
|
- Analytische Rust-Schnitt-Pipeline statt HLR/Worker/Comlink.
|
|
- App.tsx wurde **nicht** wie geplant auf eine dünne Shell reduziert
|
|
(`src/views/`/`src/menus/` wurden nie angelegt) — bekannter, unbereinigter
|
|
Punkt, siehe STATUS.md §4.3.
|
|
|
|
**Anti-Over-Engineering (weiterhin gültig):** keine Abstraktion ohne konkretes
|
|
Problem; erst lesen, dann editieren; Geometrie nie „nebenbei" refactoren.
|
|
|
|
---
|
|
|
|
## 8. Reihenfolge bei Code-Arbeit
|
|
|
|
1. **STATUS.md** (aktueller Ist-Zustand) + dieses Dokument lesen.
|
|
2. **Das betroffene Modul** lesen (nicht raten) — bei Zweifel: welcher der
|
|
mehreren Renderer/Pfade ist gerade aktiv (§4.1/§4.2)?
|
|
3. **Erst danach editieren**; `Project` immer immutabel via den Store ändern.
|
|
4. **Verifizieren:** `npx tsc -b`, `npm test` (Vitest), `cargo test` in den
|
|
betroffenen Crates, bei Rust-Änderungen `npm run build:engine{,3d}` (WASM
|
|
neu bauen, nur `.rs` committen — `src/engine/pkg*/` ist gitignored). Bei
|
|
render3d/Wasm3DViewport-Änderungen testet der Nutzer selbst in der
|
|
Tauri-Dev-App (nicht per Puppeteer/Browser verifizierbar).
|
|
5. **Dieses Dokument aktuell halten**, wenn sich Patterns ändern — insbesondere
|
|
nicht wieder in „Ziel-Struktur"-Beschreibungen abdriften, die Monate lang
|
|
niemand nachführt.
|