Files
DOSSIER-STANDALONE/src/model/wall.test.ts
T
karim 938d6421f9 Schichttrennlinie als Wand-Referenzlinie (mehrschichtige Wände)
Bei mehrschichtigen Wänden lässt sich neben Aussen/Mitte/Innen jetzt auch
eine SCHICHTTRENNLINIE (Fuge zwischen zwei Schichten) als Referenzlinie
wählen — z. B. die Achse auf die Innenkante der Aussenschale legen.
- Neues Feld Wall.referenceOffset (freier Achsversatz entlang +n); wenn
  gesetzt, übersteuert es referenceLine. wallReferenceOffset bleibt die
  EINE Quelle → Grundriss, Schnitt und 3D erben das Verhalten automatisch.
- Object-Info-Panel: das Referenzlinien-Dropdown listet zusätzlich je
  interne Fuge einen Eintrag (Kürzel der angrenzenden Schichten); Auswahl
  setzt den Versatz, Aussen/Mitte/Innen löscht ihn wieder.
- selectionInfo berechnet die Fugen-Versätze (kumulierte Schichtdicken).
+3 Tests. tsc + vitest grün.
2026-07-09 01:21:28 +02:00

137 lines
4.7 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.
// Unit-Tests für die Wand-/Decken-Resolver (wallVerticalExtent /
// ceilingVerticalExtent): reine Datenschicht, kein React/Store.
import { describe, it, expect } from "vitest";
import { ceilingVerticalExtent, wallReferenceOffset } from "./wall";
import type { Ceiling, Project, Wall } from "./types";
/** Minimalprojekt mit einem Geschoss (baseElevation 0, floorHeight 2.6) und
* einem einschichtigen Wandtyp (0.2 m), den die Decke als Aufbau nutzt. */
function makeProject(overrides?: Partial<Project>): Project {
return {
id: "t",
name: "T",
lineStyles: [],
hatches: [],
components: [{ id: "c", name: "C", color: "#ccc", hatchId: "none", joinPriority: 10 }],
wallTypes: [
{ id: "dt", name: "Decke", layers: [{ componentId: "c", thickness: 0.2 }] },
],
drawingLevels: [
{
id: "eg",
name: "EG",
kind: "floor",
visible: true,
locked: false,
floorHeight: 2.6,
cutHeight: 1.0,
baseElevation: 0,
},
{
id: "og",
name: "OG",
kind: "floor",
visible: true,
locked: false,
floorHeight: 2.6,
cutHeight: 1.0,
baseElevation: 2.8,
},
],
layers: [{ code: "30", name: "Decken", color: "#0a0a0a", lw: 0.5, visible: true, locked: false }],
walls: [],
doors: [],
openings: [],
ceilings: [],
stairs: [],
rooms: [],
drawings2d: [],
context: [],
...overrides,
};
}
function makeCeiling(overrides?: Partial<Ceiling>): Ceiling {
return {
id: "cl1",
type: "ceiling",
floorId: "eg",
categoryCode: "30",
outline: [
{ x: 0, y: 0 },
{ x: 4, y: 0 },
{ x: 4, y: 4 },
{ x: 0, y: 4 },
],
wallTypeId: "dt",
...overrides,
};
}
describe("ceilingVerticalExtent", () => {
it("ohne top/bottom: OK = Geschoss-Oberkante, UK = OK − Dicke (heutiges Verhalten)", () => {
const project = makeProject();
const ceiling = makeCeiling();
const { zBottom, zTop } = ceilingVerticalExtent(project, ceiling);
expect(zTop).toBeCloseTo(2.6); // baseElevation(0) + floorHeight(2.6)
expect(zBottom).toBeCloseTo(2.4); // zTop − thickness(0.2)
});
it("mit top: custom übersteuert die Oberkante; UK bleibt OK − Dicke", () => {
const project = makeProject();
const ceiling = makeCeiling({ top: { mode: "custom", z: 3.0 } });
const { zBottom, zTop } = ceilingVerticalExtent(project, ceiling);
expect(zTop).toBeCloseTo(3.0);
expect(zBottom).toBeCloseTo(2.8);
});
it("mit bottom: custom übersteuert die Unterkante — gewinnt über OK − Dicke", () => {
const project = makeProject();
const ceiling = makeCeiling({ bottom: { mode: "custom", z: 2.2 } });
const { zBottom, zTop } = ceilingVerticalExtent(project, ceiling);
expect(zTop).toBeCloseTo(2.6); // OK unverändert (Geschoss-Default)
expect(zBottom).toBeCloseTo(2.2); // UK-Override statt OK − Dicke (2.4)
});
it("mit top UND bottom: beide Overrides wirken unabhängig (Dicke wird ignoriert)", () => {
const project = makeProject();
const ceiling = makeCeiling({
top: { mode: "custom", z: 5.0 },
bottom: { mode: "custom", z: 4.5 },
});
const { zBottom, zTop } = ceilingVerticalExtent(project, ceiling);
expect(zTop).toBeCloseTo(5.0);
expect(zBottom).toBeCloseTo(4.5);
});
it("bottom: floor bindet die Unterkante an ein Geschoss (+ optionalem offset)", () => {
const project = makeProject();
const ceiling = makeCeiling({ bottom: { mode: "floor", floorId: "og", offset: 0.1 } });
const { zBottom, zTop } = ceilingVerticalExtent(project, ceiling);
expect(zTop).toBeCloseTo(2.6);
expect(zBottom).toBeCloseTo(2.9); // baseElevation(og)=2.8 + offset(0.1)
});
});
describe("wallReferenceOffset", () => {
const w = (extra: Partial<Wall>): Wall => ({ referenceLine: "center", ...extra } as Wall);
const T = 0.4; // Gesamtdicke → half = 0.2
it("bildet die benannten Linien ab (aussen/mitte/innen)", () => {
expect(wallReferenceOffset(w({ referenceLine: "left" }), T)).toBeCloseTo(0.2, 6);
expect(wallReferenceOffset(w({ referenceLine: "center" }), T)).toBeCloseTo(0, 6);
expect(wallReferenceOffset(w({ referenceLine: "right" }), T)).toBeCloseTo(-0.2, 6);
});
it("übersteuert die Referenzlinie mit einem freien Fugen-Versatz", () => {
// Fuge z. B. nach einer 0.05-Aussenschale: offset = half − 0.05 = 0.15.
expect(wallReferenceOffset(w({ referenceLine: "left", referenceOffset: 0.15 }), T)).toBeCloseTo(0.15, 6);
});
it("klemmt den Fugen-Versatz auf ±halbe Dicke", () => {
expect(wallReferenceOffset(w({ referenceOffset: 5 }), T)).toBeCloseTo(0.2, 6);
expect(wallReferenceOffset(w({ referenceOffset: -5 }), T)).toBeCloseTo(-0.2, 6);
});
});