ca859c4aa4
Standalone-Browser-Port von DOSSIER. Enthaelt das semantische Modell mit Plan-/3D-Ableitung, Zeichen- und Editierwerkzeuge, Rhino-artiges Befehlssystem, dockbares Panel-System, Resource-Manager, DXF/.lin/.pat-Import, i18n (de/en) sowie Projektdokumentation und Probe-Harness.
82 lines
3.2 KiB
TypeScript
82 lines
3.2 KiB
TypeScript
// Site-/Kontext-Slice: verwaltet die Kontext-Schicht `project.context`
|
|
// (importierte Meshes, Konturen-Sätze, abgeleitetes Gelände-TIN). Diese
|
|
// Geometrie ist „dumm"/nicht-semantisch — sie liegt bewusst NEBEN dem BIM-Modell.
|
|
//
|
|
// Entwurfsentscheidung: `context` ist Teil von `project` (ein einziger
|
|
// Wahrheits-Baum, konsistent mit projectSlice). Diese Slice MUTIERT daher
|
|
// `project.context` IMMUTABEL über die vorhandene `setProject`-Aktion
|
|
// (Cross-Slice), genau wie projectSlice ein neues Project-Objekt liefert. So
|
|
// bleiben Persistenz/Undo später einheitlich am Project hängen.
|
|
//
|
|
// Bezeichner englisch, Kommentare deutsch (CONVENTIONS.md).
|
|
|
|
import { generateTerrainFromContours } from "../model/terrain";
|
|
import type { ContextObject, Project } from "../model/types";
|
|
import type { StoreApi } from "./store";
|
|
|
|
/** Felder/Actions, die diese Slice in den RootState beisteuert. */
|
|
export interface SiteSlice {
|
|
/** Fügt ein Kontext-Objekt (Mesh/Konturen/Gelände) hinzu (immutabel). */
|
|
addContextObject: (obj: ContextObject) => void;
|
|
/** Fügt mehrere Kontext-Objekte in einem Schritt hinzu (z. B. DXF-Import). */
|
|
addContextObjects: (objs: ContextObject[]) => void;
|
|
/** Entfernt ein Kontext-Objekt per ID (No-op bei unbekannter ID). */
|
|
removeContextObject: (id: string) => void;
|
|
/**
|
|
* Erzeugt aus einem ContourSet (per ID) ein Gelände-TIN und fügt es als
|
|
* weiteres Kontext-Objekt hinzu. Liefert die ID des neuen TerrainMesh, oder
|
|
* null, wenn der ContourSet nicht existiert / kein Mesh entsteht.
|
|
*/
|
|
generateTerrain: (contourSetId: string) => string | null;
|
|
/** Leert die gesamte Kontext-Schicht. */
|
|
clearContext: () => void;
|
|
}
|
|
|
|
/**
|
|
* Cross-Slice-Abhängigkeit: diese Slice liest `project` und schreibt es über
|
|
* `setProject` (beide aus projectSlice). Der Store komponiert SiteSlice mit
|
|
* dieser Sicht, sodass `get()`/Actions typsicher auf das Projekt zugreifen.
|
|
*/
|
|
type SiteSliceDeps = {
|
|
project: Project;
|
|
setProject: (next: Project | ((p: Project) => Project)) => void;
|
|
};
|
|
|
|
export function createSiteSlice(
|
|
api: StoreApi<SiteSlice & SiteSliceDeps>,
|
|
): SiteSlice {
|
|
const { get } = api;
|
|
|
|
// Immutabler Kontext-Updater: ersetzt `project.context` über die vorhandene
|
|
// setProject-Aktion (konsistent mit projectSlice-Stil).
|
|
const setContext = (
|
|
update: (ctx: ContextObject[]) => ContextObject[],
|
|
): void => {
|
|
get().setProject((p) => ({ ...p, context: update(p.context ?? []) }));
|
|
};
|
|
|
|
return {
|
|
addContextObject: (obj) => setContext((ctx) => [...ctx, obj]),
|
|
|
|
addContextObjects: (objs) =>
|
|
setContext((ctx) => (objs.length ? [...ctx, ...objs] : ctx)),
|
|
|
|
removeContextObject: (id) =>
|
|
setContext((ctx) => ctx.filter((o) => o.id !== id)),
|
|
|
|
generateTerrain: (contourSetId) => {
|
|
const ctx = get().project.context ?? [];
|
|
const set = ctx.find(
|
|
(o) => o.id === contourSetId && o.type === "contourSet",
|
|
);
|
|
if (!set || set.type !== "contourSet") return null;
|
|
const terrain = generateTerrainFromContours(set.contours);
|
|
if (terrain.indices.length === 0) return null; // kein sinnvolles TIN
|
|
setContext((c) => [...c, terrain]);
|
|
return terrain.id;
|
|
},
|
|
|
|
clearContext: () => setContext(() => []),
|
|
};
|
|
}
|