Schiebefenster-Öffnungssymbol (DIN-Pfeil) in Ansicht und 3D
Schiebeflügel hatten bisher kein Öffnungssymbol (nur Dreh/Kipp/Drehkipp). DIN zeichnet für Schiebeelemente keinen Anschlag-Winkel, sondern einen Pfeil in Laufrichtung — ergänzt in der 2D-Ansicht (toElevation) und im 3D-fein (toWalls3d), Richtung aus der Griffseite. Test deckt Schiebe/Fest/Drehkipp ab.
This commit is contained in:
@@ -353,6 +353,51 @@ describe("toElevation — Öffnungen: Verdeckung + Reveal-Schatten", () => {
|
|||||||
expect(symbols.length).toBeGreaterThan(0);
|
expect(symbols.length).toBeGreaterThan(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("Öffnungssymbolik je Art: Schiebe=Pfeil (3 Linien), Fest=keine, Drehkipp=4", () => {
|
||||||
|
const base = elevationProject({ overhang: false });
|
||||||
|
const mkProject = (kind: "schiebe" | "fest" | "drehkipp"): Project =>
|
||||||
|
({
|
||||||
|
...base,
|
||||||
|
windowTypes: [
|
||||||
|
{
|
||||||
|
id: "wt",
|
||||||
|
name: "F",
|
||||||
|
kind,
|
||||||
|
wingCount: 1,
|
||||||
|
glazing: "zweifach",
|
||||||
|
frameWidth: 0.06,
|
||||||
|
defaultSillHeight: 0.9,
|
||||||
|
defaultWidth: 1,
|
||||||
|
defaultHeight: 1.2,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
openings: [
|
||||||
|
{
|
||||||
|
id: "op",
|
||||||
|
type: "opening",
|
||||||
|
hostWallId: "NEAR",
|
||||||
|
categoryCode: "21",
|
||||||
|
kind: "window",
|
||||||
|
typeId: "wt",
|
||||||
|
position: 1.5,
|
||||||
|
width: 1,
|
||||||
|
height: 1.2,
|
||||||
|
sillHeight: 0.9,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}) as unknown as Project;
|
||||||
|
const symCount = (kind: "schiebe" | "fest" | "drehkipp"): number => {
|
||||||
|
const p = mkProject(kind);
|
||||||
|
const plan = generateElevationPlan(p, p.drawingLevels[1])!;
|
||||||
|
return plan.primitives.filter(
|
||||||
|
(pr) => pr.kind === "line" && (pr as { cls?: string }).cls === "elevation-opening-symbol",
|
||||||
|
).length;
|
||||||
|
};
|
||||||
|
expect(symCount("schiebe")).toBe(3); // Pfeil: Schaft + 2 Spitzen
|
||||||
|
expect(symCount("fest")).toBe(0); // Festverglasung ohne Symbol
|
||||||
|
expect(symCount("drehkipp")).toBe(4); // Dreh (2) + Kipp (2)
|
||||||
|
});
|
||||||
|
|
||||||
it("Reveal-Schatten: shadows=true erzeugt Öffnungs-Schattenbänder, false keine", () => {
|
it("Reveal-Schatten: shadows=true erzeugt Öffnungs-Schattenbänder, false keine", () => {
|
||||||
const project = openingProject();
|
const project = openingProject();
|
||||||
const level = project.drawingLevels[1];
|
const level = project.drawingLevels[1];
|
||||||
|
|||||||
@@ -799,6 +799,22 @@ function collectOpenings(project: Project, frame: ElevationFrame): ProjectedOpen
|
|||||||
[quadAt(pr.pts, gB, gz0), apex],
|
[quadAt(pr.pts, gB, gz0), apex],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if (kind === "schiebe") {
|
||||||
|
// Schiebeflügel: KEIN Dreieck (keine Bandseite), sondern ein Pfeil in
|
||||||
|
// Laufrichtung (horizontal) auf halber Glashöhe — die Griffseite
|
||||||
|
// (hingeSide) bestimmt die Pfeilrichtung. Klassische DIN-Konvention.
|
||||||
|
const zc = (gz0 + gz1) / 2;
|
||||||
|
const toRight = (sd.hingeSide ?? "left") === "left"; // Griff links ⇒ schiebt nach rechts
|
||||||
|
const tail = toRight ? gA : gB;
|
||||||
|
const head = toRight ? gB : gA;
|
||||||
|
const barb = (head - tail) * 0.22; // Pfeilspitzen-Rücksprung (Glasbreite-Anteil)
|
||||||
|
const headPt = quadAt(pr.pts, head, zc);
|
||||||
|
pr.symbol.push(
|
||||||
|
[quadAt(pr.pts, tail, zc), headPt], // Schaft
|
||||||
|
[quadAt(pr.pts, head - barb, gz0 + (gz1 - gz0) * 0.32), headPt], // obere Spitze
|
||||||
|
[quadAt(pr.pts, head - barb, gz0 + (gz1 - gz0) * 0.68), headPt], // untere Spitze
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Fensterbank (Sims, VW): Bank + Tropfkante als zwei Bänder unter dem
|
// Fensterbank (Sims, VW): Bank + Tropfkante als zwei Bänder unter dem
|
||||||
// Rahmen, seitlich leicht überstehend. Default AN (sillBoard fehlt),
|
// Rahmen, seitlich leicht überstehend. Default AN (sillBoard fehlt),
|
||||||
|
|||||||
@@ -2298,6 +2298,17 @@ function frameMeshesForOpening(
|
|||||||
pushSymbol(gA, gbz, apexU, gtz);
|
pushSymbol(gA, gbz, apexU, gtz);
|
||||||
pushSymbol(gB, gbz, apexU, gtz);
|
pushSymbol(gB, gbz, apexU, gtz);
|
||||||
}
|
}
|
||||||
|
if (kind === "schiebe") {
|
||||||
|
// Schiebe: horizontaler Pfeil in Laufrichtung (Griff links ⇒ nach rechts).
|
||||||
|
const zc = (gbz + gtz) / 2;
|
||||||
|
const toRight = (s.hingeSide ?? "left") === "left";
|
||||||
|
const tail = toRight ? gA : gB;
|
||||||
|
const head = toRight ? gB : gA;
|
||||||
|
const barb = (head - tail) * 0.22;
|
||||||
|
pushSymbol(tail, zc, head, zc); // Schaft
|
||||||
|
pushSymbol(head - barb, gbz + (gtz - gbz) * 0.32, head, zc); // obere Spitze
|
||||||
|
pushSymbol(head - barb, gbz + (gtz - gbz) * 0.68, head, zc); // untere Spitze
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user