Projekt-Mutationen/Ressourcen-Typ-CRUD aus App.tsx in useProjectActions() extrahiert
Bündelt Projekt-Mutationen (Store-Actions), Wand-/Decken-/Dach-/Tür-/ Fenster-/Treppentyp-CRUD sowie diverse Element-Mutationsaktionen (Teil der laufenden App.tsx-Verkleinerung).
This commit is contained in:
+93
-363
@@ -27,22 +27,15 @@ import { wallCorners } from "./model/geometry";
|
||||
import { add, dot, leftNormal, normalize, scale, sub } from "./model/geometry";
|
||||
import type {
|
||||
Ceiling,
|
||||
CeilingType,
|
||||
ContextObject,
|
||||
DoorType,
|
||||
Drawing2D,
|
||||
EdgeGrip,
|
||||
Layout,
|
||||
OverrideRule,
|
||||
Project,
|
||||
Roof,
|
||||
RoofType,
|
||||
Stair,
|
||||
StairType,
|
||||
Vec2,
|
||||
Wall,
|
||||
WallType,
|
||||
WindowType,
|
||||
} from "./model/types";
|
||||
import { generatePlan } from "./plan/generatePlan";
|
||||
import type { CategoryDisplayResolver } from "./plan/generatePlan";
|
||||
@@ -159,6 +152,7 @@ import { useDialogState } from "./state/useDialogState";
|
||||
import { useTopBarState } from "./state/useTopBarState";
|
||||
import { useDrawingToolState } from "./state/useDrawingToolState";
|
||||
import { useSelectionState } from "./state/useSelectionState";
|
||||
import { useProjectActions } from "./state/useProjectActions";
|
||||
import { useThemeModeState } from "./theme/useThemeMode";
|
||||
import { CommandLine } from "./ui/CommandLine";
|
||||
import type { CommandLineHandle, CommandLineField, CommandLineOption } from "./ui/CommandLine";
|
||||
@@ -288,36 +282,6 @@ function drawingsBBox(
|
||||
return Number.isFinite(minX) ? { minX, minY, maxX, maxY } : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bounding-Box (Modell-Meter) neu importierter Kontext-Objekte (Konturen/
|
||||
* Meshes/Terrain, z. B. aus dem Standort-Import-Dialog), als zwei Eckpunkte
|
||||
* für `PlanViewHandle.fitBounds` (Auto-Zoom auf Import). Ignoriert die
|
||||
* Z-Achse (reine 2D-Projektion, wie die Plan-Darstellung der Kontext-
|
||||
* Konturen in generatePlan.ts). Leere/degenerierte Eingabe → null.
|
||||
*/
|
||||
function contextObjectsBounds(objs: ContextObject[]): Vec2[] | null {
|
||||
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
||||
const acc = (x: number, y: number) => {
|
||||
minX = Math.min(minX, x); minY = Math.min(minY, y);
|
||||
maxX = Math.max(maxX, x); maxY = Math.max(maxY, y);
|
||||
};
|
||||
for (const obj of objs) {
|
||||
if (obj.type === "contourSet") {
|
||||
for (const c of obj.contours) for (const p of c.pts) acc(p.x, p.y);
|
||||
} else if (obj.type === "image") {
|
||||
acc(obj.min.x, obj.min.y);
|
||||
acc(obj.max.x, obj.max.y);
|
||||
} else {
|
||||
// importedMesh / terrainMesh: flaches (x,y,z…)-Array, Stride 3.
|
||||
const pos = obj.positions;
|
||||
for (let i = 0; i + 1 < pos.length; i += 3) acc(pos[i], pos[i + 1]);
|
||||
}
|
||||
}
|
||||
return Number.isFinite(minX)
|
||||
? [{ x: minX, y: minY }, { x: maxX, y: maxY }]
|
||||
: null;
|
||||
}
|
||||
|
||||
/** Ein Drawing2D um (dx,dy) in Modell-Metern verschieben (alle Formen). */
|
||||
function translateDrawing(d: Drawing2D, dx: number, dy: number): Drawing2D {
|
||||
const mv = (p: Vec2): Vec2 => ({ x: p.x + dx, y: p.y + dy });
|
||||
@@ -2124,332 +2088,98 @@ export default function App() {
|
||||
]);
|
||||
|
||||
// ── Projekt-Mutationen (aus dem Store-Slice) ─────────────────────────────
|
||||
// Sämtliche immutablen Projekt-Mutationen liegen jetzt in projectSlice. App
|
||||
// liest sie als (referenzstabile) Store-Actions und reicht sie unverändert an
|
||||
// Panels/Menüs/Editoren weiter.
|
||||
const toggleLevelVisible = useStore((s) => s.toggleLevelVisible);
|
||||
const toggleCategoryVisible = useStore((s) => s.toggleCategoryVisible);
|
||||
const addFloor = useStore((s) => s.addFloor);
|
||||
const addDrawing = useStore((s) => s.addDrawing);
|
||||
const addSection = useStore((s) => s.addSection);
|
||||
const addElevation = useStore((s) => s.addElevation);
|
||||
const addDrawingLevel = useStore((s) => s.addDrawingLevel);
|
||||
const importDrawings = useStore((s) => s.importDrawings);
|
||||
const addCategory = useStore((s) => s.addCategory);
|
||||
const patchCategory = useStore((s) => s.patchCategory);
|
||||
const addSubCategory = useStore((s) => s.addSubCategory);
|
||||
const duplicateCategory = useStore((s) => s.duplicateCategory);
|
||||
const deleteCategory = useStore((s) => s.deleteCategory);
|
||||
const assignWallCategory = useStore((s) => s.assignWallCategory);
|
||||
const snapshotLayerVisibility = useStore((s) => s.snapshotLayerVisibility);
|
||||
const applyLayerVisibility = useStore((s) => s.applyLayerVisibility);
|
||||
const snapshotDrawingVisibility = useStore((s) => s.snapshotDrawingVisibility);
|
||||
const applyDrawingVisibility = useStore((s) => s.applyDrawingVisibility);
|
||||
const patchLevel = useStore((s) => s.patchLevel);
|
||||
const duplicateLevel = useStore((s) => s.duplicateLevel);
|
||||
const deleteLevel = useStore((s) => s.deleteLevel);
|
||||
const patchComponent = useStore((s) => s.patchComponent);
|
||||
const addComponent = useStore((s) => s.addComponent);
|
||||
const deleteComponent = useStore((s) => s.deleteComponent);
|
||||
const patchHatch = useStore((s) => s.patchHatch);
|
||||
const addHatch = useStore((s) => s.addHatch);
|
||||
const deleteHatch = useStore((s) => s.deleteHatch);
|
||||
const patchLineStyle = useStore((s) => s.patchLineStyle);
|
||||
const addLineStyle = useStore((s) => s.addLineStyle);
|
||||
const deleteLineStyle = useStore((s) => s.deleteLineStyle);
|
||||
// Wandstile: immutable Patch eines Wandtyps (z. B. Schichtfugen-Stile). Kein
|
||||
// eigener Store-Slice nötig — läuft direkt über setProject wie die übrigen
|
||||
// Ressourcen-Mutationen.
|
||||
const patchWallType = (id: string, patch: Partial<WallType>) =>
|
||||
setProject((p) => ({
|
||||
...p,
|
||||
wallTypes: p.wallTypes.map((wt) => (wt.id === id ? { ...wt, ...patch } : wt)),
|
||||
}));
|
||||
// Grafische Override-Regeln: ersetzt die ganze Regelliste (Reihenfolge =
|
||||
// Priorität, oben gewinnt). Läuft wie die übrigen Ressourcen-Mutationen
|
||||
// direkt über setProject — persistiert damit automatisch im Projekt-JSON.
|
||||
const setOverrideRules = (rules: OverrideRule[]) =>
|
||||
setProject((p) => ({ ...p, overrideRules: rules }));
|
||||
// Deckenstile: immutable Patch eines Deckentyps — analog `patchWallType`.
|
||||
const patchCeilingType = (id: string, patch: Partial<CeilingType>) =>
|
||||
setProject((p) => ({
|
||||
...p,
|
||||
ceilingTypes: (p.ceilingTypes ?? []).map((ct) =>
|
||||
ct.id === id ? { ...ct, ...patch } : ct,
|
||||
),
|
||||
}));
|
||||
// Neuen Wandtyp anlegen: eine Default-Schicht (erstes Bauteil, 200 mm).
|
||||
const addWallType = () =>
|
||||
setProject((p) => {
|
||||
const componentId = p.components[0]?.id ?? "";
|
||||
const wallType: WallType = {
|
||||
id: `wt-${Date.now()}`,
|
||||
name: t("default.wallTypeName"),
|
||||
layers: [{ componentId, thickness: 0.2 }],
|
||||
};
|
||||
return { ...p, wallTypes: [...p.wallTypes, wallType] };
|
||||
});
|
||||
// Wandtyp löschen — geschützt, solange ihn eine Wand verwendet.
|
||||
const deleteWallType = (id: string) =>
|
||||
setProject((p) => {
|
||||
const used = p.walls.some((w) => w.wallTypeId === id);
|
||||
if (used) {
|
||||
const name = p.wallTypes.find((wt) => wt.id === id)?.name ?? id;
|
||||
notify(t("alert.wallTypeInUse", { name }), "warning");
|
||||
return p;
|
||||
}
|
||||
return { ...p, wallTypes: p.wallTypes.filter((wt) => wt.id !== id) };
|
||||
});
|
||||
// Neuen Deckentyp anlegen — analog `addWallType` (150 mm Default).
|
||||
const addCeilingType = () =>
|
||||
setProject((p) => {
|
||||
const componentId = p.components[0]?.id ?? "";
|
||||
const ceilingType: CeilingType = {
|
||||
id: `ct-${Date.now()}`,
|
||||
name: t("default.ceilingTypeName"),
|
||||
layers: [{ componentId, thickness: 0.15 }],
|
||||
};
|
||||
return { ...p, ceilingTypes: [...(p.ceilingTypes ?? []), ceilingType] };
|
||||
});
|
||||
// Deckentyp löschen — geschützt, solange ihn eine Decke verwendet.
|
||||
const deleteCeilingType = (id: string) =>
|
||||
setProject((p) => {
|
||||
const used = (p.ceilings ?? []).some((c) => c.ceilingTypeId === id);
|
||||
if (used) {
|
||||
const name = (p.ceilingTypes ?? []).find((ct) => ct.id === id)?.name ?? id;
|
||||
notify(t("alert.ceilingTypeInUse", { name }), "warning");
|
||||
return p;
|
||||
}
|
||||
return {
|
||||
...p,
|
||||
ceilingTypes: (p.ceilingTypes ?? []).filter((ct) => ct.id !== id),
|
||||
};
|
||||
});
|
||||
// ── Dachtypen (Dachaufbauten) — analog Deckentyp ──────────────────────────
|
||||
const patchRoofType = (id: string, patch: Partial<RoofType>) =>
|
||||
setProject((p) => ({
|
||||
...p,
|
||||
roofTypes: (p.roofTypes ?? []).map((rt) => (rt.id === id ? { ...rt, ...patch } : rt)),
|
||||
}));
|
||||
const addRoofType = () =>
|
||||
setProject((p) => {
|
||||
const componentId = p.components[0]?.id ?? "";
|
||||
const roofType: RoofType = {
|
||||
id: `rt-${Date.now()}`,
|
||||
name: t("default.roofTypeName"),
|
||||
layers: [{ componentId, thickness: 0.2 }],
|
||||
};
|
||||
return { ...p, roofTypes: [...(p.roofTypes ?? []), roofType] };
|
||||
});
|
||||
// Dachtyp löschen — geschützt, solange ihn ein Dach verwendet.
|
||||
const deleteRoofType = (id: string) =>
|
||||
setProject((p) => {
|
||||
const used = (p.roofs ?? []).some((r) => r.roofTypeId === id);
|
||||
if (used) {
|
||||
const name = (p.roofTypes ?? []).find((rt) => rt.id === id)?.name ?? id;
|
||||
notify(t("alert.roofTypeInUse", { name }), "warning");
|
||||
return p;
|
||||
}
|
||||
return { ...p, roofTypes: (p.roofTypes ?? []).filter((rt) => rt.id !== id) };
|
||||
});
|
||||
// ── Bauteil-Typen: Tür / Fenster / Treppe (Bibliothek) ────────────────────
|
||||
// Anlegen/Patchen/Löschen analog Wand-/Deckentyp — direkt über setProject
|
||||
// (kein eigener Slice). Löschen ist geschützt, solange ein Element den Typ
|
||||
// per `typeId` referenziert. Defaults orientieren sich an den Element-Inline-
|
||||
// Werten (Tür 0.9×2.0, Fenster 1.2×1.4 Brüstung 0.9).
|
||||
const addDoorType = () =>
|
||||
setProject((p) => {
|
||||
const dt: DoorType = {
|
||||
id: `dt-${Date.now()}`,
|
||||
name: t("default.doorTypeName"),
|
||||
kind: "dreh",
|
||||
leafCount: 1,
|
||||
leafStyle: "glatt",
|
||||
frameThickness: 0.05,
|
||||
defaultWidth: 0.9,
|
||||
defaultHeight: 2.0,
|
||||
};
|
||||
return { ...p, doorTypes: [...(p.doorTypes ?? []), dt] };
|
||||
});
|
||||
const patchDoorType = (id: string, patch: Partial<DoorType>) =>
|
||||
setProject((p) => ({
|
||||
...p,
|
||||
doorTypes: (p.doorTypes ?? []).map((dt) =>
|
||||
dt.id === id ? { ...dt, ...patch } : dt,
|
||||
),
|
||||
}));
|
||||
const deleteDoorType = (id: string) =>
|
||||
setProject((p) => {
|
||||
const used = (p.openings ?? []).some((o) => o.typeId === id);
|
||||
if (used) {
|
||||
const name = (p.doorTypes ?? []).find((dt) => dt.id === id)?.name ?? id;
|
||||
notify(t("alert.doorTypeInUse", { name }), "warning");
|
||||
return p;
|
||||
}
|
||||
return { ...p, doorTypes: (p.doorTypes ?? []).filter((dt) => dt.id !== id) };
|
||||
});
|
||||
const addWindowType = () =>
|
||||
setProject((p) => {
|
||||
const wt: WindowType = {
|
||||
id: `ft-${Date.now()}`,
|
||||
name: t("default.windowTypeName"),
|
||||
kind: "drehkipp",
|
||||
wingCount: 1,
|
||||
glazing: "zweifach",
|
||||
frameThickness: 0.06,
|
||||
defaultSillHeight: 0.9,
|
||||
defaultWidth: 1.2,
|
||||
defaultHeight: 1.4,
|
||||
};
|
||||
return { ...p, windowTypes: [...(p.windowTypes ?? []), wt] };
|
||||
});
|
||||
const patchWindowType = (id: string, patch: Partial<WindowType>) =>
|
||||
setProject((p) => ({
|
||||
...p,
|
||||
windowTypes: (p.windowTypes ?? []).map((wt) =>
|
||||
wt.id === id ? { ...wt, ...patch } : wt,
|
||||
),
|
||||
}));
|
||||
const deleteWindowType = (id: string) =>
|
||||
setProject((p) => {
|
||||
const used = (p.openings ?? []).some((o) => o.typeId === id);
|
||||
if (used) {
|
||||
const name = (p.windowTypes ?? []).find((wt) => wt.id === id)?.name ?? id;
|
||||
notify(t("alert.windowTypeInUse", { name }), "warning");
|
||||
return p;
|
||||
}
|
||||
return {
|
||||
...p,
|
||||
windowTypes: (p.windowTypes ?? []).filter((wt) => wt.id !== id),
|
||||
};
|
||||
});
|
||||
// „Als Stil speichern": aktuellen Fenster-/Tür-Typ der Öffnung als NEUEN
|
||||
// benannten Stil ablegen und der Öffnung zuweisen (VW „Fenster speichern…").
|
||||
// Ohne Bezugstyp wird aus den Default-Feldern ein frischer Stil erzeugt.
|
||||
const saveOpeningStyle = (openingId: string, name: string) =>
|
||||
setProject((p) => {
|
||||
const o = (p.openings ?? []).find((x) => x.id === openingId);
|
||||
if (!o) return p;
|
||||
if (o.kind === "door") {
|
||||
const base = (p.doorTypes ?? []).find((d) => d.id === o.typeId);
|
||||
const nt: DoorType = base
|
||||
? { ...base, id: `dt-${Date.now()}`, name }
|
||||
: {
|
||||
id: `dt-${Date.now()}`,
|
||||
name,
|
||||
kind: "dreh",
|
||||
leafCount: 1,
|
||||
leafStyle: "glatt",
|
||||
frameThickness: 0.05,
|
||||
defaultWidth: 0.9,
|
||||
defaultHeight: 2.0,
|
||||
};
|
||||
return {
|
||||
...p,
|
||||
doorTypes: [...(p.doorTypes ?? []), nt],
|
||||
openings: (p.openings ?? []).map((x) =>
|
||||
x.id === openingId ? { ...x, typeId: nt.id } : x,
|
||||
),
|
||||
};
|
||||
}
|
||||
const base = (p.windowTypes ?? []).find((w) => w.id === o.typeId);
|
||||
const nt: WindowType = base
|
||||
? { ...base, id: `ft-${Date.now()}`, name }
|
||||
: {
|
||||
id: `ft-${Date.now()}`,
|
||||
name,
|
||||
kind: "drehkipp",
|
||||
wingCount: 1,
|
||||
glazing: "zweifach",
|
||||
frameThickness: 0.06,
|
||||
defaultSillHeight: 0.9,
|
||||
defaultWidth: 1.2,
|
||||
defaultHeight: 1.4,
|
||||
};
|
||||
return {
|
||||
...p,
|
||||
windowTypes: [...(p.windowTypes ?? []), nt],
|
||||
openings: (p.openings ?? []).map((x) =>
|
||||
x.id === openingId ? { ...x, typeId: nt.id } : x,
|
||||
),
|
||||
};
|
||||
});
|
||||
const addStairType = () =>
|
||||
setProject((p) => {
|
||||
const st: StairType = {
|
||||
id: `st-${Date.now()}`,
|
||||
name: t("default.stairTypeName"),
|
||||
structure: "massiv",
|
||||
closedRisers: true,
|
||||
treadThickness: 0.04,
|
||||
nosing: 0.03,
|
||||
railing: "keine",
|
||||
defaultWidth: 1.0,
|
||||
};
|
||||
return { ...p, stairTypes: [...(p.stairTypes ?? []), st] };
|
||||
});
|
||||
const patchStairType = (id: string, patch: Partial<StairType>) =>
|
||||
setProject((p) => ({
|
||||
...p,
|
||||
stairTypes: (p.stairTypes ?? []).map((st) =>
|
||||
st.id === id ? { ...st, ...patch } : st,
|
||||
),
|
||||
}));
|
||||
const deleteStairType = (id: string) =>
|
||||
setProject((p) => {
|
||||
const used = (p.stairs ?? []).some((s) => s.typeId === id);
|
||||
if (used) {
|
||||
const name = (p.stairTypes ?? []).find((st) => st.id === id)?.name ?? id;
|
||||
notify(t("alert.stairTypeInUse", { name }), "warning");
|
||||
return p;
|
||||
}
|
||||
return { ...p, stairTypes: (p.stairTypes ?? []).filter((st) => st.id !== id) };
|
||||
});
|
||||
const importLineStyles = useStore((s) => s.importLineStyles);
|
||||
const importHatches = useStore((s) => s.importHatches);
|
||||
// Site-/Kontext-Schicht (siteSlice): Import/Entfernen/Gelände.
|
||||
const addContextObjects = useStore((s) => s.addContextObjects);
|
||||
// Wie addContextObjects, aber passt die Plan-Ansicht danach auf die Bounding-
|
||||
// Box der NEU importierten Objekte ein (Auto-Zoom auf Import, ROADMAP §11) —
|
||||
// sonst muss man nach Standort-/Geo-Import manuell zur Geometrie suchen.
|
||||
const addContextObjectsAndFit = (objs: ContextObject[]) => {
|
||||
addContextObjects(objs);
|
||||
const pts = contextObjectsBounds(objs);
|
||||
if (pts) planViewRef.current?.fitBounds(pts);
|
||||
};
|
||||
const removeContextObject = useStore((s) => s.removeContextObject);
|
||||
const removeContextObjects = useStore((s) => s.removeContextObjects);
|
||||
const generateTerrain = useStore((s) => s.generateTerrain);
|
||||
const moveGripOf = useStore((s) => s.moveGripOf);
|
||||
const moveElementByOf = useStore((s) => s.moveElementByOf);
|
||||
const moveEdgeOf = useStore((s) => s.moveEdgeOf);
|
||||
const commitTransformOn = useStore((s) => s.commitTransformOn);
|
||||
const setElementColor = useStore((s) => s.setElementColor);
|
||||
const setElementWeight = useStore((s) => s.setElementWeight);
|
||||
const setElementFill = useStore((s) => s.setElementFill);
|
||||
const setElementFillColor = useStore((s) => s.setElementFillColor);
|
||||
const setElementForeground = useStore((s) => s.setElementForeground);
|
||||
const setElementBackground = useStore((s) => s.setElementBackground);
|
||||
const updateDrawing2D = useStore((s) => s.updateDrawing2D);
|
||||
const reorderDrawings = useStore((s) => s.reorderDrawings);
|
||||
const resizeElement = useStore((s) => s.resizeElement);
|
||||
const updateWall = useStore((s) => s.updateWall);
|
||||
const setWallThickness = useStore((s) => s.setWallThickness);
|
||||
const updateOpening = useStore((s) => s.updateOpening);
|
||||
const moveCeilingGrip = useStore((s) => s.moveCeilingGrip);
|
||||
const moveCeilingBy = useStore((s) => s.moveCeilingBy);
|
||||
const moveCeilingEdge = useStore((s) => s.moveCeilingEdge);
|
||||
const updateCeiling = useStore((s) => s.updateCeiling);
|
||||
const setCeilingThickness = useStore((s) => s.setCeilingThickness);
|
||||
const updateStair = useStore((s) => s.updateStair);
|
||||
const moveStairBy = useStore((s) => s.moveStairBy);
|
||||
const updateRoom = useStore((s) => s.updateRoom);
|
||||
const moveRoomBy = useStore((s) => s.moveRoomBy);
|
||||
const moveRoomGrip = useStore((s) => s.moveRoomGrip);
|
||||
const moveRoomEdge = useStore((s) => s.moveRoomEdge);
|
||||
const moveRoomStamp = useStore((s) => s.moveRoomStamp);
|
||||
const setRoomStampDoc = useStore((s) => s.setRoomStampDoc);
|
||||
const setRoomStamp = useStore((s) => s.setRoomStamp);
|
||||
// Sämtliche immutablen Projekt-Mutationen + Ressourcen-Typ-CRUD (Wand-/
|
||||
// Decken-/Dach-/Tür-/Fenster-/Treppentyp) in useProjectActions() gebündelt,
|
||||
// siehe dort.
|
||||
const {
|
||||
toggleLevelVisible,
|
||||
toggleCategoryVisible,
|
||||
addFloor,
|
||||
addDrawing,
|
||||
addSection,
|
||||
addElevation,
|
||||
addDrawingLevel,
|
||||
importDrawings,
|
||||
addCategory,
|
||||
patchCategory,
|
||||
addSubCategory,
|
||||
duplicateCategory,
|
||||
deleteCategory,
|
||||
assignWallCategory,
|
||||
snapshotLayerVisibility,
|
||||
applyLayerVisibility,
|
||||
snapshotDrawingVisibility,
|
||||
applyDrawingVisibility,
|
||||
patchLevel,
|
||||
duplicateLevel,
|
||||
deleteLevel,
|
||||
patchComponent,
|
||||
addComponent,
|
||||
deleteComponent,
|
||||
patchHatch,
|
||||
addHatch,
|
||||
deleteHatch,
|
||||
patchLineStyle,
|
||||
addLineStyle,
|
||||
deleteLineStyle,
|
||||
patchWallType,
|
||||
setOverrideRules,
|
||||
patchCeilingType,
|
||||
addWallType,
|
||||
deleteWallType,
|
||||
addCeilingType,
|
||||
deleteCeilingType,
|
||||
patchRoofType,
|
||||
addRoofType,
|
||||
deleteRoofType,
|
||||
addDoorType,
|
||||
patchDoorType,
|
||||
deleteDoorType,
|
||||
addWindowType,
|
||||
patchWindowType,
|
||||
deleteWindowType,
|
||||
saveOpeningStyle,
|
||||
addStairType,
|
||||
patchStairType,
|
||||
deleteStairType,
|
||||
importLineStyles,
|
||||
importHatches,
|
||||
addContextObjects,
|
||||
addContextObjectsAndFit,
|
||||
removeContextObject,
|
||||
removeContextObjects,
|
||||
generateTerrain,
|
||||
moveGripOf,
|
||||
moveElementByOf,
|
||||
moveEdgeOf,
|
||||
commitTransformOn,
|
||||
setElementColor,
|
||||
setElementWeight,
|
||||
setElementFill,
|
||||
setElementFillColor,
|
||||
setElementForeground,
|
||||
setElementBackground,
|
||||
updateDrawing2D,
|
||||
reorderDrawings,
|
||||
resizeElement,
|
||||
updateWall,
|
||||
setWallThickness,
|
||||
updateOpening,
|
||||
moveCeilingGrip,
|
||||
moveCeilingBy,
|
||||
moveCeilingEdge,
|
||||
updateCeiling,
|
||||
setCeilingThickness,
|
||||
updateStair,
|
||||
moveStairBy,
|
||||
updateRoom,
|
||||
moveRoomBy,
|
||||
moveRoomGrip,
|
||||
moveRoomEdge,
|
||||
moveRoomStamp,
|
||||
setRoomStampDoc,
|
||||
setRoomStamp,
|
||||
} = useProjectActions(setProject, notify, planViewRef);
|
||||
|
||||
// Text-Ziel der Oberleisten-Text-Gruppe: der Stempel-Text des (einzeln)
|
||||
// gewählten Raums. Ohne aktive Editor-Auswahl wirkt Formatierung auf das ganze
|
||||
|
||||
@@ -0,0 +1,484 @@
|
||||
// Bündelt Projekt-Mutationen als (referenzstabile) Store-Actions plus die
|
||||
// Ressourcen-Typ-CRUD (Wand-/Decken-/Dach-/Tür-/Fenster-/Treppentyp), die
|
||||
// direkt über `setProject` laufen (kein eigener Slice). Löschen ist je Typ
|
||||
// geschützt, solange ein Element ihn per `typeId`/`wallTypeId`/… referenziert.
|
||||
// Nur aus App() herausgezogen, um die Funktion zu entlasten — reine
|
||||
// Zustands-/Aktions-Bündelung, keine Verhaltensänderung.
|
||||
//
|
||||
// Extrahiert aus App.tsx. Bezeichner englisch, Kommentare deutsch (CONVENTIONS.md).
|
||||
|
||||
import type { RefObject } from "react";
|
||||
import { useStore } from "./appStore";
|
||||
import { t } from "../i18n";
|
||||
import type {
|
||||
CeilingType,
|
||||
ContextObject,
|
||||
DoorType,
|
||||
OverrideRule,
|
||||
Project,
|
||||
RoofType,
|
||||
StairType,
|
||||
Vec2,
|
||||
WallType,
|
||||
WindowType,
|
||||
} from "../model/types";
|
||||
import type { PlanViewHandle } from "../plan/PlanView";
|
||||
import type { NotifyKind } from "./notifySlice";
|
||||
|
||||
/**
|
||||
* Bounding-Box (Modell-Meter) neu importierter Kontext-Objekte (Konturen/
|
||||
* Meshes/Terrain, z. B. aus dem Standort-Import-Dialog), als zwei Eckpunkte
|
||||
* für `PlanViewHandle.fitBounds` (Auto-Zoom auf Import). Ignoriert die
|
||||
* Z-Achse (reine 2D-Projektion, wie die Plan-Darstellung der Kontext-
|
||||
* Konturen in generatePlan.ts). Leere/degenerierte Eingabe → null.
|
||||
*/
|
||||
function contextObjectsBounds(objs: ContextObject[]): Vec2[] | null {
|
||||
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
||||
const acc = (x: number, y: number) => {
|
||||
minX = Math.min(minX, x); minY = Math.min(minY, y);
|
||||
maxX = Math.max(maxX, x); maxY = Math.max(maxY, y);
|
||||
};
|
||||
for (const obj of objs) {
|
||||
if (obj.type === "contourSet") {
|
||||
for (const c of obj.contours) for (const p of c.pts) acc(p.x, p.y);
|
||||
} else if (obj.type === "image") {
|
||||
acc(obj.min.x, obj.min.y);
|
||||
acc(obj.max.x, obj.max.y);
|
||||
} else {
|
||||
// importedMesh / terrainMesh: flaches (x,y,z…)-Array, Stride 3.
|
||||
const pos = obj.positions;
|
||||
for (let i = 0; i + 1 < pos.length; i += 3) acc(pos[i], pos[i + 1]);
|
||||
}
|
||||
}
|
||||
return Number.isFinite(minX)
|
||||
? [{ x: minX, y: minY }, { x: maxX, y: maxY }]
|
||||
: null;
|
||||
}
|
||||
|
||||
export function useProjectActions(
|
||||
// `setProject`/`notify` kommen als Parameter herein statt erneut via
|
||||
// useStore geholt zu werden: beide werden schon früher in App() gebraucht
|
||||
// (Command-Engine/Grips, vor dieser Sektion) und bleiben dort deklariert —
|
||||
// sonst gäbe es die Store-Action zweimal (Duplikat-Deklaration in App()).
|
||||
setProject: (next: Project | ((p: Project) => Project)) => void,
|
||||
notify: (message: string, kind?: NotifyKind) => void,
|
||||
planViewRef: RefObject<PlanViewHandle | null>,
|
||||
) {
|
||||
// ── Projekt-Mutationen (aus dem Store-Slice) ─────────────────────────────
|
||||
// Sämtliche immutablen Projekt-Mutationen liegen jetzt in projectSlice. App
|
||||
// liest sie als (referenzstabile) Store-Actions und reicht sie unverändert an
|
||||
// Panels/Menüs/Editoren weiter.
|
||||
const toggleLevelVisible = useStore((s) => s.toggleLevelVisible);
|
||||
const toggleCategoryVisible = useStore((s) => s.toggleCategoryVisible);
|
||||
const addFloor = useStore((s) => s.addFloor);
|
||||
const addDrawing = useStore((s) => s.addDrawing);
|
||||
const addSection = useStore((s) => s.addSection);
|
||||
const addElevation = useStore((s) => s.addElevation);
|
||||
const addDrawingLevel = useStore((s) => s.addDrawingLevel);
|
||||
const importDrawings = useStore((s) => s.importDrawings);
|
||||
const addCategory = useStore((s) => s.addCategory);
|
||||
const patchCategory = useStore((s) => s.patchCategory);
|
||||
const addSubCategory = useStore((s) => s.addSubCategory);
|
||||
const duplicateCategory = useStore((s) => s.duplicateCategory);
|
||||
const deleteCategory = useStore((s) => s.deleteCategory);
|
||||
const assignWallCategory = useStore((s) => s.assignWallCategory);
|
||||
const snapshotLayerVisibility = useStore((s) => s.snapshotLayerVisibility);
|
||||
const applyLayerVisibility = useStore((s) => s.applyLayerVisibility);
|
||||
const snapshotDrawingVisibility = useStore((s) => s.snapshotDrawingVisibility);
|
||||
const applyDrawingVisibility = useStore((s) => s.applyDrawingVisibility);
|
||||
const patchLevel = useStore((s) => s.patchLevel);
|
||||
const duplicateLevel = useStore((s) => s.duplicateLevel);
|
||||
const deleteLevel = useStore((s) => s.deleteLevel);
|
||||
const patchComponent = useStore((s) => s.patchComponent);
|
||||
const addComponent = useStore((s) => s.addComponent);
|
||||
const deleteComponent = useStore((s) => s.deleteComponent);
|
||||
const patchHatch = useStore((s) => s.patchHatch);
|
||||
const addHatch = useStore((s) => s.addHatch);
|
||||
const deleteHatch = useStore((s) => s.deleteHatch);
|
||||
const patchLineStyle = useStore((s) => s.patchLineStyle);
|
||||
const addLineStyle = useStore((s) => s.addLineStyle);
|
||||
const deleteLineStyle = useStore((s) => s.deleteLineStyle);
|
||||
// Wandstile: immutable Patch eines Wandtyps (z. B. Schichtfugen-Stile). Kein
|
||||
// eigener Store-Slice nötig — läuft direkt über setProject wie die übrigen
|
||||
// Ressourcen-Mutationen.
|
||||
const patchWallType = (id: string, patch: Partial<WallType>) =>
|
||||
setProject((p) => ({
|
||||
...p,
|
||||
wallTypes: p.wallTypes.map((wt) => (wt.id === id ? { ...wt, ...patch } : wt)),
|
||||
}));
|
||||
// Grafische Override-Regeln: ersetzt die ganze Regelliste (Reihenfolge =
|
||||
// Priorität, oben gewinnt). Läuft wie die übrigen Ressourcen-Mutationen
|
||||
// direkt über setProject — persistiert damit automatisch im Projekt-JSON.
|
||||
const setOverrideRules = (rules: OverrideRule[]) =>
|
||||
setProject((p) => ({ ...p, overrideRules: rules }));
|
||||
// Deckenstile: immutable Patch eines Deckentyps — analog `patchWallType`.
|
||||
const patchCeilingType = (id: string, patch: Partial<CeilingType>) =>
|
||||
setProject((p) => ({
|
||||
...p,
|
||||
ceilingTypes: (p.ceilingTypes ?? []).map((ct) =>
|
||||
ct.id === id ? { ...ct, ...patch } : ct,
|
||||
),
|
||||
}));
|
||||
// Neuen Wandtyp anlegen: eine Default-Schicht (erstes Bauteil, 200 mm).
|
||||
const addWallType = () =>
|
||||
setProject((p) => {
|
||||
const componentId = p.components[0]?.id ?? "";
|
||||
const wallType: WallType = {
|
||||
id: `wt-${Date.now()}`,
|
||||
name: t("default.wallTypeName"),
|
||||
layers: [{ componentId, thickness: 0.2 }],
|
||||
};
|
||||
return { ...p, wallTypes: [...p.wallTypes, wallType] };
|
||||
});
|
||||
// Wandtyp löschen — geschützt, solange ihn eine Wand verwendet.
|
||||
const deleteWallType = (id: string) =>
|
||||
setProject((p) => {
|
||||
const used = p.walls.some((w) => w.wallTypeId === id);
|
||||
if (used) {
|
||||
const name = p.wallTypes.find((wt) => wt.id === id)?.name ?? id;
|
||||
notify(t("alert.wallTypeInUse", { name }), "warning");
|
||||
return p;
|
||||
}
|
||||
return { ...p, wallTypes: p.wallTypes.filter((wt) => wt.id !== id) };
|
||||
});
|
||||
// Neuen Deckentyp anlegen — analog `addWallType` (150 mm Default).
|
||||
const addCeilingType = () =>
|
||||
setProject((p) => {
|
||||
const componentId = p.components[0]?.id ?? "";
|
||||
const ceilingType: CeilingType = {
|
||||
id: `ct-${Date.now()}`,
|
||||
name: t("default.ceilingTypeName"),
|
||||
layers: [{ componentId, thickness: 0.15 }],
|
||||
};
|
||||
return { ...p, ceilingTypes: [...(p.ceilingTypes ?? []), ceilingType] };
|
||||
});
|
||||
// Deckentyp löschen — geschützt, solange ihn eine Decke verwendet.
|
||||
const deleteCeilingType = (id: string) =>
|
||||
setProject((p) => {
|
||||
const used = (p.ceilings ?? []).some((c) => c.ceilingTypeId === id);
|
||||
if (used) {
|
||||
const name = (p.ceilingTypes ?? []).find((ct) => ct.id === id)?.name ?? id;
|
||||
notify(t("alert.ceilingTypeInUse", { name }), "warning");
|
||||
return p;
|
||||
}
|
||||
return {
|
||||
...p,
|
||||
ceilingTypes: (p.ceilingTypes ?? []).filter((ct) => ct.id !== id),
|
||||
};
|
||||
});
|
||||
// ── Dachtypen (Dachaufbauten) — analog Deckentyp ──────────────────────────
|
||||
const patchRoofType = (id: string, patch: Partial<RoofType>) =>
|
||||
setProject((p) => ({
|
||||
...p,
|
||||
roofTypes: (p.roofTypes ?? []).map((rt) => (rt.id === id ? { ...rt, ...patch } : rt)),
|
||||
}));
|
||||
const addRoofType = () =>
|
||||
setProject((p) => {
|
||||
const componentId = p.components[0]?.id ?? "";
|
||||
const roofType: RoofType = {
|
||||
id: `rt-${Date.now()}`,
|
||||
name: t("default.roofTypeName"),
|
||||
layers: [{ componentId, thickness: 0.2 }],
|
||||
};
|
||||
return { ...p, roofTypes: [...(p.roofTypes ?? []), roofType] };
|
||||
});
|
||||
// Dachtyp löschen — geschützt, solange ihn ein Dach verwendet.
|
||||
const deleteRoofType = (id: string) =>
|
||||
setProject((p) => {
|
||||
const used = (p.roofs ?? []).some((r) => r.roofTypeId === id);
|
||||
if (used) {
|
||||
const name = (p.roofTypes ?? []).find((rt) => rt.id === id)?.name ?? id;
|
||||
notify(t("alert.roofTypeInUse", { name }), "warning");
|
||||
return p;
|
||||
}
|
||||
return { ...p, roofTypes: (p.roofTypes ?? []).filter((rt) => rt.id !== id) };
|
||||
});
|
||||
// ── Bauteil-Typen: Tür / Fenster / Treppe (Bibliothek) ────────────────────
|
||||
// Anlegen/Patchen/Löschen analog Wand-/Deckentyp — direkt über setProject
|
||||
// (kein eigener Slice). Löschen ist geschützt, solange ein Element den Typ
|
||||
// per `typeId` referenziert. Defaults orientieren sich an den Element-Inline-
|
||||
// Werten (Tür 0.9×2.0, Fenster 1.2×1.4 Brüstung 0.9).
|
||||
const addDoorType = () =>
|
||||
setProject((p) => {
|
||||
const dt: DoorType = {
|
||||
id: `dt-${Date.now()}`,
|
||||
name: t("default.doorTypeName"),
|
||||
kind: "dreh",
|
||||
leafCount: 1,
|
||||
leafStyle: "glatt",
|
||||
frameThickness: 0.05,
|
||||
defaultWidth: 0.9,
|
||||
defaultHeight: 2.0,
|
||||
};
|
||||
return { ...p, doorTypes: [...(p.doorTypes ?? []), dt] };
|
||||
});
|
||||
const patchDoorType = (id: string, patch: Partial<DoorType>) =>
|
||||
setProject((p) => ({
|
||||
...p,
|
||||
doorTypes: (p.doorTypes ?? []).map((dt) =>
|
||||
dt.id === id ? { ...dt, ...patch } : dt,
|
||||
),
|
||||
}));
|
||||
const deleteDoorType = (id: string) =>
|
||||
setProject((p) => {
|
||||
const used = (p.openings ?? []).some((o) => o.typeId === id);
|
||||
if (used) {
|
||||
const name = (p.doorTypes ?? []).find((dt) => dt.id === id)?.name ?? id;
|
||||
notify(t("alert.doorTypeInUse", { name }), "warning");
|
||||
return p;
|
||||
}
|
||||
return { ...p, doorTypes: (p.doorTypes ?? []).filter((dt) => dt.id !== id) };
|
||||
});
|
||||
const addWindowType = () =>
|
||||
setProject((p) => {
|
||||
const wt: WindowType = {
|
||||
id: `ft-${Date.now()}`,
|
||||
name: t("default.windowTypeName"),
|
||||
kind: "drehkipp",
|
||||
wingCount: 1,
|
||||
glazing: "zweifach",
|
||||
frameThickness: 0.06,
|
||||
defaultSillHeight: 0.9,
|
||||
defaultWidth: 1.2,
|
||||
defaultHeight: 1.4,
|
||||
};
|
||||
return { ...p, windowTypes: [...(p.windowTypes ?? []), wt] };
|
||||
});
|
||||
const patchWindowType = (id: string, patch: Partial<WindowType>) =>
|
||||
setProject((p) => ({
|
||||
...p,
|
||||
windowTypes: (p.windowTypes ?? []).map((wt) =>
|
||||
wt.id === id ? { ...wt, ...patch } : wt,
|
||||
),
|
||||
}));
|
||||
const deleteWindowType = (id: string) =>
|
||||
setProject((p) => {
|
||||
const used = (p.openings ?? []).some((o) => o.typeId === id);
|
||||
if (used) {
|
||||
const name = (p.windowTypes ?? []).find((wt) => wt.id === id)?.name ?? id;
|
||||
notify(t("alert.windowTypeInUse", { name }), "warning");
|
||||
return p;
|
||||
}
|
||||
return {
|
||||
...p,
|
||||
windowTypes: (p.windowTypes ?? []).filter((wt) => wt.id !== id),
|
||||
};
|
||||
});
|
||||
// „Als Stil speichern": aktuellen Fenster-/Tür-Typ der Öffnung als NEUEN
|
||||
// benannten Stil ablegen und der Öffnung zuweisen (VW „Fenster speichern…").
|
||||
// Ohne Bezugstyp wird aus den Default-Feldern ein frischer Stil erzeugt.
|
||||
const saveOpeningStyle = (openingId: string, name: string) =>
|
||||
setProject((p) => {
|
||||
const o = (p.openings ?? []).find((x) => x.id === openingId);
|
||||
if (!o) return p;
|
||||
if (o.kind === "door") {
|
||||
const base = (p.doorTypes ?? []).find((d) => d.id === o.typeId);
|
||||
const nt: DoorType = base
|
||||
? { ...base, id: `dt-${Date.now()}`, name }
|
||||
: {
|
||||
id: `dt-${Date.now()}`,
|
||||
name,
|
||||
kind: "dreh",
|
||||
leafCount: 1,
|
||||
leafStyle: "glatt",
|
||||
frameThickness: 0.05,
|
||||
defaultWidth: 0.9,
|
||||
defaultHeight: 2.0,
|
||||
};
|
||||
return {
|
||||
...p,
|
||||
doorTypes: [...(p.doorTypes ?? []), nt],
|
||||
openings: (p.openings ?? []).map((x) =>
|
||||
x.id === openingId ? { ...x, typeId: nt.id } : x,
|
||||
),
|
||||
};
|
||||
}
|
||||
const base = (p.windowTypes ?? []).find((w) => w.id === o.typeId);
|
||||
const nt: WindowType = base
|
||||
? { ...base, id: `ft-${Date.now()}`, name }
|
||||
: {
|
||||
id: `ft-${Date.now()}`,
|
||||
name,
|
||||
kind: "drehkipp",
|
||||
wingCount: 1,
|
||||
glazing: "zweifach",
|
||||
frameThickness: 0.06,
|
||||
defaultSillHeight: 0.9,
|
||||
defaultWidth: 1.2,
|
||||
defaultHeight: 1.4,
|
||||
};
|
||||
return {
|
||||
...p,
|
||||
windowTypes: [...(p.windowTypes ?? []), nt],
|
||||
openings: (p.openings ?? []).map((x) =>
|
||||
x.id === openingId ? { ...x, typeId: nt.id } : x,
|
||||
),
|
||||
};
|
||||
});
|
||||
const addStairType = () =>
|
||||
setProject((p) => {
|
||||
const st: StairType = {
|
||||
id: `st-${Date.now()}`,
|
||||
name: t("default.stairTypeName"),
|
||||
structure: "massiv",
|
||||
closedRisers: true,
|
||||
treadThickness: 0.04,
|
||||
nosing: 0.03,
|
||||
railing: "keine",
|
||||
defaultWidth: 1.0,
|
||||
};
|
||||
return { ...p, stairTypes: [...(p.stairTypes ?? []), st] };
|
||||
});
|
||||
const patchStairType = (id: string, patch: Partial<StairType>) =>
|
||||
setProject((p) => ({
|
||||
...p,
|
||||
stairTypes: (p.stairTypes ?? []).map((st) =>
|
||||
st.id === id ? { ...st, ...patch } : st,
|
||||
),
|
||||
}));
|
||||
const deleteStairType = (id: string) =>
|
||||
setProject((p) => {
|
||||
const used = (p.stairs ?? []).some((s) => s.typeId === id);
|
||||
if (used) {
|
||||
const name = (p.stairTypes ?? []).find((st) => st.id === id)?.name ?? id;
|
||||
notify(t("alert.stairTypeInUse", { name }), "warning");
|
||||
return p;
|
||||
}
|
||||
return { ...p, stairTypes: (p.stairTypes ?? []).filter((st) => st.id !== id) };
|
||||
});
|
||||
const importLineStyles = useStore((s) => s.importLineStyles);
|
||||
const importHatches = useStore((s) => s.importHatches);
|
||||
// Site-/Kontext-Schicht (siteSlice): Import/Entfernen/Gelände.
|
||||
const addContextObjects = useStore((s) => s.addContextObjects);
|
||||
// Wie addContextObjects, aber passt die Plan-Ansicht danach auf die Bounding-
|
||||
// Box der NEU importierten Objekte ein (Auto-Zoom auf Import, ROADMAP §11) —
|
||||
// sonst muss man nach Standort-/Geo-Import manuell zur Geometrie suchen.
|
||||
const addContextObjectsAndFit = (objs: ContextObject[]) => {
|
||||
addContextObjects(objs);
|
||||
const pts = contextObjectsBounds(objs);
|
||||
if (pts) planViewRef.current?.fitBounds(pts);
|
||||
};
|
||||
const removeContextObject = useStore((s) => s.removeContextObject);
|
||||
const removeContextObjects = useStore((s) => s.removeContextObjects);
|
||||
const generateTerrain = useStore((s) => s.generateTerrain);
|
||||
const moveGripOf = useStore((s) => s.moveGripOf);
|
||||
const moveElementByOf = useStore((s) => s.moveElementByOf);
|
||||
const moveEdgeOf = useStore((s) => s.moveEdgeOf);
|
||||
const commitTransformOn = useStore((s) => s.commitTransformOn);
|
||||
const setElementColor = useStore((s) => s.setElementColor);
|
||||
const setElementWeight = useStore((s) => s.setElementWeight);
|
||||
const setElementFill = useStore((s) => s.setElementFill);
|
||||
const setElementFillColor = useStore((s) => s.setElementFillColor);
|
||||
const setElementForeground = useStore((s) => s.setElementForeground);
|
||||
const setElementBackground = useStore((s) => s.setElementBackground);
|
||||
const updateDrawing2D = useStore((s) => s.updateDrawing2D);
|
||||
const reorderDrawings = useStore((s) => s.reorderDrawings);
|
||||
const resizeElement = useStore((s) => s.resizeElement);
|
||||
const updateWall = useStore((s) => s.updateWall);
|
||||
const setWallThickness = useStore((s) => s.setWallThickness);
|
||||
const updateOpening = useStore((s) => s.updateOpening);
|
||||
const moveCeilingGrip = useStore((s) => s.moveCeilingGrip);
|
||||
const moveCeilingBy = useStore((s) => s.moveCeilingBy);
|
||||
const moveCeilingEdge = useStore((s) => s.moveCeilingEdge);
|
||||
const updateCeiling = useStore((s) => s.updateCeiling);
|
||||
const setCeilingThickness = useStore((s) => s.setCeilingThickness);
|
||||
const updateStair = useStore((s) => s.updateStair);
|
||||
const moveStairBy = useStore((s) => s.moveStairBy);
|
||||
const updateRoom = useStore((s) => s.updateRoom);
|
||||
const moveRoomBy = useStore((s) => s.moveRoomBy);
|
||||
const moveRoomGrip = useStore((s) => s.moveRoomGrip);
|
||||
const moveRoomEdge = useStore((s) => s.moveRoomEdge);
|
||||
const moveRoomStamp = useStore((s) => s.moveRoomStamp);
|
||||
const setRoomStampDoc = useStore((s) => s.setRoomStampDoc);
|
||||
const setRoomStamp = useStore((s) => s.setRoomStamp);
|
||||
|
||||
return {
|
||||
toggleLevelVisible,
|
||||
toggleCategoryVisible,
|
||||
addFloor,
|
||||
addDrawing,
|
||||
addSection,
|
||||
addElevation,
|
||||
addDrawingLevel,
|
||||
importDrawings,
|
||||
addCategory,
|
||||
patchCategory,
|
||||
addSubCategory,
|
||||
duplicateCategory,
|
||||
deleteCategory,
|
||||
assignWallCategory,
|
||||
snapshotLayerVisibility,
|
||||
applyLayerVisibility,
|
||||
snapshotDrawingVisibility,
|
||||
applyDrawingVisibility,
|
||||
patchLevel,
|
||||
duplicateLevel,
|
||||
deleteLevel,
|
||||
patchComponent,
|
||||
addComponent,
|
||||
deleteComponent,
|
||||
patchHatch,
|
||||
addHatch,
|
||||
deleteHatch,
|
||||
patchLineStyle,
|
||||
addLineStyle,
|
||||
deleteLineStyle,
|
||||
patchWallType,
|
||||
setOverrideRules,
|
||||
patchCeilingType,
|
||||
addWallType,
|
||||
deleteWallType,
|
||||
addCeilingType,
|
||||
deleteCeilingType,
|
||||
patchRoofType,
|
||||
addRoofType,
|
||||
deleteRoofType,
|
||||
addDoorType,
|
||||
patchDoorType,
|
||||
deleteDoorType,
|
||||
addWindowType,
|
||||
patchWindowType,
|
||||
deleteWindowType,
|
||||
saveOpeningStyle,
|
||||
addStairType,
|
||||
patchStairType,
|
||||
deleteStairType,
|
||||
importLineStyles,
|
||||
importHatches,
|
||||
addContextObjects,
|
||||
addContextObjectsAndFit,
|
||||
removeContextObject,
|
||||
removeContextObjects,
|
||||
generateTerrain,
|
||||
moveGripOf,
|
||||
moveElementByOf,
|
||||
moveEdgeOf,
|
||||
commitTransformOn,
|
||||
setElementColor,
|
||||
setElementWeight,
|
||||
setElementFill,
|
||||
setElementFillColor,
|
||||
setElementForeground,
|
||||
setElementBackground,
|
||||
updateDrawing2D,
|
||||
reorderDrawings,
|
||||
resizeElement,
|
||||
updateWall,
|
||||
setWallThickness,
|
||||
updateOpening,
|
||||
moveCeilingGrip,
|
||||
moveCeilingBy,
|
||||
moveCeilingEdge,
|
||||
updateCeiling,
|
||||
setCeilingThickness,
|
||||
updateStair,
|
||||
moveStairBy,
|
||||
updateRoom,
|
||||
moveRoomBy,
|
||||
moveRoomGrip,
|
||||
moveRoomEdge,
|
||||
moveRoomStamp,
|
||||
setRoomStampDoc,
|
||||
setRoomStamp,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user