ca859c4aa4
Standalone-Browser-Port von DOSSIER. Enthaelt das semantische Modell mit Plan-/3D-Ableitung, Zeichen- und Editierwerkzeuge, Rhino-artiges Befehlssystem, dockbares Panel-System, Resource-Manager, DXF/.lin/.pat-Import, i18n (de/en) sowie Projektdokumentation und Probe-Harness.
425 lines
19 KiB
Markdown
425 lines
19 KiB
Markdown
# Design — Bauteile (Elements)
|
||
|
||
> Teil der Standalone-Architektur — siehe [../../ARCHITECTURE.md](../../ARCHITECTURE.md).
|
||
> Output/Pläne: [plans-output.md](plans-output.md). Ressourcen/Stile:
|
||
> [resources-graphics.md](resources-graphics.md).
|
||
|
||
Dieses Dokument legt die **Daten**, die **Generierung** (3D-Geometrie + Plan-
|
||
Symbolik) und das **Grip-Editing** je Bauteil fest und übersetzt DOSSIERs
|
||
`elemente.py` (7244 LOC, Monolith) in **kleine Bauteil-Module** (`src/model/
|
||
elements/wall.ts`, `opening.ts`, …). Bezeichner englisch, Prosa deutsch, Meter.
|
||
|
||
DOSSIERs Architektur dort: pro Element eine **Achse/Outline-Source** (editierbar)
|
||
+ ein **auto-generiertes Volumen** (`wand_axis`+`wand_volume`, Outline+Brep).
|
||
Browser-Äquivalent: das **semantische Element ist die Source**; Geometrie wird per
|
||
`generate*()` **abgeleitet** (nie persistiert). Das ist sauberer als DOSSIERs
|
||
zwei-Objekt-Modell und kennt kein Cache-Stale.
|
||
|
||
---
|
||
|
||
## 0. Gemeinsames Fundament
|
||
|
||
```ts
|
||
// src/model/elements/base.ts
|
||
interface ElementBase {
|
||
id: string;
|
||
type: ElementType; // "wall" | "window" | "door" | "slab" | "stair" | "roof"
|
||
// | "column" | "beam" | "space" | "draw2d"
|
||
floorId: string; // Zeichnungsebene (Geschoss); bei gehosteten via Host
|
||
categoryCode: string; // Ebene (Grafik-Kategorie), z.B. "20"
|
||
styleId?: string; // optionaler Element-Override-Stil (resources-graphics.md)
|
||
name?: string;
|
||
}
|
||
```
|
||
|
||
**Geometrie-Konvention** (aus CONVENTIONS.md, im Spike etabliert): Wand-Normale
|
||
`n = leftNormal(u) = (-u.y, u.x)`; bei CCW-Wicklung zeigt `+n` nach innen.
|
||
Schichten werden außen (`-T/2`) → innen (`+T/2`) gestapelt (`generatePlan.addWallPoche`,
|
||
`Viewport3D.addWallMeshes`).
|
||
|
||
**Detailgrad** (LoD) — DOSSIERs `darstellung` (`auto|einfach|standard|detail`):
|
||
```ts
|
||
type DetailLevel = "coarse" | "medium" | "fine"; // einfach | standard | detail
|
||
// Auflösung: Element-Wert "auto" → Dokument-/Snapshot-Wert; sonst Element-Wert.
|
||
function resolveDetail(el: ElementBase, doc: { detailLevel: DetailLevel }): DetailLevel
|
||
```
|
||
≙ DOSSIER `_resolve_oeff_darstellung` + `get_aktive_darstellung`. Steuert, *wie
|
||
viel* Symbolik gezeichnet wird (1:500 Rechteck → 1:50 Glas/Sims/Schwenkbogen).
|
||
|
||
**Generierungs-Signaturen** (jedes Modul exportiert beides):
|
||
```ts
|
||
function build3d(project, el, ctx): THREE.Object3D // Volumen (Schichten/Brep)
|
||
function generatePlan(project, el, ctx, lod): Primitive[] // Schnittflächen + Symbol
|
||
// ctx trägt baseElevation, joins, sichtbare Codes, resolver für Components/Styles
|
||
```
|
||
|
||
---
|
||
|
||
## 1. Wand (Wall) — mehrschichtig
|
||
|
||
### 1.1 Daten
|
||
```ts
|
||
interface Wall extends ElementBase {
|
||
type: "wall";
|
||
start: Vec2; end: Vec2; // Achse (Centerline) im Grundriss [im Spike]
|
||
wallTypeId: string; // → WallType.layers (außen→innen)
|
||
height: number;
|
||
reference: "mid" | "left" | "right"; // Referenzlage der Achse (DOSSIER _wand_referenz)
|
||
baseOffset?: number; // UK relativ zu OKFF (default 0)
|
||
topOffset?: number; // OK-Override (default = floorHeight)
|
||
jointRole?: "auto" | "through" | "butt"; // T-Stoss-Rolle (DOSSIER wand_joint_rolle)
|
||
// Mehrsegment-Wände (Polyline): optional axisPoints statt start/end
|
||
axisPoints?: Vec2[];
|
||
}
|
||
```
|
||
`reference` verschiebt die Achse auf Außenkante/Mitte (DOSSIER
|
||
`_wall_offsets_from_referenz`): hilft beim Modellieren *und* beim Import fremder
|
||
Pläne (ROADMAP §11). Offsets: `mid → [+T/2, -T/2]`, `left → [0, -T]`, `right → [+T, 0]`.
|
||
|
||
### 1.2 Generierung — 3D + Plan (Status: im Spike, einschichtig→mehrschichtig ✅)
|
||
Beide Sichten extrudieren/füllen **dasselbe gehrte Band-Polygon** pro Schicht.
|
||
Heute schon vorhanden:
|
||
- `geometry.clippedBand(start, end, offA, offB, startCut, endCut)` — Band mit
|
||
Gehrungsschnitt.
|
||
- `generatePlan.addWallPoche` — pro Schicht ein gefülltes Polygon (Component-Fill +
|
||
Schraffur), Öffnungen ausgespart.
|
||
- `Viewport3D.addLayerPrism` — dasselbe Polygon via `ExtrudeGeometry`.
|
||
|
||
### 1.3 Wand-Verschneidung (Joins) — Risiko #1
|
||
|
||
**Status: L-Ecken-Gehrung ✅** (`joins.computeJoins` → `miterLine`, robust gegen
|
||
Wicklung + ungleiche Dicken). **Offen: Prioritäts-T-/X-Stöße** bei mehrschichtigen
|
||
Wänden.
|
||
|
||
DOSSIERs gelöste Logik (`elemente._t_junction_layer_overrides`, `_wand_should_apply_t_miter`),
|
||
die wir portieren:
|
||
|
||
1. **Knoten finden:** Endpunkte auf Gitter runden (`roundKey`, existiert),
|
||
gruppieren. `==1` freies Ende, `==2` L-Ecke (Gehrung, ✅), `>2` T/X.
|
||
2. **Through-Wand bestimmen:** an einem T-Stoß läuft genau **eine** Wand durch.
|
||
Auswahl nach `jointRole` (DOSSIER-Regel), sonst nach Component-`joinPriority`:
|
||
```
|
||
my.role="through" → ich laufe durch (kein Miter)
|
||
my.role="butt" → ich stoße an (Miter)
|
||
beide "auto" → höhere joinPriority = Through-Wand
|
||
```
|
||
3. **Schicht-Durchdringung (Backbone):** **nur das Material mit der höchsten
|
||
gemeinsamen `joinPriority`** in *beiden* Wänden läuft durch und unioniert
|
||
(T-Form). Beispiel ROADMAP §2d: Beton (800) läuft mittig durch; Putze (100)
|
||
verbinden sich seitlich, gehen aber nirgends durch den Beton. Alle Nicht-
|
||
Backbone-Schichten der anstoßenden Wand mitern an der Through-Außenkante
|
||
(`standard_miter`). Ergebnis: gleichfarbige Außenlagen bilden automatisch
|
||
saubere L-Stöße.
|
||
|
||
```ts
|
||
// joins.ts — Erweiterung der bestehenden API
|
||
interface WallCuts { startCut: Line|null; endCut: Line|null;
|
||
// neu: pro-Schicht Overrides am T-Stoss
|
||
layerExtensions?: number[]; // wie weit jede Schicht in Through-Body drillt
|
||
layerMiters?: (Line|null)[]; // pro-Schicht Mitre (null = Backbone, läuft durch)
|
||
}
|
||
function computeJoins(project, walls): Map<string, WallCuts> // erweitert
|
||
```
|
||
|
||
**Implementierungsplan (stufenweise, Risiko #1):**
|
||
- (a) ✅ L-Gehrung bleibt.
|
||
- (b) T-Stoß ohne Schichten: Backbone = ganze Wand; Through union, Stem mitert.
|
||
- (c) T-Stoß mit Schichten: Backbone-Material-Logik wie oben (Port von
|
||
`_t_junction_layer_overrides`).
|
||
- (d) X-Stoß: paarweise als zwei T behandeln.
|
||
- **Booleans:** Union/Extension der Backbone-Säule via **OpenCascade.js/Manifold**
|
||
im Worker (`workers/geometry.worker.ts`), nur für 3D + exakten B-Rep-Export; der
|
||
2D-Plan bleibt rein analytisch (Polygon-Clipping, kein Kernel) — schnell.
|
||
- **Validierung:** Screenshot-Probe der T-Ecke (Beton durch, Putz seitlich).
|
||
|
||
### 1.4 Grip-Editing (Risiko #L, Phase 3–4)
|
||
DOSSIER: Display-Conduit zeichnet dicke Marker an Achs-Endpunkten, MouseCallback
|
||
fängt Klick → `GetPoint` mit Snap → `_replace_axis_vertex` → Volumen regeneriert
|
||
(`wand_grips.py`). Browser-Port:
|
||
- **Marker:** SVG-Kreise (r ≈ 7 px) an Endpunkten/Knicks der *selektierten* Wand,
|
||
als Overlay über dem Plan (unabhängig von Ebenen-Sichtbarkeit) — exakt DOSSIERs
|
||
Conduit-Idee.
|
||
- **Hit-Test:** Pointer-Distanz < 14 px (DOSSIER `_HIT_RADIUS_PX`).
|
||
- **Drag:** `pointerdown` auf Marker → Live-Preview-Linien zu Nachbar-Vertices →
|
||
Snap (Endpunkt/Ortho/Raster) → `pointerup` → `store.apply(p => wall.start = newPt)`.
|
||
Abgeleitete Sichten (Plan + 3D) re-derivieren reaktiv — kein manuelles Regen.
|
||
- Funktioniert für Line (2 Grips) und Polyline (jeder Knick ein Grip), wie DOSSIER.
|
||
|
||
---
|
||
|
||
## 2. Öffnungen (Window / Door) — gehostet, LoD
|
||
|
||
### 2.1 Daten
|
||
```ts
|
||
interface OpeningBase extends ElementBase {
|
||
hostWallId: string; // Host-Wand (Geschoss ergibt sich daraus) [im Spike]
|
||
position: number; // Abstand entlang Wandachse vom Wand-Start (m)
|
||
width: number; height: number;
|
||
reference: "mid" | "left" | "right"; // Lage des Klickpunkts in der Öffnung
|
||
detailLevel: DetailLevel | "auto";
|
||
frame?: { width: number; depth: number; pos: "outer"|"mid"|"inner"; offset: number };
|
||
outerSide: "left" | "right"; // welche Wandseite ist außen
|
||
}
|
||
interface Window extends OpeningBase {
|
||
type: "window";
|
||
sill: number; // Brüstungshöhe
|
||
sashes: 1|2|3|4; // Flügelzahl
|
||
sillProfileOut?: "none"|"narrow"|"standard"|"wide"; // Sims außen (DOSSIER _OEFF_SIMS_STYLES)
|
||
sillProfileIn?: "none"|"narrow"|"standard"|"wide";
|
||
glass: boolean;
|
||
}
|
||
interface Door extends OpeningBase {
|
||
type: "door";
|
||
swing: "left" | "right"; // Anschlagseite [im Spike]
|
||
hinge: "start" | "end"; // Scharnierpfosten [im Spike]
|
||
openAngle: number; // Plan-Öffnungswinkel 0–180 (default 90)
|
||
doorType: "normal" | "wall-opening"; // Wandöffnung = ohne Blatt
|
||
frameType: "casing" | "block"; // Zarge | Blockrahmen
|
||
lintel?: "none"|"inner"|"outer"|"both";// Sturzlinien-Anzeige (DOSSIER _OEFF_STURZ)
|
||
}
|
||
```
|
||
Felder 1:1 aus DOSSIERs `_OEFF_*`-Keys + `_OEFF_STYLE_FIELDS`. Presets (Fenster
|
||
Standard/Gross/Bandlage, Tür Innen/Eingang/Verglast, Wandöffnung) als
|
||
Style-Katalog (resources-graphics.md), seed wie `_OEFF_DEFAULT_STYLES`.
|
||
|
||
### 2.2 Host-Beziehung (Risiko #2)
|
||
Die Öffnung kennt ihre Wand (`hostWallId`); ihre Geometrie wird **relativ zur
|
||
Wandachse** berechnet (`opening.axisFrame(wall, position)` → Punkt + Tangente +
|
||
Normale, ≙ DOSSIER `_oeff_axis_frame`). Verschiebt sich die Wand, folgt die
|
||
Öffnung automatisch (sie hält keinen absoluten Punkt). Beim Plan/3D wird die
|
||
Wand an `[position, position+width]` ausgespart — steht im Spike (`addWallPoche`
|
||
Segmentierung, `addWallMeshes` Sturz).
|
||
|
||
### 2.3 Generierung nach LoD
|
||
| LoD | Plan-Symbol | 3D |
|
||
|---|---|---|
|
||
| **coarse** (1:200/500) | Öffnung als Lücke + dünne Linie | Aussparung, kein Rahmen |
|
||
| **medium** (1:100) | + Rahmenlinien, Tür-Schwenkbogen (`addDoorSymbol` ✅), Sturz gestrichelt | Aussparung + einfacher Rahmen-Quader |
|
||
| **fine** (1:50) | + Glas-Doppellinie, Sims, Flügel-Teilung, Anschlag | Rahmen + Blatt + Glas (transparent) + Sims (DOSSIER `_OEFF_PIECE_DEFS`) |
|
||
|
||
- **Tür-Schwenkbogen:** im Spike (`generatePlan.addDoorSymbol` — Blatt + Arc).
|
||
Ausbau: `openAngle`, lichte vs. volle Breite je LoD (Port von
|
||
`_make_tuer_swing_curves`).
|
||
- **3D-Stücke** (Rahmen/Glas/Flügel/Sims/Sturz) ≙ DOSSIER `_make_oeffnung_pieces`
|
||
/ `_OEFF_PIECE_DEFS` — jeweils eigene Component (Farbe + Transparenz: Glas
|
||
α≈0.88, IOR 1.5). Pieces landen auf Unter-Ebenen von `21 Türen/Fenster`.
|
||
|
||
---
|
||
|
||
## 3. Decke / Boden (Slab) — mit Aussparungen
|
||
|
||
### 3.1 Daten
|
||
```ts
|
||
interface Slab extends ElementBase {
|
||
type: "slab";
|
||
boundary: Vec2[]; // geschlossener Umriss (CCW)
|
||
slabTypeId: string; // mehrschichtig (analog WallType)
|
||
openings?: Vec2[][]; // Aussparungen: Treppenauge, Schacht, Kamin (DOSSIER aussp)
|
||
ukOverride?: number; okOverride?: number; // UK/OK statt auto (Abhängung, schräge Brüstung)
|
||
}
|
||
```
|
||
|
||
### 3.2 Generierung
|
||
- **Z-Auflösung:** `okOverride ?? (baseElevation_oberes_Geschoss)`,
|
||
`ukOverride ?? (ok - thickness)` — Port von `_resolve_decke_z`. Decke sitzt
|
||
standardmäßig zwischen zwei Geschossen.
|
||
- **3D:** `boundary` als `THREE.Shape`, Aussparungen als `shape.holes` (`THREE.Path`),
|
||
`ExtrudeGeometry` über die Schichten (≙ `_make_decke_volume(outline, holes)`).
|
||
- **Plan:** im Schnitt unter `cutHeight` meist nur Kante; Aussparungs-Ränder als
|
||
Linien; geschnittene Decke (in Schnitt-Ansicht) bekommt Schraffur.
|
||
- **Aussparung↔Decke:** Aussparung als geschlossene Curve, die räumlich in der
|
||
Decke liegt (`_find_decke_containing_point` / `_find_aussparungen_for_decke`).
|
||
Bei uns: `Slab.openings` direkt im Slab — keine separate Source nötig (einfacher
|
||
als DOSSIERs Parent-Child).
|
||
|
||
---
|
||
|
||
## 4. Treppe (Stair) — Typen, Lauflinie, geschossübergreifend
|
||
|
||
### 4.1 Daten
|
||
```ts
|
||
interface Stair extends ElementBase {
|
||
type: "stair";
|
||
kind: "straight" | "l-shaped" | "spiral"; // gerade | L | Wendel (DOSSIER _TREPPE_ARTEN)
|
||
run: Vec2[]; // Lauflinien-Stützpunkte (gerade: 2; L: 3; Wendel: Zentrum+Start)
|
||
width: number;
|
||
reference: "mid" | "left" | "right"; // Lage der Lauflinie zur Treppe
|
||
steps: number; // Anzahl Steigungen
|
||
mode: "solid" | "flat" | "slab-edge"; // massiv | flach | Plattenrand
|
||
runSlabThickness?: number; // Lauf-Plattendicke
|
||
floorEndId?: string; // Zielgeschoss (geschossübergreifend, Risiko #6)
|
||
heightOverride?: number; ukOverride?: number;
|
||
rules?: { riser:[lo,hi,on]; tread:[lo,hi,on]; stepGo:[lo,hi,on] }; // SIA-Komfortregeln
|
||
lockRiser?: { value: number }; // Schrittmass-Lock (S fix, N passt sich an)
|
||
// Plan-Symbol-Flags (DOSSIER _KEY_TREPPE_SHOW_*)
|
||
show?: { treads; runLine; outline; breakLine };
|
||
upperDashed?: boolean; // obere Stufen gestrichelt (über Schnitthöhe)
|
||
arrowStyle?: "classic"|"filled"|"double"|"line";
|
||
}
|
||
```
|
||
|
||
### 4.2 Generierung
|
||
- **Steigung/Auftritt:** `riser = height/steps`; `tread` aus Lauflinienlänge /
|
||
(steps−1). SIA-Komfort: `2·riser + tread ∈ [0.60, 0.65]` (DOSSIER
|
||
`_TREPPE_SOLL_DEFAULT`). Lock: ist `lockRiser` gesetzt, wird `steps` neu
|
||
berechnet statt `riser` zu ändern.
|
||
- **3D je `kind`:** gerade → Stapel von Tritt-Quadern oder massive Rampe;
|
||
L → zwei Läufe + Podest (`podestMin`); Wendel → um Zentrum rotierte Tritte
|
||
(Port `_make_treppe_*_preview` / Volume-Funktionen). `mode` steuert massiv vs.
|
||
Lauf-Platte.
|
||
- **Geschossübergreifend (Risiko #6):** Höhe = `(baseElevation[floorEndId] -
|
||
baseElevation[floorId])` falls `floorEndId` gesetzt; sonst Geschosshöhe. Treppe
|
||
taucht dann in beiden Geschoss-Grundrissen auf (mit Schnitt an `cutHeight`).
|
||
- **Plan-Symbol (normgerecht):** Lauflinie mit **Auf-/Abpfeil** (`arrowStyle`),
|
||
Stufenkanten, Bruchlinie an `cutHeight` (untere durchgezogen, obere gestrichelt
|
||
via `upperDashed`), Außenkante. ≙ DOSSIERs 2D-Treppensymbol; liegt auf Ebene
|
||
`40 Treppen`/`41 Treppen-2D`.
|
||
|
||
### 4.3 Grip-Editing
|
||
Lauflinien-Stützpunkte als Grips (wie Wand-Vertices, §1.4); Ziehen ändert
|
||
Geometrie + Stufenzahl reaktiv.
|
||
|
||
---
|
||
|
||
## 5. Dach (Roof)
|
||
|
||
### 5.1 Daten
|
||
```ts
|
||
interface Roof extends ElementBase {
|
||
type: "roof";
|
||
outline: Vec2[]; // Grundriss-Umriss
|
||
roofType: "mono" | "gable" | "hip" | "mansard"; // Pult|Sattel|Walm|Mansarde
|
||
thickness: number;
|
||
slope: number; // Grad (Hauptneigung)
|
||
eaveIndex?: number; // Index der Traufkante (Pult)
|
||
ridge?: "long" | "short"; // Firstrichtung (Sattel)
|
||
// Mansarde:
|
||
slopeLower?: number; kinkHeight?: number;
|
||
mansardVariant?: "hip" | "gable" | "hip-gable";
|
||
}
|
||
```
|
||
|
||
### 5.2 Generierung
|
||
Port von DOSSIERs `_make_pultdach/_satteldach/_walmdach/_mansardendach*` +
|
||
`_thicken_roof_inward`. Aufwand M–L (Mansarde später). Reihenfolge: Pult →
|
||
Sattel → Walm → Mansarde. 3D als Brep/Mesh über OpenCascade.js (Worker), da
|
||
Schräg-Verschneidung Booleans braucht. Plan: Firstlinien + Traufe + ggf.
|
||
Höhenkoten.
|
||
|
||
---
|
||
|
||
## 6. Tragwerk (Column / Beam)
|
||
|
||
### 6.1 Daten
|
||
```ts
|
||
interface ProfileDef {
|
||
shape: "square"|"rect"|"round"|"i-beam"|"tube"; // DOSSIER _TRAG_PROFILE
|
||
b?: number; h?: number; d?: number; t?: number; // Breite/Höhe/Durchm./Wanddicke
|
||
angle: number; // Rotation um Z
|
||
}
|
||
interface Column extends ElementBase { type:"column"; point: Vec2; profile: ProfileDef;
|
||
uk?: number; ok?: number; }
|
||
interface Beam extends ElementBase { type:"beam"; axis:[Vec2,Vec2]; profile: ProfileDef;
|
||
zTop?: number; // hängt unter Decken-OK (zTop = ok der Decke)
|
||
}
|
||
```
|
||
|
||
### 6.2 Generierung
|
||
- **Querschnitt:** `profileCurve(shape, b,h,d,t, angle)` (Port `_trag_profile_curve`)
|
||
→ für Stütze entlang Z extrudieren (`_make_stuetze_volume`), für Träger entlang
|
||
der Achse (`_make_traeger_volume`, Profil in der Schnitt-Ebene).
|
||
- **Träger achs-basiert unter Decke:** `zTop` default = OK der darüberliegenden
|
||
Decke → Unterzug folgt automatisch (weniger Update-Fehler, ROADMAP §11).
|
||
- Stützen liegen auf `25 Stützen`, Träger auf `35 Träger`.
|
||
|
||
---
|
||
|
||
## 7. Raum (Space) — SIA-416 + Stempel
|
||
|
||
### 7.1 Daten
|
||
```ts
|
||
interface Space extends ElementBase {
|
||
type: "space";
|
||
boundary: Vec2[]; // geschlossener Umriss
|
||
number?: string; spaceName?: string; function?: string;
|
||
sia?: "" | "HNF"|"NNF"|"VF"|"FF"|"GF"|"AGF"; // SIA-416-Klasse
|
||
persons?: number; // Personenbelegung (Brandschutz)
|
||
areaRounding: "exact"|"0.01"|"0.1"|"0.5"|"1";
|
||
stamp: StampConfig; // Raumstempel-Layout (s.u.)
|
||
fill?: string; // Füll-Hatch-Id (optional)
|
||
}
|
||
interface StampConfig { // ≙ DOSSIER Stempel-Builder
|
||
layout: FieldId[][]; // Zeilen × Felder, z.B. [["number","name"],["function"],["area"]]
|
||
font; bold; italic; textHeight; textMode:"fixed"|"scale"; align:"left"|"mid"|"right";
|
||
offset: Vec2; // Stempel-Position relativ zum Centroid (User-Move)
|
||
}
|
||
type FieldId = "number"|"name"|"function"|"area"|"sia";
|
||
```
|
||
|
||
### 7.2 Generierung & Bilanz
|
||
- **Fläche:** Shoelace-Formel über `boundary`, gerundet nach `areaRounding`
|
||
(`_resolve_raum_rundung`). Umfang analog.
|
||
- **Stempel:** als SVG-Text-Block aus `layout`-Zeilen am Centroid + `offset`
|
||
(User kann verschieben; Offset persistiert wie DOSSIER `stamp_dx/dy`).
|
||
`textMode:"scale"` → Texthöhe in Paper-mm × Massstab (plans-output.md).
|
||
- **SIA-Färbung:** über die **Overrides-Engine** (regelbasiert), nicht hartcodiert
|
||
— DOSSIER `_build_sia_preset_rules` erzeugt 4 Regeln `userString sia == hnf|nnf|vf|ff`
|
||
→ Farbe + Solid-Hatch. Bei uns: ein Override-Preset „SIA-416" (resources-graphics.md),
|
||
das auf `space.sia` matcht. Toggle = Preset aktivieren.
|
||
- **SIA-Bilanz + CSV:** `panels/SiaBalance.tsx` summiert Flächen je Klasse je
|
||
Geschoss → Tabelle + CSV-Export (`HNF/NNF/VF/FF/GF/AGF`). Pflicht für
|
||
CH-Flächennachweis (ROADMAP ⭐).
|
||
|
||
---
|
||
|
||
## 8. Werkzeuge (Tools) — ersetzt Rhino-Command-Aliases
|
||
|
||
DOSSIER hat pro Bauteil ein Command-Alias (`rhino/aliases/cmd/wand.py`, `tuer.py`,
|
||
`treppe.py`, …) das `GetPoint`-Interaktionen fährt. Browser: ein **Tool-Interface**
|
||
mit Pointer-Handlern + Snap.
|
||
|
||
```ts
|
||
interface Tool {
|
||
id: ToolId;
|
||
onPointerDown(pt: Vec2, snap: SnapResult, state): void;
|
||
onPointerMove(pt: Vec2, snap: SnapResult, state): Primitive[]; // Live-Preview
|
||
onPointerUp(pt: Vec2, snap: SnapResult, state): void;
|
||
commit(store): void; // ruft store.apply()
|
||
}
|
||
```
|
||
|
||
| Tool | DOSSIER-Alias | Kurzbeschrieb |
|
||
|---|---|---|
|
||
| `wall` | `cmd/wand` | Achse zeichnen (Linie/Polyline), Dicke/Referenz/Typ aus „last used" |
|
||
| `door`/`window` | `cmd/tuer`,`fenster` | Punkt auf Wandachse → hosten (Snap an Wand) |
|
||
| `slab` | `cmd/decke` | Umriss klicken; Aussparung als Loch |
|
||
| `stair` | `cmd/treppe` | Lauflinie + Breite + Stufen |
|
||
| `roof` | `cmd/dach` | Umriss + Typ + Neigung |
|
||
| `column`/`beam` | `cmd/stuetze`,`traeger` | Punkt / Achse + Profil |
|
||
| `space` | `cmd/raum` | Umriss → Fläche auto, Stempel |
|
||
| `draw2d` | `cmd/symbol`,`stempel` | Linie/Polyline/Rect/Kreis/Bogen/Text auf `60 Plangrafik` |
|
||
| `pipette` | `cmd/pipette` | Stil/Typ von Element übernehmen |
|
||
|
||
**Snap-Engine** (`tools/snap.ts`): Endpunkt, Mitte, Schnitt, senkrecht, Raster,
|
||
Ortho — ersetzt Rhinos OSnap. T-Snap an andere Wandachsen (Port
|
||
`_t_snap_to_wand_axis`, `_snap_endpoint_to_other_wand_axis`) sorgt für saubere
|
||
Knoten.
|
||
|
||
---
|
||
|
||
## 9. Element-Übersicht (BIM-Tree)
|
||
`panels/ElementTree.tsx`: Baum Geschoss → Bauteiltyp → Element, mit Suche und
|
||
Shift-Klick = Zoom (DOSSIER ELEMENTE-ÜBERSICHT). Inhaltsverzeichnis bei 100+
|
||
Elementen — reine Ableitung aus `project.elements`.
|
||
|
||
---
|
||
|
||
## 10. Reihenfolge der Umsetzung (verweist auf ROADMAP-Phasen)
|
||
|
||
1. **Phase 1:** Wand mehrschichtig ✅ + L-Gehrung ✅ → **Prio-T-Stoß** (§1.3);
|
||
Tür/Fenster gehostet (§2); Decke + Aussparung (§3); Wand-Referenzlage (§1.1);
|
||
Element-Übersicht (§9).
|
||
2. **Phase 2:** Treppe (§4), Dach (§5), Tragwerk (§6), SIA-Räume + Stempel (§7),
|
||
Stil-Kataloge.
|
||
3. **Phase 3–4:** Grip-Editing (§1.4/§4.3), exakte B-Rep-Booleans im Worker.
|