Files
DOSSIER-STANDALONE/src/model/wall.ts
T
karim 35299307d6 Akkumulierten grünen Arbeitsstand landen (Basis für Weiterarbeit)
Bündelt den über mehrere Sessions gewachsenen, uncommitteten Stand in
einem Basis-Commit, damit Folge-Features isoliert darauf aufsetzen.
Verifikation: tsc --noEmit sauber, vitest 600/600 grün.

Enthalten (Details in PENDENZEN.md -Liste / HANDOVER.md):
- truck-Integration: Profil-Extrusion + Verjüngung + Boolean-CSG (csgrs),
  Crate src-tauri/trucksolid, Werkzeug `extrude`, ExtrudedSolid-Modell.
- kernel2d-Port nach Rust/WASM (Phasen 1–5, Diff-Harness).
- render3d 3D-Live-Schnitt = 2D-Schnitt: geschichteter Bodenaufbau,
  Prioritäts-Verschneidung (section_boolean.rs), einstellbare
  Schichttrennlinien, per-Hatch-Strichstärke, relativeToWall-Orientierung.
- Interop-Export IFC4/STL/OBJ (Loch-Ausschnitt wallMeshCut), Schnellexport.
- Projektdatei .obp + OS-Lock (lock.rs, LockConflictDialog).
- Layout-Blätter (Modell/Editor/Panel/PDF), Ausschnitte, Override-Engine,
  Tragwerk-Stützen (Column), BIM-Tree-Panel.
- Bauteil-Typsystem (Tür/Fenster/Treppe-Typen), Betontreppe mit schräger
  Laufplatte, Text-/Textbox-Werkzeug, Mess-Werkzeug, 2D/3D-Griffe für
  Öffnungen/Treppen, Snap-Symbol-Restyle.
2026-07-09 00:57:29 +02:00

