Zweite Leichen-Runde: weitere tote Exporte + orphaned ribbonItems.ts entfernt
ts-prune nach dem ersten Durchgang erneut laufen lassen. compute/index.ts (101 Z., PoC-Brücke zu einem nie gebauten Rust-Command, im eigenen Kopfkommentar schon als ungenutzt markiert) komplett gelöscht. ribbonItems.ts war nur noch für das bereits gelöschte RibbonBar.tsx da (kein anderer Importeur mehr) — ebenfalls komplett weg. Einzelne tote Typen/Konstanten: SiaLabel (roomArea.ts), GeoImportResult (geoContext.ts, plus den dadurch verwaisten GeoOrigin-Import), die drei MATERIAL_LIBRARY_*-Konstanten (library.ts), ResolveContext-Re-Export (parametricWalls.ts), roofTotalThickness (types.ts — Duplikat, die echte Rechnung läuft in toWalls3d/bands.ts inline), DropTarget (panelDrag.tsx). resolveBackground (generatePlan/shared.ts) bewusst NICHT gelöscht: anders als das analoge resolveForeground wird es nirgends aufgerufen, obwohl backgroundSource für Wand/Decke im Modell und im Attribut-Panel existiert — sieht nach einer echten Lücke aus (By-Layer-Hintergrundfarbe kommt nie im Renderer an), nicht nach totem Code. tsc -b / vitest run (891/891) / npm run build grün.
This commit is contained in:
@@ -1,101 +0,0 @@
|
|||||||
// Compute-Grenze: der EINE Einstiegspunkt für rechenintensive Operationen.
|
|
||||||
// War als Brücke zu einem Rust-`#[tauri::command]` gedacht (PoC), aber
|
|
||||||
// ungenutzt: kein Aufrufer im Frontend, und die Rust-Seite (`compute_joins` +
|
|
||||||
// das `geometry`-Crate) wurde entfernt (ungenutzter Totcode, s. PENDENZEN.md).
|
|
||||||
// `computeJoins` läuft daher immer über den TS-Fallback; die übrigen
|
|
||||||
// Funktionen waren schon vorher reine TS-Pass-throughs.
|
|
||||||
|
|
||||||
import type { Project, Wall } from "../model/types";
|
|
||||||
import { getWallType, wallTypeThickness } from "../model/types";
|
|
||||||
import { wallReferenceOffset } from "../model/wall";
|
|
||||||
import { computeJoins as computeJoinsTS } from "../model/joins";
|
|
||||||
import type { WallCuts } from "../model/joins";
|
|
||||||
import type { Line } from "../model/geometry";
|
|
||||||
import { detectRooms as detectRoomsTS } from "../geometry/roomBoundary";
|
|
||||||
import type { WallSegment, DetectRoomsOptions } from "../geometry/roomBoundary";
|
|
||||||
import { parseDwg as parseDwgTS } from "../io/dwgParser";
|
|
||||||
import type { DxfImportResult } from "../io/dxfParser";
|
|
||||||
import type { Vec2 } from "../model/types";
|
|
||||||
|
|
||||||
// Tauri-invoke, wenn vorhanden — sonst null (Browser/kein Tauri). Dynamischer,
|
|
||||||
// GEGUARDETER Import, damit der Build ohne @tauri-apps/api grün bleibt.
|
|
||||||
async function tauriInvoke<T>(cmd: string, args: Record<string, unknown>): Promise<T | null> {
|
|
||||||
try {
|
|
||||||
// @ts-ignore optionales Paket
|
|
||||||
const mod = await import(/* @vite-ignore */ "@tauri-apps/api/core").catch(() => null);
|
|
||||||
if (!mod || typeof (mod as any).invoke !== "function") return null;
|
|
||||||
return await (mod as any).invoke(cmd, args) as T;
|
|
||||||
} catch {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Serialisierbare Wand-Repräsentation für den Rust-Kern. */
|
|
||||||
interface FlatWall {
|
|
||||||
id: string;
|
|
||||||
start: Vec2;
|
|
||||||
end: Vec2;
|
|
||||||
thickness: number;
|
|
||||||
referenceOffset: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Rohantwort des Rust-Befehls `compute_joins`. */
|
|
||||||
interface RustWallCut {
|
|
||||||
wallId: string;
|
|
||||||
startCut: Line | null;
|
|
||||||
endCut: Line | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gehrungs-Schnittlinien pro Wand. Unter Tauri via Rust-Kern, sonst TS-Fallback.
|
|
||||||
* Die Signatur ist synchron-kompatibel zur TS-Impl, aber async (Rust-Aufruf).
|
|
||||||
*/
|
|
||||||
export async function computeJoins(
|
|
||||||
project: Project,
|
|
||||||
walls: Wall[],
|
|
||||||
): Promise<Map<string, WallCuts>> {
|
|
||||||
try {
|
|
||||||
const flattened: FlatWall[] = walls.map((w) => {
|
|
||||||
const thickness = wallTypeThickness(getWallType(project, w));
|
|
||||||
return {
|
|
||||||
id: w.id,
|
|
||||||
start: w.start,
|
|
||||||
end: w.end,
|
|
||||||
thickness,
|
|
||||||
referenceOffset: wallReferenceOffset(w, thickness),
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
const res = await tauriInvoke<RustWallCut[]>("compute_joins", {
|
|
||||||
input: { walls: flattened },
|
|
||||||
});
|
|
||||||
if (res != null) {
|
|
||||||
const map = new Map<string, WallCuts>();
|
|
||||||
for (const c of res) {
|
|
||||||
map.set(c.wallId, { startCut: c.startCut, endCut: c.endCut });
|
|
||||||
}
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
// fällt unten in den TS-Pfad
|
|
||||||
}
|
|
||||||
console.warn("Rust compute_joins nicht verfügbar, TS-Fallback");
|
|
||||||
return computeJoinsTS(project, walls);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ── Pass-throughs (noch reines TS; bereit für spätere Rust-Migration) ─────────
|
|
||||||
|
|
||||||
/** Raumerkennung aus Wandsegmenten. Aktuell TS; Grenze für spätere Migration. */
|
|
||||||
export async function detectRooms(
|
|
||||||
walls: WallSegment[],
|
|
||||||
options: DetectRoomsOptions = {},
|
|
||||||
): Promise<Vec2[][]> {
|
|
||||||
return detectRoomsTS(walls, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** DWG-Import (LibreDWG-WASM). Aktuell TS; Grenze für spätere Migration. */
|
|
||||||
export async function parseShapeFromDwg(
|
|
||||||
data: ArrayBuffer,
|
|
||||||
): Promise<DxfImportResult> {
|
|
||||||
return parseDwgTS(data);
|
|
||||||
}
|
|
||||||
@@ -124,14 +124,6 @@ export const SIA_CATEGORIES: readonly SiaCategory[] = [
|
|||||||
"AGF",
|
"AGF",
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
/** Deutsche Bezeichnungen (Kurz + Lang) je SIA-416-Schlüssel. */
|
|
||||||
export interface SiaLabel {
|
|
||||||
/** Kürzel, z. B. „HNF". */
|
|
||||||
code: SiaKey;
|
|
||||||
/** Ausgeschriebene deutsche Bezeichnung. */
|
|
||||||
name: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const SIA_LABELS: Record<SiaKey, string> = {
|
const SIA_LABELS: Record<SiaKey, string> = {
|
||||||
HNF: "Hauptnutzfläche",
|
HNF: "Hauptnutzfläche",
|
||||||
NNF: "Nebennutzfläche",
|
NNF: "Nebennutzfläche",
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
// Bezeichner englisch, Kommentare deutsch (CONVENTIONS.md).
|
// Bezeichner englisch, Kommentare deutsch (CONVENTIONS.md).
|
||||||
|
|
||||||
import Delaunator from "delaunator";
|
import Delaunator from "delaunator";
|
||||||
import type { GeoOrigin } from "./lv95";
|
|
||||||
import type { ContextObject, Contour, ImportedMesh } from "../model/types";
|
import type { ContextObject, Contour, ImportedMesh } from "../model/types";
|
||||||
|
|
||||||
/** Fachliche Kategorie einer importierten Kontext-Linie. */
|
/** Fachliche Kategorie einer importierten Kontext-Linie. */
|
||||||
@@ -39,12 +38,6 @@ export interface GeoFeature {
|
|||||||
/** Default-Gebäudehöhe (m), wenn keine Höhe aus der Quelle vorliegt. */
|
/** Default-Gebäudehöhe (m), wenn keine Höhe aus der Quelle vorliegt. */
|
||||||
export const DEFAULT_BUILDING_HEIGHT = 9;
|
export const DEFAULT_BUILDING_HEIGHT = 9;
|
||||||
|
|
||||||
/** Ergebnis eines Import-Laufs: Features + verwendete Origin. */
|
|
||||||
export interface GeoImportResult {
|
|
||||||
origin: GeoOrigin;
|
|
||||||
features: GeoFeature[];
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Menschlicher Layer-/Objektname je Kategorie (deutsch, für die Kontext-Liste). */
|
/** Menschlicher Layer-/Objektname je Kategorie (deutsch, für die Kontext-Liste). */
|
||||||
const CATEGORY_LABEL: Record<GeoCategory, string> = {
|
const CATEGORY_LABEL: Record<GeoCategory, string> = {
|
||||||
building: "Gebäude",
|
building: "Gebäude",
|
||||||
|
|||||||
@@ -107,8 +107,8 @@ export type LockResult = { ok: true } | { ok: false; info: LockInfo | null };
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Holt (ungeguardet) die Tauri-`invoke`-Funktion, oder `null` ohne Tauri-Core.
|
* Holt (ungeguardet) die Tauri-`invoke`-Funktion, oder `null` ohne Tauri-Core.
|
||||||
* Anders als das Muster in compute/index.ts bzw. plan/nativeSync.ts schluckt
|
* Anders als das Muster in plan/nativeSync.ts schluckt dieser Helfer KEINE
|
||||||
* dieser Helfer KEINE Fehler aus dem eigentlichen Aufruf — ein `Err(...)` vom
|
* Fehler aus dem eigentlichen Aufruf — ein `Err(...)` vom
|
||||||
* Rust-Command (hier: „schon gelockt", inkl. {@link LockInfo}-Payload) muss bis
|
* Rust-Command (hier: „schon gelockt", inkl. {@link LockInfo}-Payload) muss bis
|
||||||
* zum Aufrufer durchgereicht werden.
|
* zum Aufrufer durchgereicht werden.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -24,10 +24,6 @@ export interface MaterialAsset {
|
|||||||
maps: Partial<Record<MaterialMapKind, string>>;
|
maps: Partial<Record<MaterialMapKind, string>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const MATERIAL_LIBRARY_SOURCE = "ambientCG (ambientcg.com)";
|
|
||||||
export const MATERIAL_LIBRARY_LICENSE = "CC0 1.0 Universal (Public Domain)";
|
|
||||||
export const MATERIAL_LIBRARY_RESOLUTION = "2K";
|
|
||||||
|
|
||||||
export const MATERIAL_LIBRARY: MaterialAsset[] = [
|
export const MATERIAL_LIBRARY: MaterialAsset[] = [
|
||||||
{
|
{
|
||||||
id: "Concrete048",
|
id: "Concrete048",
|
||||||
|
|||||||
@@ -561,9 +561,5 @@ function isExteriorWall(wall: Wall, ctx: RuleCtx): boolean {
|
|||||||
return isOnEdge(wall.start) && isOnEdge(wall.end);
|
return isOnEdge(wall.start) && isOnEdge(wall.end);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Re-Export der Kontexttypen für Unit-Tests / Integration ──────────────
|
|
||||||
// (ermöglicht Import ohne Direktverweis auf interne RuleCtx)
|
|
||||||
export type { ParametricContext as ResolveContext };
|
|
||||||
|
|
||||||
// DrawingLevel-Re-Export für Konsumenten, die keinen eigenen types-Import wollen.
|
// DrawingLevel-Re-Export für Konsumenten, die keinen eigenen types-Import wollen.
|
||||||
export type { DrawingLevel };
|
export type { DrawingLevel };
|
||||||
|
|||||||
@@ -2353,10 +2353,6 @@ export const roofLayers = (project: Project, roof: Roof): Layer[] => {
|
|||||||
return [{ componentId: "", thickness: Math.max(0, roof.thickness) }];
|
return [{ componentId: "", thickness: Math.max(0, roof.thickness) }];
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Gesamtdicke eines Daches (Meter, senkrecht zur Fläche) = Summe der Schichten. */
|
|
||||||
export const roofTotalThickness = (project: Project, roof: Roof): number =>
|
|
||||||
roofLayers(project, roof).reduce((s, l) => s + Math.max(0, l.thickness), 0);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Löst den {@link DoorType} einer Tür-Öffnung auf, oder `undefined` (keine
|
* Löst den {@link DoorType} einer Tür-Öffnung auf, oder `undefined` (keine
|
||||||
* `typeId` bzw. unbekannt ⇒ Inline-Verhalten). Bewusst NICHT werfend — der
|
* `typeId` bzw. unbekannt ⇒ Inline-Verhalten). Bewusst NICHT werfend — der
|
||||||
|
|||||||
@@ -172,9 +172,8 @@ export function ToolIcon({ id }: { id: ToolId }) {
|
|||||||
|
|
||||||
// ── Kategorien ───────────────────────────────────────────────────────────────
|
// ── Kategorien ───────────────────────────────────────────────────────────────
|
||||||
// Werkzeuge/Befehle in drei Rubriken sortiert (Nutzerwunsch: „sortiere nach 2D
|
// Werkzeuge/Befehle in drei Rubriken sortiert (Nutzerwunsch: „sortiere nach 2D
|
||||||
// und 3D und Bearbeiten"). Befehlsnamen spiegeln die Ribbon-Registry
|
// und 3D und Bearbeiten"): reine Panel-Gruppierung (2D-Zeichnen · 3D/BIM-
|
||||||
// (ui/ribbon/ribbonItems.ts) — dort liegt die kanonische Liste; hier nur die
|
// Bauteile · Bearbeiten-Aktionen).
|
||||||
// Panel-Gruppierung (2D-Zeichnen · 3D/BIM-Bauteile · Bearbeiten-Aktionen).
|
|
||||||
const TOOLS_2D: ToolId[] = ["line", "polyline", "rect", "circle", "arc", "text", "textbox", "image"];
|
const TOOLS_2D: ToolId[] = ["line", "polyline", "rect", "circle", "arc", "text", "textbox", "image"];
|
||||||
const TOOLS_3D: ToolId[] = ["wall", "ceiling", "window", "door", "stair", "room"];
|
const TOOLS_3D: ToolId[] = ["wall", "ceiling", "window", "door", "stair", "room"];
|
||||||
const COMMANDS_3D = ["column", "ceilingopening", "roof", "extrude", "sectionline", "viewline"];
|
const COMMANDS_3D = ["column", "ceilingopening", "roof", "extrude", "sectionline", "viewline"];
|
||||||
|
|||||||
@@ -36,12 +36,6 @@ const DRAG_THRESHOLD = 5;
|
|||||||
export const DEFAULT_FLOAT_W = 300;
|
export const DEFAULT_FLOAT_W = 300;
|
||||||
export const DEFAULT_FLOAT_H = 360;
|
export const DEFAULT_FLOAT_H = 360;
|
||||||
|
|
||||||
/** Ein aufgelöstes Ablageziel beim Loslassen. */
|
|
||||||
export type DropTarget =
|
|
||||||
| { kind: "join"; dock: DockId; group: number; index?: number }
|
|
||||||
| { kind: "newgroup"; dock: DockId; at: number }
|
|
||||||
| { kind: "float"; x: number; y: number };
|
|
||||||
|
|
||||||
/** Laufender Drag-Zustand (für Geist + Hervorhebung). */
|
/** Laufender Drag-Zustand (für Geist + Hervorhebung). */
|
||||||
interface DragState {
|
interface DragState {
|
||||||
panelId: string;
|
panelId: string;
|
||||||
|
|||||||
@@ -1,121 +0,0 @@
|
|||||||
// Ribbon-Registry (docs/design/ribbon-ui-plan.md §Architektur) — EINE
|
|
||||||
// datengetriebene Beschreibung aller Ribbon-Elemente. Die Ribbon-Tabs UND eine
|
|
||||||
// spätere modulare Custom-Bar (Phase 4) sind bloß zwei Ansichten über dieselbe
|
|
||||||
// Registry, ohne Sonderweg pro Element.
|
|
||||||
//
|
|
||||||
// Ein `RibbonItem` ist entweder ein Werkzeug (`tool` → onSelectTool, wie die
|
|
||||||
// Werkzeug-Sidebar) oder ein Engine-Befehl (`command` → engine.start). Beide
|
|
||||||
// münden in exakt DENSELBEN Pfad wie Klick in der alten Sidebar bzw. das Tippen
|
|
||||||
// des Befehlsnamens — keine Duplikate.
|
|
||||||
//
|
|
||||||
// Bezeichner englisch, UI-Text/Kommentare deutsch (CONVENTIONS.md). Sichtbare
|
|
||||||
// Texte kommen als i18n-Schlüssel und werden erst in der Komponente über t(...)
|
|
||||||
// aufgelöst.
|
|
||||||
|
|
||||||
import type { ToolId } from "../../tools/types";
|
|
||||||
|
|
||||||
/** Ein aktivierbares Ribbon-Element. Bei `command` wird die Beschriftung aus der
|
|
||||||
* Befehls-Registry (`getCommand(name).labelKey`) abgeleitet — kein doppeltes
|
|
||||||
* Pflegen von Labels. */
|
|
||||||
export type RibbonItem =
|
|
||||||
| { kind: "tool"; id: ToolId }
|
|
||||||
| { kind: "command"; name: string };
|
|
||||||
|
|
||||||
/** Eine benannte Gruppe von Elementen innerhalb eines Tabs. */
|
|
||||||
export interface RibbonGroup {
|
|
||||||
titleKey: string;
|
|
||||||
items: RibbonItem[];
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Kennung eines Ribbon-Tabs (fest, für Tab-State + i18n). */
|
|
||||||
export type RibbonTabId = "2d" | "bim" | "custom";
|
|
||||||
|
|
||||||
/** Ein Ribbon-Tab: Beschriftung + gruppierte Elemente. */
|
|
||||||
export interface RibbonTab {
|
|
||||||
id: RibbonTabId;
|
|
||||||
labelKey: string;
|
|
||||||
groups: RibbonGroup[];
|
|
||||||
}
|
|
||||||
|
|
||||||
const c = (name: string): RibbonItem => ({ kind: "command", name });
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Die Ribbon-Tabs (2D·BIM·Eigene) — keine Tab-Reiter mehr in der UI (v12,
|
|
||||||
* siehe layout.ts): App rendert alle drei permanent nebeneinander (kein
|
|
||||||
* Umschalter). Reine Werkzeug-Elemente (`t(...)`, persistentes Werkzeug wie
|
|
||||||
* Wand/Linie/Fenster) leben AUSSCHLIESSLICH im ToolsPanel (kein Doppel-
|
|
||||||
* Auftritt). Reine Befehls-Elemente (`c(...)`, Einmal-Aktionen wie
|
|
||||||
* Verschieben/Kopieren/Säule setzen ohne eigenen Werkzeug-Modus) bleiben hier,
|
|
||||||
* da sie im Panel keine Entsprechung haben. Ansichts-/Zoom-/Darstellungs-
|
|
||||||
* Steuerung + Text-Formatierung sitzen direkt in App (ViewRibbonTab), nicht
|
|
||||||
* in dieser Registry.
|
|
||||||
*/
|
|
||||||
export const RIBBON_TABS: RibbonTab[] = [
|
|
||||||
{
|
|
||||||
id: "2d",
|
|
||||||
labelKey: "ribbon.tab.2d",
|
|
||||||
groups: [
|
|
||||||
{
|
|
||||||
titleKey: "ribbon.group.modify",
|
|
||||||
items: [
|
|
||||||
c("move"),
|
|
||||||
c("copy"),
|
|
||||||
c("rotate"),
|
|
||||||
c("mirror"),
|
|
||||||
c("offset"),
|
|
||||||
c("trim"),
|
|
||||||
c("join"),
|
|
||||||
c("measure"),
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "bim",
|
|
||||||
labelKey: "ribbon.tab.bim",
|
|
||||||
groups: [
|
|
||||||
{
|
|
||||||
// "extrude" war vormals im (jetzt entfernten) 3D-Ribbon-Tab
|
|
||||||
// (Ribbon3dTab) — einziger Zugang zum Befehl, daher hier statt
|
|
||||||
// gestrichen.
|
|
||||||
titleKey: "ribbon.group.components",
|
|
||||||
items: [c("column"), c("ceilingopening"), c("roof"), c("extrude")],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
titleKey: "ribbon.group.sections",
|
|
||||||
items: [c("sectionline"), c("viewline")],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// Modulare Custom-Bar (Phase 4): der Nutzer stellt sich die Elemente selbst
|
|
||||||
// zusammen (persistiert). Gerendert aus `customItems`, nicht aus `groups`.
|
|
||||||
id: "custom",
|
|
||||||
labelKey: "ribbon.tab.custom",
|
|
||||||
groups: [],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
/** Stabiler Schlüssel eines Items für die Persistenz der Custom-Bar. */
|
|
||||||
export function itemKey(item: RibbonItem): string {
|
|
||||||
return item.kind === "tool" ? `tool:${item.id}` : `command:${item.name}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Parst einen Item-Schlüssel zurück (oder null bei unbekanntem Präfix). */
|
|
||||||
export function itemFromKey(key: string): RibbonItem | null {
|
|
||||||
const i = key.indexOf(":");
|
|
||||||
if (i < 0) return null;
|
|
||||||
const kind = key.slice(0, i);
|
|
||||||
const rest = key.slice(i + 1);
|
|
||||||
if (kind === "tool") return { kind: "tool", id: rest as ToolId };
|
|
||||||
if (kind === "command") return { kind: "command", name: rest };
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Alle datengetriebenen Items (aus den Werkzeug-/Befehls-Tabs) — die wählbare
|
|
||||||
* Menge für den Custom-Bar-Picker. „views"/„custom" tragen keine `groups`.
|
|
||||||
*/
|
|
||||||
export const ALL_RIBBON_ITEMS: RibbonItem[] = RIBBON_TABS.flatMap((tab) =>
|
|
||||||
tab.groups.flatMap((g) => g.items),
|
|
||||||
);
|
|
||||||
Reference in New Issue
Block a user