Wand-Poché bei "grob" immer vollschwarz (SIA 400 Fig. 36)
Bisher war die Füllung bei Detailgrad "grob" nur schwarz, wenn das dominante Wandbauteil selbst ein "solid"-Hatch-Pattern hatte — bei mehrschichtigen Wandtypen (Backstein/Dämmung/Verputz) blieb sie weiss. SIA 400 kennt bei 1:100 aber keine Materialunterscheidung, die Poché ist immer vollschwarz. Fix + Regressionstest von Hermes/Qwen3 übernommen und um den fehlenden Test sowie das Aufräumen der jetzt toten backbonePocheFill-Hilfsfunktion ergänzt.
This commit is contained in:
+10
-25
@@ -553,11 +553,13 @@ export interface SectionCutStyle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Löst das tragende Bauteil (höchste `joinPriority`) einer Wand auf — dieselbe
|
* Löst das tragende Bauteil (höchste `joinPriority`) einer Wand auf und liefert
|
||||||
* Regel wie {@link backbonePocheFill} für die grobe Grundriss-Poché — und liefert
|
* dessen Poché-Füllung + echte Schraffur für die Schnitt-Poché (mittel/fein).
|
||||||
* dessen Poché-Füllung + echte Schraffur für die Schnitt-Poché. `null`, wenn Wandtyp
|
* Die grobe Grundriss-Poché (1:100) folgt dieser Bauteil-Regel NICHT mehr —
|
||||||
* oder Bauteil nicht auflösbar sind (z. B. verwaistes `wallTypeId`); der
|
* sie ist immer vollschwarz, unabhängig vom Bauteil-Pattern (SIA 400 Fig. 36,
|
||||||
* Aufrufer fällt dann auf die generische Schnitt-Schraffur zurück.
|
* s. `addWallPoche`). `null`, wenn Wandtyp oder Bauteil nicht auflösbar sind
|
||||||
|
* (z. B. verwaistes `wallTypeId`); der Aufrufer fällt dann auf die generische
|
||||||
|
* Schnitt-Schraffur zurück.
|
||||||
*/
|
*/
|
||||||
export function resolveWallSectionStyle(project: Project, wall: Wall): SectionCutStyle | null {
|
export function resolveWallSectionStyle(project: Project, wall: Wall): SectionCutStyle | null {
|
||||||
try {
|
try {
|
||||||
@@ -1565,9 +1567,7 @@ function addWallPoche(
|
|||||||
|
|
||||||
const outlineMm = wallLwMm * OUTLINE_DETAIL_FACTOR[detail];
|
const outlineMm = wallLwMm * OUTLINE_DETAIL_FACTOR[detail];
|
||||||
const layerLineMm = LAYER_LINE_MM * LAYER_DETAIL_FACTOR[detail];
|
const layerLineMm = LAYER_LINE_MM * LAYER_DETAIL_FACTOR[detail];
|
||||||
// Vereinfachte Füllung (grob): neutrale SIA-Poché des tragenden Bauteils
|
// Vereinfachte Füllung (grob): immer schwarze Vollfüllung, keine Schraffur
|
||||||
// (höchste Priorität) — weiß, bzw. schwarz falls dessen Muster "solid" ist.
|
|
||||||
const simpleFill = backbonePocheFill(project, wt);
|
|
||||||
|
|
||||||
// Durchgangswand-Aussparungen (Phase 1c): über diese Achsen-Intervalle × Quer-
|
// Durchgangswand-Aussparungen (Phase 1c): über diese Achsen-Intervalle × Quer-
|
||||||
// Offsetbereiche wird die Nah-Putz-Zone der Durchgangswand echt ausgeschnitten
|
// Offsetbereiche wird die Nah-Putz-Zone der Durchgangswand echt ausgeschnitten
|
||||||
@@ -1617,10 +1617,11 @@ function addWallPoche(
|
|||||||
|
|
||||||
if (detail === "grob") {
|
if (detail === "grob") {
|
||||||
// Eine Sammelfläche über die volle Dicke, ohne Schraffur, dicker Umriss.
|
// Eine Sammelfläche über die volle Dicke, ohne Schraffur, dicker Umriss.
|
||||||
|
// Bei grob: immer Vollschwarz-Füllung gemäß SIA 400 Anhang B.9, Figur 36
|
||||||
out.push({
|
out.push({
|
||||||
kind: "polygon",
|
kind: "polygon",
|
||||||
pts: clippedBand(p1, p2, refOff - total / 2, refOff + total / 2, startCut, endCut),
|
pts: clippedBand(p1, p2, refOff - total / 2, refOff + total / 2, startCut, endCut),
|
||||||
fill: simpleFill,
|
fill: HATCH_INK,
|
||||||
stroke,
|
stroke,
|
||||||
strokeWidthMm: outlineMm,
|
strokeWidthMm: outlineMm,
|
||||||
hatch: NO_HATCH,
|
hatch: NO_HATCH,
|
||||||
@@ -1840,22 +1841,6 @@ function addWallPoche(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Neutrale SIA-Poché-Füllung des tragenden Bauteils (höchste joinPriority) für
|
|
||||||
* die grobe Sammelfläche: Papier, bzw. Tinte falls dessen Schraffur "solid" ist.
|
|
||||||
* (Ersetzt die frühere rohe Bauteil-Albedo — im Plan zählt die Poché, nicht die
|
|
||||||
* 3D-Materialfarbe.)
|
|
||||||
*/
|
|
||||||
function backbonePocheFill(project: Project, wt: Project["wallTypes"][number]): string {
|
|
||||||
let best: { pattern: HatchPattern; prio: number } | null = null;
|
|
||||||
for (const layer of wt.layers) {
|
|
||||||
const comp = getComponent(project, layer.componentId);
|
|
||||||
if (!best || comp.joinPriority > best.prio)
|
|
||||||
best = { pattern: getHatch(project, comp.hatchId).pattern, prio: comp.joinPriority };
|
|
||||||
}
|
|
||||||
return best ? pocheFill(best.pattern) : HATCH_PAPER;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tür-Symbol je Detailgrad:
|
* Tür-Symbol je Detailgrad:
|
||||||
* • grob — nur die gerade Türblatt-Linie (die Öffnungs-Lücke kommt aus der
|
* • grob — nur die gerade Türblatt-Linie (die Öffnungs-Lücke kommt aus der
|
||||||
|
|||||||
@@ -83,6 +83,67 @@ describe("generatePlan — Schnitt vs. Ansicht nach Schnitthöhe", () => {
|
|||||||
|
|
||||||
// ── Decke über der Schnittebene → gestrichelte Überkopf-Umrisslinie ──────────
|
// ── Decke über der Schnittebene → gestrichelte Überkopf-Umrisslinie ──────────
|
||||||
|
|
||||||
|
// ── grob (1:100) → Wand-Poché IMMER vollschwarz (SIA 400 Fig. 36) ──────────
|
||||||
|
|
||||||
|
/** Minimalprojekt mit einer Wand, deren Bauteil ein NICHT-"solid" Hatch-Pattern
|
||||||
|
* hat (Backstein/diagonal — der Normalfall bei mehrschichtigen Wandtypen). */
|
||||||
|
function nonSolidWallProject(): Project {
|
||||||
|
const wall: Wall = {
|
||||||
|
id: "W1",
|
||||||
|
type: "wall",
|
||||||
|
floorId: "eg",
|
||||||
|
categoryCode: "20",
|
||||||
|
start: { x: 0, y: 0 },
|
||||||
|
end: { x: 4, y: 0 },
|
||||||
|
wallTypeId: "aw",
|
||||||
|
height: 2.6,
|
||||||
|
};
|
||||||
|
return {
|
||||||
|
id: "t",
|
||||||
|
name: "T",
|
||||||
|
lineStyles: [{ id: "thin", name: "d", weight: 0.13, color: "#111", dash: null }],
|
||||||
|
hatches: [{ id: "diag", name: "Diagonal", pattern: "diagonal", scale: 1, angle: 45, color: "#111" }],
|
||||||
|
components: [{ id: "brick", name: "Backstein", color: "#c9a876", hatchId: "diag", joinPriority: 10 }],
|
||||||
|
wallTypes: [{ id: "aw", name: "AW", layers: [{ componentId: "brick", thickness: 0.3 }] }],
|
||||||
|
drawingLevels: [
|
||||||
|
{ id: "eg", name: "EG", kind: "floor", visible: true, locked: false, floorHeight: 2.6, cutHeight: 1.0, baseElevation: 0 },
|
||||||
|
],
|
||||||
|
layers: [{ code: "20", name: "Wände", color: "#0a0a0a", lw: 0.5, visible: true, locked: false }],
|
||||||
|
walls: [wall],
|
||||||
|
doors: [],
|
||||||
|
openings: [],
|
||||||
|
ceilings: [],
|
||||||
|
stairs: [],
|
||||||
|
rooms: [],
|
||||||
|
drawings2d: [],
|
||||||
|
context: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("generatePlan — grob: Wand-Poché immer vollschwarz (SIA 400 Fig. 36)", () => {
|
||||||
|
const wallPolys = (plan: ReturnType<typeof generatePlan>, id: string) =>
|
||||||
|
plan.primitives.filter(
|
||||||
|
(p): p is Extract<typeof p, { kind: "polygon" }> => p.kind === "polygon" && p.wallId === id,
|
||||||
|
);
|
||||||
|
|
||||||
|
it("grob: Vollschwarz-Füllung auch wenn das Bauteil-Pattern NICHT 'solid' ist (Regression)", () => {
|
||||||
|
const plan = generatePlan(nonSolidWallProject(), "eg", new Set(["20"]), undefined, "grob");
|
||||||
|
const polys = wallPolys(plan, "W1");
|
||||||
|
expect(polys.length).toBeGreaterThan(0);
|
||||||
|
expect(polys.every((p) => p.fill === "#0f0f0f")).toBe(true);
|
||||||
|
expect(polys.every((p) => p.hatch.pattern === "none")).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("mittel/fein: Füllung bleibt bauteilfarben (KEIN Vollschwarz-Zwang) — unverändertes Verhalten", () => {
|
||||||
|
for (const detail of ["mittel", "fein"] as const) {
|
||||||
|
const plan = generatePlan(nonSolidWallProject(), "eg", new Set(["20"]), undefined, detail);
|
||||||
|
const polys = wallPolys(plan, "W1");
|
||||||
|
expect(polys.length).toBeGreaterThan(0);
|
||||||
|
expect(polys.some((p) => p.fill !== "#0f0f0f")).toBe(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
/** Minimalprojekt mit EINER Decke (Slab) ohne Wände → voller Umriss sichtbar. */
|
/** Minimalprojekt mit EINER Decke (Slab) ohne Wände → voller Umriss sichtbar. */
|
||||||
function ceilingProject(): Project {
|
function ceilingProject(): Project {
|
||||||
return {
|
return {
|
||||||
|
|||||||
Reference in New Issue
Block a user