168 lines
6.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Wand-Resolver: leitet aus den (optionalen) Wand-Attributen die konkreten
// geometrischen Größen ab — Versatz der Achse über die Dicke (Referenzlinie)
// und die vertikale Ausdehnung (UK..OK). Alle Defaults entsprechen exakt dem
// bisherigen Verhalten, sodass bestehende Wände unverändert rendern.
//
// Bezeichner englisch, Kommentare deutsch (CONVENTIONS.md).
import type { Ceiling, Column, Project, Stair, VerticalAnchor, Wall } from "./types";
import { ceilingThickness, getFloor } from "./types";
/**
* Versatz der Schichtstapelung entlang der linken Normalen `+n` (leftNormal),
* sodass die Achse auf der gewünschten Wandfläche liegt. Die Schichten werden
* normalerweise symmetrisch von `T/2` (außen, +n-Seite) bis `+T/2` (innen)
* gestapelt; dieser Versatz wird ZUSÄTZLICH auf jeden Schicht-Offset addiert.
*
* • "center" → 0 (Schichten symmetrisch um die Achse — Default).
* • "left" → +T/2 (Achse auf der +n-/„außen"-Fläche; Wand liegt auf n).
* • "right" → T/2 (Achse auf der n-/„innen"-Fläche; Wand liegt auf +n).
*
* Die Schicht-Offsets laufen von T/2 (= +n außen) nach +T/2 (= n innen).
* Für "left" soll die T/2-Kante (außen) auf der Achse liegen → +T/2 addieren,
* sodass die Schichten von 0…T (alle auf der n-Seite) liegen.
*/
export function wallReferenceOffset(
wall: Wall,
totalThickness: number,
): number {
const ref = wall.referenceLine ?? "center";
const half = totalThickness / 2;
if (ref === "left") return +half;
if (ref === "right") return -half;
return 0;
}
/** Löst einen VerticalAnchor zu einem absoluten Z (Meter) auf oder `null`. */
function resolveAnchor(
project: Project,
anchor: VerticalAnchor | undefined,
): number | null {
if (!anchor) return null;
if (anchor.mode === "custom") return anchor.z;
// "floor": baseElevation des gebundenen Geschosses (+ optionalem Offset).
const floor = project.drawingLevels.find((z) => z.id === anchor.floorId);
if (!floor) return null;
return (floor.baseElevation ?? 0) + (anchor.offset ?? 0);
}
/**
* Vertikale Ausdehnung der Wand (absolute Z-Werte in Metern).
* • zBottom: aus `wall.bottom`, sonst baseElevation des Wand-Geschosses
* (= heutiges Verhalten).
* • zTop: aus `wall.top`, sonst `zBottom + wall.height` (= heute).
* Sind beide UK/OK ungesetzt, liefert dies exakt `[baseElevation, base+height]`.
*/
export function wallVerticalExtent(
project: Project,
wall: Wall,
): { zBottom: number; zTop: number } {
// Geschoss-baseElevation als Default-UK (heutiges Verhalten). Fehlt das
// Geschoss, 0 als sicherer Rückfall.
let floorBase = 0;
try {
floorBase = getFloor(project, wall.floorId).baseElevation ?? 0;
} catch {
floorBase = 0;
}
const zBottom = resolveAnchor(project, wall.bottom) ?? floorBase;
const zTop = resolveAnchor(project, wall.top) ?? zBottom + wall.height;
return { zBottom, zTop };
}
/**
* Vertikale Ausdehnung einer Decke (absolute Z-Werte in Metern).
* • zTop: aus `ceiling.top`, sonst Oberkante des Geschosses
* (baseElevation + floorHeight) — also bündig mit dem Wandkopf.
* • zBottom: aus `ceiling.bottom`, sonst zTop Deckendicke (die Decke
* wächst nach UNTEN — heutiges Verhalten). Die `thickness` bleibt bei
* gesetztem `bottom` rein informativ (dient nicht mehr der UK-Ableitung).
* Fehlt das Geschoss, dient 0 als sicherer Rückfall für die Oberkante.
*/
export function ceilingVerticalExtent(
project: Project,
ceiling: Ceiling,
): { zBottom: number; zTop: number } {
let floorTop = 0;
try {
const floor = getFloor(project, ceiling.floorId);
floorTop = (floor.baseElevation ?? 0) + (floor.floorHeight ?? 0);
} catch {
floorTop = 0;
}
const zTop = resolveAnchor(project, ceiling.top) ?? floorTop;
const zBottom =
resolveAnchor(project, ceiling.bottom) ??
zTop - ceilingThickness(project, ceiling);
return { zBottom, zTop };
}
/**
* Vertikale Ausdehnung einer Treppe (absolute Z-Werte in Metern).
* • zBottom: OKFF (baseElevation) des zugehörigen Geschosses.
* • zTop: zBottom + Gesamt-Steighöhe. Fehlt `stair.totalRise`, gilt die
* Geschosshöhe (floorHeight) des Geschosses — so steigt die Treppe genau ins
* nächste Geschoss (OKFF → OKFF).
* Fehlt das Geschoss, dient 0 als sicherer Rückfall für die Unterkante.
*/
export function stairVerticalExtent(
project: Project,
stair: Stair,
): { zBottom: number; zTop: number } {
let base = 0;
let floorHeight = 0;
try {
const floor = getFloor(project, stair.floorId);
base = floor.baseElevation ?? 0;
floorHeight = floor.floorHeight ?? 0;
} catch {
base = 0;
floorHeight = 0;
}
const rise =
stair.totalRise != null && stair.totalRise > 0
? stair.totalRise
: floorHeight > 0
? floorHeight
: 2.6;
return { zBottom: base, zTop: base + rise };
}
/**
* Vertikale Ausdehnung einer Stütze (absolute Z-Werte in Metern) — dieselbe
* Regel wie {@link wallVerticalExtent}:
* • zBottom: aus `column.bottom`, sonst baseElevation des Geschosses.
* • zTop: aus `column.top`, sonst `zBottom + column.height`.
* Fehlt das Geschoss, dient 0 als sicherer Rückfall für die Unterkante.
*/
export function columnVerticalExtent(
project: Project,
column: Column,
): { zBottom: number; zTop: number } {
let floorBase = 0;
try {
floorBase = getFloor(project, column.floorId).baseElevation ?? 0;
} catch {
floorBase = 0;
}
const zBottom = resolveAnchor(project, column.bottom) ?? floorBase;
const zTop = resolveAnchor(project, column.top) ?? zBottom + column.height;
return { zBottom, zTop };
}
/**
* Das Geschoss DIREKT ÜBER dem Wand-Geschoss (in Dokumentreihenfolge der
* "floor"-Ebenen) oder `undefined`, wenn die Wand im obersten Geschoss liegt.
* Dient der „Verknüpfung zum oberen Geschoss" (OK an nächstes Geschoss binden).
*/
export function nextFloorAbove(
project: Project,
wall: Wall,
): { id: string; name: string } | undefined {
const floors = project.drawingLevels.filter((z) => z.kind === "floor");
const idx = floors.findIndex((z) => z.id === wall.floorId);
if (idx < 0) return undefined;
const above = floors[idx + 1];
return above ? { id: above.id, name: above.name } : undefined;
}