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",
|
||||
] 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> = {
|
||||
HNF: "Hauptnutzfläche",
|
||||
NNF: "Nebennutzfläche",
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
// Bezeichner englisch, Kommentare deutsch (CONVENTIONS.md).
|
||||
|
||||
import Delaunator from "delaunator";
|
||||
import type { GeoOrigin } from "./lv95";
|
||||
import type { ContextObject, Contour, ImportedMesh } from "../model/types";
|
||||
|
||||
/** 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. */
|
||||
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). */
|
||||
const CATEGORY_LABEL: Record<GeoCategory, string> = {
|
||||
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.
|
||||
* Anders als das Muster in compute/index.ts bzw. plan/nativeSync.ts schluckt
|
||||
* dieser Helfer KEINE Fehler aus dem eigentlichen Aufruf — ein `Err(...)` vom
|
||||
* Anders als das Muster in plan/nativeSync.ts schluckt dieser Helfer KEINE
|
||||
* Fehler aus dem eigentlichen Aufruf — ein `Err(...)` vom
|
||||
* Rust-Command (hier: „schon gelockt", inkl. {@link LockInfo}-Payload) muss bis
|
||||
* zum Aufrufer durchgereicht werden.
|
||||
*/
|
||||
|
||||
@@ -24,10 +24,6 @@ export interface MaterialAsset {
|
||||
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[] = [
|
||||
{
|
||||
id: "Concrete048",
|
||||
|
||||
@@ -561,9 +561,5 @@ function isExteriorWall(wall: Wall, ctx: RuleCtx): boolean {
|
||||
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.
|
||||
export type { DrawingLevel };
|
||||
|
||||
@@ -2353,10 +2353,6 @@ export const roofLayers = (project: Project, roof: Roof): Layer[] => {
|
||||
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
|
||||
* `typeId` bzw. unbekannt ⇒ Inline-Verhalten). Bewusst NICHT werfend — der
|
||||
|
||||
@@ -172,9 +172,8 @@ export function ToolIcon({ id }: { id: ToolId }) {
|
||||
|
||||
// ── Kategorien ───────────────────────────────────────────────────────────────
|
||||
// Werkzeuge/Befehle in drei Rubriken sortiert (Nutzerwunsch: „sortiere nach 2D
|
||||
// und 3D und Bearbeiten"). Befehlsnamen spiegeln die Ribbon-Registry
|
||||
// (ui/ribbon/ribbonItems.ts) — dort liegt die kanonische Liste; hier nur die
|
||||
// Panel-Gruppierung (2D-Zeichnen · 3D/BIM-Bauteile · Bearbeiten-Aktionen).
|
||||
// und 3D und Bearbeiten"): reine Panel-Gruppierung (2D-Zeichnen · 3D/BIM-
|
||||
// Bauteile · Bearbeiten-Aktionen).
|
||||
const TOOLS_2D: ToolId[] = ["line", "polyline", "rect", "circle", "arc", "text", "textbox", "image"];
|
||||
const TOOLS_3D: ToolId[] = ["wall", "ceiling", "window", "door", "stair", "room"];
|
||||
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_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). */
|
||||
interface DragState {
|
||||
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