Schnittlinien-Werkzeug: Befehl sectionline/viewline setzt linePoints
Zwei Klicks (Start -> Ende) legen die Grundriss-Schnitt-/Ansichtslinie einer DrawingLevel fest. Ziel: genau eine Platzhalter-Ebene ohne Linie wird belegt, sonst neue Ebene (Schnitt B/C ...). Live-Vorschau mit Richtungspfeil, Art (Schnitt/Ansicht) als Inline-Option umschaltbar. Registry-Aliase schnittlinie/ ansichtslinie, Ribbon-Gruppe 'Schnitte' im BIM-Tab, i18n de/en, Datenpfad-Tests.
This commit is contained in:
@@ -0,0 +1,100 @@
|
|||||||
|
// Schnittlinien-Befehl: der reine Datenpfad (commitLine/nextLevelName) — setzt
|
||||||
|
// die Grundriss-Schnittlinie auf die richtige Ziel-Ebene bzw. legt eine neue an.
|
||||||
|
|
||||||
|
import { describe, it, expect } from "vitest";
|
||||||
|
import { _test } from "./sectionline";
|
||||||
|
import type { DrawingLevel, Project } from "../../model/types";
|
||||||
|
|
||||||
|
const { commitLine, nextLevelName } = _test;
|
||||||
|
|
||||||
|
function projectWith(levels: DrawingLevel[]): Project {
|
||||||
|
return {
|
||||||
|
id: "p",
|
||||||
|
name: "T",
|
||||||
|
layers: [],
|
||||||
|
drawingLevels: levels,
|
||||||
|
walls: [],
|
||||||
|
drawings2d: [],
|
||||||
|
} as unknown as Project;
|
||||||
|
}
|
||||||
|
|
||||||
|
const a = { x: 0, y: 0 };
|
||||||
|
const b = { x: 5, y: 0 };
|
||||||
|
|
||||||
|
describe("sectionline — commitLine", () => {
|
||||||
|
it("belegt die EINE Platzhalter-Schnittebene ohne Linie", () => {
|
||||||
|
const p = projectWith([
|
||||||
|
{ id: "eg", name: "EG", kind: "floor", visible: true, locked: false },
|
||||||
|
{ id: "s1", name: "Schnitt A", kind: "section", visible: true, locked: false },
|
||||||
|
]);
|
||||||
|
const out = commitLine(p, a, b, "section");
|
||||||
|
const s = out.drawingLevels.find((z) => z.id === "s1")!;
|
||||||
|
expect(s.linePoints).toEqual([a, b]);
|
||||||
|
expect(s.directionSign).toBe(1);
|
||||||
|
// Keine neue Ebene angelegt.
|
||||||
|
expect(out.drawingLevels).toHaveLength(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("legt eine NEUE Schnittebene an, wenn keine Platzhalter-Ebene existiert", () => {
|
||||||
|
const p = projectWith([
|
||||||
|
{ id: "eg", name: "EG", kind: "floor", visible: true, locked: false },
|
||||||
|
{
|
||||||
|
id: "s1",
|
||||||
|
name: "Schnitt A",
|
||||||
|
kind: "section",
|
||||||
|
visible: true,
|
||||||
|
locked: false,
|
||||||
|
linePoints: [{ x: 1, y: 1 }, { x: 2, y: 2 }],
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
const out = commitLine(p, a, b, "section");
|
||||||
|
expect(out.drawingLevels).toHaveLength(3);
|
||||||
|
const created = out.drawingLevels[out.drawingLevels.length - 1];
|
||||||
|
expect(created.kind).toBe("section");
|
||||||
|
expect(created.linePoints).toEqual([a, b]);
|
||||||
|
// Zweite Ebene → Buchstabe B.
|
||||||
|
expect(created.name).toContain("B");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("legt bei ZWEI Platzhaltern (mehrdeutig) eine neue Ebene an", () => {
|
||||||
|
const p = projectWith([
|
||||||
|
{ id: "s1", name: "Schnitt A", kind: "section", visible: true, locked: false },
|
||||||
|
{ id: "s2", name: "Schnitt B", kind: "section", visible: true, locked: false },
|
||||||
|
]);
|
||||||
|
const out = commitLine(p, a, b, "section");
|
||||||
|
expect(out.drawingLevels).toHaveLength(3);
|
||||||
|
// Die bestehenden Platzhalter bleiben unangetastet.
|
||||||
|
expect(out.drawingLevels[0].linePoints).toBeUndefined();
|
||||||
|
expect(out.drawingLevels[1].linePoints).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("verwirft entartete (zu kurze) Linien", () => {
|
||||||
|
const p = projectWith([
|
||||||
|
{ id: "s1", name: "Schnitt A", kind: "section", visible: true, locked: false },
|
||||||
|
]);
|
||||||
|
const out = commitLine(p, a, { x: 0.02, y: 0 }, "section");
|
||||||
|
expect(out).toBe(p);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("trennt Schnitt- und Ansichts-Ebenen (kind)", () => {
|
||||||
|
const p = projectWith([
|
||||||
|
{ id: "s1", name: "Schnitt A", kind: "section", visible: true, locked: false },
|
||||||
|
]);
|
||||||
|
// Ansichtslinie darf die Schnitt-Platzhalter-Ebene NICHT belegen.
|
||||||
|
const out = commitLine(p, a, b, "elevation");
|
||||||
|
expect(out.drawingLevels).toHaveLength(2);
|
||||||
|
expect(out.drawingLevels[0].linePoints).toBeUndefined();
|
||||||
|
expect(out.drawingLevels[1].kind).toBe("elevation");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("sectionline — nextLevelName", () => {
|
||||||
|
it("zählt Buchstaben je Art hoch (A, B, C …)", () => {
|
||||||
|
const p0 = projectWith([]);
|
||||||
|
expect(nextLevelName(p0, "section")).toContain("A");
|
||||||
|
const p1 = projectWith([
|
||||||
|
{ id: "s1", name: "Schnitt A", kind: "section", visible: true, locked: false },
|
||||||
|
]);
|
||||||
|
expect(nextLevelName(p1, "section")).toContain("B");
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,213 @@
|
|||||||
|
// Schnittlinie — setzt die Grundriss-Schnitt-/Ansichtslinie einer Zeichnungsebene
|
||||||
|
// (DrawingLevel, kind "section"/"elevation") per zwei Klicks (Start → Ende). Die
|
||||||
|
// Linie steuert `sectionPlaneFromLevel` (plan/toSection.ts): senkrecht auf ihr
|
||||||
|
// steht die Blickrichtung (directionSign, Voreinstellung +1).
|
||||||
|
//
|
||||||
|
// Schritte:
|
||||||
|
// 1) „Schnitt-Startpunkt:" → Punkt
|
||||||
|
// 2) „Schnitt-Endpunkt:" → Live-Linie + Richtungspfeil; Klick committet.
|
||||||
|
//
|
||||||
|
// Ziel-Ebene (im Commit bestimmt): existiert GENAU EINE Ebene der gewählten Art
|
||||||
|
// OHNE gesetzte Linie (frisch angelegter Platzhalter), wird deren Linie gesetzt;
|
||||||
|
// sonst wird eine NEUE Ebene angelegt (Name „Schnitt B/C…" bzw. „Ansicht …").
|
||||||
|
//
|
||||||
|
// Die Art (Schnitt/Ansicht) ist als Inline-Option umschaltbar — dieselbe Mechanik
|
||||||
|
// für beide, nur `kind` unterscheidet sich (Alias `viewline` startet mit
|
||||||
|
// „elevation"). Bezeichner englisch, sichtbarer Text via t().
|
||||||
|
|
||||||
|
import { t } from "../../i18n";
|
||||||
|
import type { DrawingLevel, DrawingLevelKind } from "../../model/types";
|
||||||
|
import { leftNormal, normalize, sub } from "../../model/geometry";
|
||||||
|
import type {
|
||||||
|
Command,
|
||||||
|
CommandResult,
|
||||||
|
CommandState,
|
||||||
|
CmdOption,
|
||||||
|
DraftShape,
|
||||||
|
Project,
|
||||||
|
ToolDraft,
|
||||||
|
Vec2,
|
||||||
|
} from "../types";
|
||||||
|
|
||||||
|
/** Nur Schnitt/Ansicht tragen eine Linie. */
|
||||||
|
type LineKind = "section" | "elevation";
|
||||||
|
|
||||||
|
/** Wählbare Art (Inline-Optionen der Befehlszeile). */
|
||||||
|
const KIND_OPTIONS: CmdOption[] = [
|
||||||
|
{ id: "section", labelKey: "cmd.sectionline.kind.section" },
|
||||||
|
{ id: "elevation", labelKey: "cmd.sectionline.kind.elevation" },
|
||||||
|
];
|
||||||
|
const KIND_IDS = new Set(KIND_OPTIONS.map((o) => o.id));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Richtungspfeil-Vorschau: kurze Linie vom Mittelpunkt der Schnittlinie entlang
|
||||||
|
* der Blicknormalen (leftNormal der Linie, per directionSign gedreht) plus zwei
|
||||||
|
* Flügel-Segmente — zeigt, wohin der Schnitt „blickt".
|
||||||
|
*/
|
||||||
|
function directionArrow(a: Vec2, b: Vec2, sign: 1 | -1): DraftShape[] {
|
||||||
|
const dir = sub(b, a);
|
||||||
|
const len = Math.hypot(dir.x, dir.y);
|
||||||
|
if (len < 1e-6) return [];
|
||||||
|
const u = normalize(dir);
|
||||||
|
const n = leftNormal(u); // (-uy, ux)
|
||||||
|
const nx = n.x * sign;
|
||||||
|
const ny = n.y * sign;
|
||||||
|
const mid = { x: (a.x + b.x) / 2, y: (a.y + b.y) / 2 };
|
||||||
|
// Pfeillänge ~ min(1 m, Viertel der Linienlänge), damit die Vorschau lesbar bleibt.
|
||||||
|
const arrowLen = Math.min(1, len / 4);
|
||||||
|
const tip = { x: mid.x + nx * arrowLen, y: mid.y + ny * arrowLen };
|
||||||
|
const wing = arrowLen * 0.35;
|
||||||
|
// Flügel: vom Spitzenpunkt zurück, je halb entlang −u und +u geneigt.
|
||||||
|
const back = { x: tip.x - nx * wing * 2, y: tip.y - ny * wing * 2 };
|
||||||
|
const w1 = { x: back.x + u.x * wing, y: back.y + u.y * wing };
|
||||||
|
const w2 = { x: back.x - u.x * wing, y: back.y - u.y * wing };
|
||||||
|
return [
|
||||||
|
{ kind: "line", a: mid, b: tip },
|
||||||
|
{ kind: "line", a: tip, b: w1 },
|
||||||
|
{ kind: "line", a: tip, b: w2 },
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Vorschau: Schnittlinie + Richtungspfeil + Länge im HUD. */
|
||||||
|
function lineDraft(a: Vec2, cursor: Vec2 | null, sign: 1 | -1): ToolDraft {
|
||||||
|
if (!cursor) return { preview: [{ kind: "poly", pts: [a] }], vertices: [a] };
|
||||||
|
const preview: DraftShape[] = [
|
||||||
|
{ kind: "line", a, b: cursor },
|
||||||
|
...directionArrow(a, cursor, sign),
|
||||||
|
];
|
||||||
|
const draft: ToolDraft = { preview, vertices: [a] };
|
||||||
|
draft.hud = {
|
||||||
|
at: cursor,
|
||||||
|
text: `${Math.hypot(cursor.x - a.x, cursor.y - a.y).toFixed(2)} m`,
|
||||||
|
};
|
||||||
|
return draft;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Nächster freier Ebenen-Name der Art (A, B, C … über die Anzahl bestehender). */
|
||||||
|
function nextLevelName(p: Project, kind: LineKind): string {
|
||||||
|
const count = p.drawingLevels.filter((z) => z.kind === kind).length;
|
||||||
|
// Buchstaben-Suffix (A, B, …, Z, dann AA…) — klassische Schnitt-Benennung.
|
||||||
|
let n = count;
|
||||||
|
let letters = "";
|
||||||
|
do {
|
||||||
|
letters = String.fromCharCode(65 + (n % 26)) + letters;
|
||||||
|
n = Math.floor(n / 26) - 1;
|
||||||
|
} while (n >= 0);
|
||||||
|
const key = kind === "section" ? "cmd.sectionline.newSection" : "cmd.sectionline.newElevation";
|
||||||
|
return t(key, { letter: letters });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setzt die Schnittlinie [a, b] auf die Ziel-Ebene (immutabel). Existiert GENAU
|
||||||
|
* EINE Ebene der Art ohne Linie, wird sie belegt; sonst wird eine neue angelegt.
|
||||||
|
* Entartete (zu kurze) Linien werden verworfen.
|
||||||
|
*/
|
||||||
|
function commitLine(p: Project, a: Vec2, b: Vec2, kind: LineKind): Project {
|
||||||
|
if (Math.hypot(b.x - a.x, b.y - a.y) < 0.1) return p;
|
||||||
|
const line: [Vec2, Vec2] = [a, b];
|
||||||
|
const orphans = p.drawingLevels.filter((z) => z.kind === kind && !z.linePoints);
|
||||||
|
if (orphans.length === 1) {
|
||||||
|
const targetId = orphans[0].id;
|
||||||
|
return {
|
||||||
|
...p,
|
||||||
|
drawingLevels: p.drawingLevels.map((z) =>
|
||||||
|
z.id === targetId ? { ...z, linePoints: line, directionSign: z.directionSign ?? 1 } : z,
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const level: DrawingLevel = {
|
||||||
|
id: `${kind}-${Date.now()}`,
|
||||||
|
name: nextLevelName(p, kind),
|
||||||
|
kind: kind as DrawingLevelKind,
|
||||||
|
visible: true,
|
||||||
|
locked: false,
|
||||||
|
linePoints: line,
|
||||||
|
directionSign: 1,
|
||||||
|
};
|
||||||
|
return { ...p, drawingLevels: [...p.drawingLevels, level] };
|
||||||
|
}
|
||||||
|
|
||||||
|
interface LineIdle extends CommandState {
|
||||||
|
phase: "start";
|
||||||
|
kind: LineKind;
|
||||||
|
}
|
||||||
|
interface LineEnd extends CommandState {
|
||||||
|
phase: "end";
|
||||||
|
a: Vec2;
|
||||||
|
cursor: Vec2 | null;
|
||||||
|
kind: LineKind;
|
||||||
|
}
|
||||||
|
type LineState = LineIdle | LineEnd;
|
||||||
|
|
||||||
|
const DIRECTION_SIGN: 1 = 1;
|
||||||
|
|
||||||
|
function makeCommand(name: string, startKind: LineKind): Command {
|
||||||
|
const idle = (kind: LineKind): [CommandState, CommandResult] => [
|
||||||
|
{ phase: "start", kind, lastPoint: null } as LineIdle,
|
||||||
|
{ draft: null, done: true },
|
||||||
|
];
|
||||||
|
return {
|
||||||
|
name,
|
||||||
|
labelKey: "cmd.sectionline.label",
|
||||||
|
// Nicht floorOnly: eine Schnittlinie zieht man IM Grundriss, wo Bauteile
|
||||||
|
// liegen — die aktive Ebene ist dann ein Geschoss. Aber der Befehl soll auch
|
||||||
|
// auf freien Zeichnungsebenen nutzbar bleiben; die Prüfung übernimmt der
|
||||||
|
// Grundriss-Kontext (keine harte Sperre nötig).
|
||||||
|
floorOnly: true,
|
||||||
|
prompt: (s) => ((s as LineState).phase === "end" ? "cmd.sectionline.end" : "cmd.sectionline.start"),
|
||||||
|
accepts: () => ["point", "option"],
|
||||||
|
options: () => KIND_OPTIONS,
|
||||||
|
init: (): LineIdle => ({ phase: "start", kind: startKind, lastPoint: null }),
|
||||||
|
|
||||||
|
onInput: (state, input): [CommandState, CommandResult] => {
|
||||||
|
const s = state as LineState;
|
||||||
|
if (input.kind === "option" && KIND_IDS.has(input.id)) {
|
||||||
|
const ns = { ...s, kind: input.id as LineKind } as LineState;
|
||||||
|
const draft =
|
||||||
|
ns.phase === "end" ? lineDraft(ns.a, ns.cursor, DIRECTION_SIGN) : null;
|
||||||
|
return [ns, { draft }];
|
||||||
|
}
|
||||||
|
if (input.kind !== "point") {
|
||||||
|
return [
|
||||||
|
s,
|
||||||
|
{ draft: s.phase === "end" ? lineDraft(s.a, s.cursor, DIRECTION_SIGN) : null },
|
||||||
|
];
|
||||||
|
}
|
||||||
|
if (s.phase !== "end") {
|
||||||
|
const ns: LineEnd = {
|
||||||
|
phase: "end",
|
||||||
|
a: input.point,
|
||||||
|
cursor: input.point,
|
||||||
|
kind: s.kind,
|
||||||
|
lastPoint: input.point,
|
||||||
|
};
|
||||||
|
return [ns, { draft: lineDraft(input.point, input.point, DIRECTION_SIGN) }];
|
||||||
|
}
|
||||||
|
const a = s.a;
|
||||||
|
const b = input.point;
|
||||||
|
const kind = s.kind;
|
||||||
|
return [
|
||||||
|
{ phase: "start", kind, lastPoint: null } as LineIdle,
|
||||||
|
{ draft: null, done: true, commit: (p) => commitLine(p, a, b, kind) },
|
||||||
|
];
|
||||||
|
},
|
||||||
|
|
||||||
|
onMove: (state, point): [CommandState, CommandResult] => {
|
||||||
|
const s = state as LineState;
|
||||||
|
if (s.phase !== "end") return [s, { draft: null }];
|
||||||
|
const ns: LineEnd = { ...s, cursor: point };
|
||||||
|
return [ns, { draft: lineDraft(s.a, point, DIRECTION_SIGN) }];
|
||||||
|
},
|
||||||
|
|
||||||
|
onConfirm: (state): [CommandState, CommandResult] => idle((state as LineState).kind),
|
||||||
|
onCancel: (state): [CommandState, CommandResult] => idle((state as LineState).kind),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Schnittlinie (startet als „section"). */
|
||||||
|
export const sectionLineCommand: Command = makeCommand("sectionline", "section");
|
||||||
|
/** Ansichtslinie (startet als „elevation"; identische Mechanik). */
|
||||||
|
export const viewLineCommand: Command = makeCommand("viewline", "elevation");
|
||||||
|
|
||||||
|
// Für Tests: die reinen Datenpfad-Helfer.
|
||||||
|
export const _test = { commitLine, nextLevelName, directionArrow };
|
||||||
@@ -29,6 +29,7 @@ import { trimCommand } from "./cmds/trim";
|
|||||||
import { importCommand } from "./cmds/import";
|
import { importCommand } from "./cmds/import";
|
||||||
import { terrainCommand } from "./cmds/terrain";
|
import { terrainCommand } from "./cmds/terrain";
|
||||||
import { measureCommand } from "./cmds/measure";
|
import { measureCommand } from "./cmds/measure";
|
||||||
|
import { sectionLineCommand, viewLineCommand } from "./cmds/sectionline";
|
||||||
|
|
||||||
/** Alle bekannten Befehle, Schlüssel = Befehlsname (lowercase). */
|
/** Alle bekannten Befehle, Schlüssel = Befehlsname (lowercase). */
|
||||||
export const COMMANDS: Record<string, Command> = {
|
export const COMMANDS: Record<string, Command> = {
|
||||||
@@ -59,6 +60,8 @@ export const COMMANDS: Record<string, Command> = {
|
|||||||
import: importCommand,
|
import: importCommand,
|
||||||
terrain: terrainCommand,
|
terrain: terrainCommand,
|
||||||
measure: measureCommand,
|
measure: measureCommand,
|
||||||
|
sectionline: sectionLineCommand,
|
||||||
|
viewline: viewLineCommand,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -105,6 +108,8 @@ export const ALIASES: Record<string, string> = {
|
|||||||
tr: "trim",
|
tr: "trim",
|
||||||
imp: "import",
|
imp: "import",
|
||||||
ter: "terrain",
|
ter: "terrain",
|
||||||
|
schnittlinie: "sectionline",
|
||||||
|
ansichtslinie: "viewline",
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Liefert den Befehl zu einem exakten Namen (oder undefined). */
|
/** Liefert den Befehl zu einem exakten Namen (oder undefined). */
|
||||||
|
|||||||
@@ -145,6 +145,7 @@ export const de = {
|
|||||||
"ribbon.group.draw": "Zeichnen",
|
"ribbon.group.draw": "Zeichnen",
|
||||||
"ribbon.group.modify": "Ändern",
|
"ribbon.group.modify": "Ändern",
|
||||||
"ribbon.group.components": "Bauteile",
|
"ribbon.group.components": "Bauteile",
|
||||||
|
"ribbon.group.sections": "Schnitte",
|
||||||
"ribbon.group.custom": "Eigene Leiste",
|
"ribbon.group.custom": "Eigene Leiste",
|
||||||
"ribbon.custom.add": "+ Hinzufügen",
|
"ribbon.custom.add": "+ Hinzufügen",
|
||||||
"ribbon.custom.empty": "Elemente über + Hinzufügen wählen",
|
"ribbon.custom.empty": "Elemente über + Hinzufügen wählen",
|
||||||
@@ -974,6 +975,13 @@ export const de = {
|
|||||||
"cmd.roof.shape.mansarde": "Mansarddach",
|
"cmd.roof.shape.mansarde": "Mansarddach",
|
||||||
"cmd.roof.shape.zelt": "Zeltdach",
|
"cmd.roof.shape.zelt": "Zeltdach",
|
||||||
"cmd.roof.shape.flach": "Flachdach",
|
"cmd.roof.shape.flach": "Flachdach",
|
||||||
|
"cmd.sectionline.label": "Schnittlinie",
|
||||||
|
"cmd.sectionline.start": "Schnitt-Startpunkt:",
|
||||||
|
"cmd.sectionline.end": "Schnitt-Endpunkt:",
|
||||||
|
"cmd.sectionline.kind.section": "Schnitt",
|
||||||
|
"cmd.sectionline.kind.elevation": "Ansicht",
|
||||||
|
"cmd.sectionline.newSection": "Schnitt {letter}",
|
||||||
|
"cmd.sectionline.newElevation": "Ansicht {letter}",
|
||||||
"cmd.opening.label": "Öffnung",
|
"cmd.opening.label": "Öffnung",
|
||||||
"cmd.opening.windowLabel": "Fenster",
|
"cmd.opening.windowLabel": "Fenster",
|
||||||
"cmd.opening.doorLabel": "Tür",
|
"cmd.opening.doorLabel": "Tür",
|
||||||
|
|||||||
@@ -144,6 +144,7 @@ export const en: Record<TranslationKey, string> = {
|
|||||||
"ribbon.group.draw": "Draw",
|
"ribbon.group.draw": "Draw",
|
||||||
"ribbon.group.modify": "Modify",
|
"ribbon.group.modify": "Modify",
|
||||||
"ribbon.group.components": "Components",
|
"ribbon.group.components": "Components",
|
||||||
|
"ribbon.group.sections": "Sections",
|
||||||
"ribbon.group.custom": "Custom bar",
|
"ribbon.group.custom": "Custom bar",
|
||||||
"ribbon.custom.add": "+ Add",
|
"ribbon.custom.add": "+ Add",
|
||||||
"ribbon.custom.empty": "Pick elements via “+ Add”",
|
"ribbon.custom.empty": "Pick elements via “+ Add”",
|
||||||
@@ -964,6 +965,13 @@ export const en: Record<TranslationKey, string> = {
|
|||||||
"cmd.roof.shape.mansarde": "Mansard roof",
|
"cmd.roof.shape.mansarde": "Mansard roof",
|
||||||
"cmd.roof.shape.zelt": "Pyramid roof",
|
"cmd.roof.shape.zelt": "Pyramid roof",
|
||||||
"cmd.roof.shape.flach": "Flat roof",
|
"cmd.roof.shape.flach": "Flat roof",
|
||||||
|
"cmd.sectionline.label": "Section line",
|
||||||
|
"cmd.sectionline.start": "Section start point:",
|
||||||
|
"cmd.sectionline.end": "Section end point:",
|
||||||
|
"cmd.sectionline.kind.section": "Section",
|
||||||
|
"cmd.sectionline.kind.elevation": "Elevation",
|
||||||
|
"cmd.sectionline.newSection": "Section {letter}",
|
||||||
|
"cmd.sectionline.newElevation": "Elevation {letter}",
|
||||||
"cmd.opening.label": "Opening",
|
"cmd.opening.label": "Opening",
|
||||||
"cmd.opening.windowLabel": "Window",
|
"cmd.opening.windowLabel": "Window",
|
||||||
"cmd.opening.doorLabel": "Door",
|
"cmd.opening.doorLabel": "Door",
|
||||||
|
|||||||
@@ -763,6 +763,13 @@ export interface DrawingLevel {
|
|||||||
linePoints?: [Vec2, Vec2];
|
linePoints?: [Vec2, Vec2];
|
||||||
/** Blickrichtung relativ zur Schnittlinie (nur Schnitt/Ansicht). */
|
/** Blickrichtung relativ zur Schnittlinie (nur Schnitt/Ansicht). */
|
||||||
directionSign?: 1 | -1;
|
directionSign?: 1 | -1;
|
||||||
|
/**
|
||||||
|
* Schnitt-Tiefe in Metern (nur Schnitt/Ansicht): Bauteile weiter als `depth`
|
||||||
|
* HINTER der Schnittebene (in Blickrichtung) werden ausgeblendet. Fehlt der
|
||||||
|
* Wert, ist die Tiefe unbegrenzt (das gesamte Modell wird projiziert — heutiges
|
||||||
|
* Verhalten).
|
||||||
|
*/
|
||||||
|
depth?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -110,6 +110,10 @@ export const RIBBON_TABS: RibbonTab[] = [
|
|||||||
t("room"),
|
t("room"),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
titleKey: "ribbon.group.sections",
|
||||||
|
items: [c("sectionline"), c("viewline")],
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user