From fcd924eb313e6462c28b808b1951a8eda406ce25 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Tue, 29 Jul 2025 17:20:34 +0530 Subject: [PATCH] feat: Implement undo and redo functionality for 2D scene controls - Added useRedoHandler to manage redo actions, including socket communication for wall, floor, zone, and aisle updates. - Added useUndoHandler to manage undo actions, reversing the effects of previous actions with corresponding socket updates. - Created UndoRedo2DControls component to handle keyboard shortcuts for undo (Ctrl+Z) and redo (Ctrl+Y). - Established a Zustand store (useUndoRedo2DStore) to maintain undo and redo stacks, with methods for pushing, popping, and peeking actions. --- .../floor/floorCreator/floorCreator.tsx | 52 +- app/src/modules/builder/line/line.tsx | 92 +++- app/src/modules/builder/point/point.tsx | 203 ++++++- .../builder/wall/wallCreator/wallCreator.tsx | 86 ++- .../builder/zone/zoneCreator/zoneCreator.tsx | 52 +- app/src/modules/scene/controls/controls.tsx | 3 + .../handlers/useRedoHandler.ts | 355 ++++++++++++ .../handlers/useUndoHandler.ts | 356 ++++++++++++ .../undoRedo2D/undoRedo2DControls.tsx | 49 ++ app/src/modules/scene/sceneContext.tsx | 12 +- app/src/store/builder/useFloorStore.ts | 59 +- app/src/store/builder/useUndoRedo2DStore.ts | 78 +++ app/src/store/builder/useZoneStore.ts | 59 +- app/src/types/builderTypes.d.ts | 38 ++ app/src/types/world/worldConstants.ts | 508 +++++++++--------- 15 files changed, 1701 insertions(+), 301 deletions(-) create mode 100644 app/src/modules/scene/controls/undoRedoControls/handlers/useRedoHandler.ts create mode 100644 app/src/modules/scene/controls/undoRedoControls/handlers/useUndoHandler.ts create mode 100644 app/src/modules/scene/controls/undoRedoControls/undoRedo2D/undoRedo2DControls.tsx create mode 100644 app/src/store/builder/useUndoRedo2DStore.ts diff --git a/app/src/modules/builder/floor/floorCreator/floorCreator.tsx b/app/src/modules/builder/floor/floorCreator/floorCreator.tsx index acab425..28450aa 100644 --- a/app/src/modules/builder/floor/floorCreator/floorCreator.tsx +++ b/app/src/modules/builder/floor/floorCreator/floorCreator.tsx @@ -19,8 +19,9 @@ function FloorCreator() { const { toolMode } = useToolMode(); const { activeLayer } = useActiveLayer(); const { socket } = useSocketStore(); - const { floorStore } = useSceneContext(); - const { addFloor, getFloorPointById, getFloorByPoints } = floorStore(); + const { floorStore, undoRedo2DStore } = useSceneContext(); + const { addFloor, getFloorPointById } = floorStore(); + const { push2D } = undoRedo2DStore(); const drag = useRef(false); const isLeftMouseDown = useRef(false); const { selectedVersionStore } = useVersionContext(); @@ -103,6 +104,21 @@ function FloorCreator() { }; addFloor(floor); + + push2D({ + type: 'Draw', + actions: [ + { + actionType: 'Line-Create', + point: { + type: 'Floor', + lineData: floor, + timeStamp: new Date().toISOString(), + } + } + ], + }) + if (projectId) { // API @@ -142,6 +158,21 @@ function FloorCreator() { }; addFloor(floor); + + push2D({ + type: 'Draw', + actions: [ + { + actionType: 'Line-Create', + point: { + type: 'Floor', + lineData: floor, + timeStamp: new Date().toISOString(), + } + } + ], + }) + if (projectId) { // API @@ -191,6 +222,21 @@ function FloorCreator() { }; addFloor(floor); + + push2D({ + type: 'Draw', + actions: [ + { + actionType: 'Line-Create', + point: { + type: 'Floor', + lineData: floor, + timeStamp: new Date().toISOString(), + } + } + ], + }) + if (projectId) { // API @@ -243,7 +289,7 @@ function FloorCreator() { canvasElement.removeEventListener("click", onMouseClick); canvasElement.removeEventListener("contextmenu", onContext); }; - }, [gl, camera, scene, raycaster, pointer, plane, toggleView, toolMode, activeLayer, socket, tempPoints, isCreating, addFloor, getFloorPointById, getFloorByPoints, floorDepth, isBeveled, bevelStrength, sideMaterial, topMaterial, snappedPosition, snappedPoint]); + }, [gl, camera, scene, raycaster, pointer, plane, toggleView, toolMode, activeLayer, socket, tempPoints, isCreating, addFloor, getFloorPointById, floorDepth, isBeveled, bevelStrength, sideMaterial, topMaterial, snappedPosition, snappedPoint]); return ( <> diff --git a/app/src/modules/builder/line/line.tsx b/app/src/modules/builder/line/line.tsx index a0470aa..c9f5e9b 100644 --- a/app/src/modules/builder/line/line.tsx +++ b/app/src/modules/builder/line/line.tsx @@ -30,10 +30,11 @@ function Line({ points }: Readonly) { const [isDeletable, setIsDeletable] = useState(false); const { socket } = useSocketStore(); const { toolMode } = useToolMode(); - const { wallStore, floorStore, zoneStore } = useSceneContext(); + const { wallStore, floorStore, zoneStore, undoRedo2DStore } = useSceneContext(); + const { push2D } = undoRedo2DStore(); const { removeWallByPoints, setPosition: setWallPosition, getWallsByPointId } = wallStore(); - const { removeFloorByPoints, setPosition: setFloorPosition, getFloorsByPointId } = floorStore(); - const { removeZoneByPoints, setPosition: setZonePosition, getZonesByPointId } = zoneStore(); + const { removeFloorByPoints, setPosition: setFloorPosition, getFloorsByPointId, getFloorsByPoints } = floorStore(); + const { removeZoneByPoints, setPosition: setZonePosition, getZonesByPointId, getZonesByPoints } = zoneStore(); const { userId, organization } = getUserData(); const { selectedVersionStore } = useVersionContext(); const { selectedVersion } = selectedVersionStore(); @@ -117,10 +118,26 @@ function Line({ points }: Readonly) { } socket.emit('v1:model-Wall:delete', data); + + push2D({ + type: 'Draw', + actions: [ + { + actionType: 'Line-Delete', + point: { + type: 'Wall', + lineData: removedWall, + timeStamp: new Date().toISOString(), + } + } + ] + }); } + setHoveredLine(null); } if (points[0].pointType === 'Floor' && points[1].pointType === 'Floor') { + const Floors = getFloorsByPoints(points); const { removedFloors, updatedFloors } = removeFloorByPoints(points); if (removedFloors.length > 0) { removedFloors.forEach(floor => { @@ -143,6 +160,22 @@ function Line({ points }: Readonly) { socket.emit('v1:model-Floor:delete', data); } }); + + const removedFloorsData = removedFloors.map((floor) => ({ + type: "Floor" as const, + lineData: floor, + timeStamp: new Date().toISOString(), + })); + + push2D({ + type: 'Draw', + actions: [ + { + actionType: 'Lines-Delete', + points: removedFloorsData + } + ] + }); } if (updatedFloors.length > 0) { updatedFloors.forEach(floor => { @@ -165,11 +198,29 @@ function Line({ points }: Readonly) { socket.emit('v1:model-Floor:add', data); } }); + + const updatedFloorsData = updatedFloors.map((floor) => ({ + type: "Floor" as const, + lineData: Floors.find(f => f.floorUuid === floor.floorUuid) || floor, + newData: floor, + timeStamp: new Date().toISOString(), + })); + + push2D({ + type: 'Draw', + actions: [ + { + actionType: 'Lines-Update', + points: updatedFloorsData + } + ] + }); } setHoveredLine(null); } if (points[0].pointType === 'Zone' && points[1].pointType === 'Zone') { + const Zones = getZonesByPoints(points); const { removedZones, updatedZones } = removeZoneByPoints(points); if (removedZones.length > 0) { removedZones.forEach(zone => { @@ -192,6 +243,22 @@ function Line({ points }: Readonly) { socket.emit('v1:zone:delete', data); } }); + + const removedZonesData = removedZones.map((zone) => ({ + type: "Zone" as const, + lineData: zone, + timeStamp: new Date().toISOString(), + })); + + push2D({ + type: 'Draw', + actions: [ + { + actionType: 'Lines-Delete', + points: removedZonesData + } + ] + }); } if (updatedZones.length > 0) { updatedZones.forEach(zone => { @@ -214,7 +281,26 @@ function Line({ points }: Readonly) { socket.emit('v1:zone:add', data); } }); + + const updatedZonesData = updatedZones.map((zone) => ({ + type: "Zone" as const, + lineData: Zones.find(z => z.zoneUuid === zone.zoneUuid) || zone, + newData: zone, + timeStamp: new Date().toISOString(), + })); + + push2D({ + type: 'Draw', + actions: [ + { + actionType: 'Lines-Update', + points: updatedZonesData + } + ] + }); } + + setHoveredLine(null); } handleCanvasCursors('default'); } diff --git a/app/src/modules/builder/point/point.tsx b/app/src/modules/builder/point/point.tsx index 5c62dd5..b203f05 100644 --- a/app/src/modules/builder/point/point.tsx +++ b/app/src/modules/builder/point/point.tsx @@ -32,13 +32,14 @@ function Point({ point }: { readonly point: Point }) { const [dragOffset, setDragOffset] = useState(null); const { socket } = useSocketStore(); const { toolMode } = useToolMode(); - const { aisleStore, wallStore, floorStore, zoneStore } = useSceneContext(); + const { aisleStore, wallStore, floorStore, zoneStore, undoRedo2DStore } = useSceneContext(); + const { push2D } = undoRedo2DStore(); const { setPosition: setAislePosition, removePoint: removeAislePoint, getAislesByPointId } = aisleStore(); const { setPosition: setWallPosition, removePoint: removeWallPoint, getWallsByPointId } = wallStore(); const { setPosition: setFloorPosition, removePoint: removeFloorPoint, getFloorsByPointId } = floorStore(); const { setPosition: setZonePosition, removePoint: removeZonePoint, getZonesByPointId } = zoneStore(); const { snapAislePoint, snapAisleAngle, snapWallPoint, snapWallAngle, snapFloorPoint, snapFloorAngle, snapZonePoint, snapZoneAngle } = usePointSnapping({ uuid: point.pointUuid, pointType: point.pointType, position: point.position }); - const { hoveredPoint,hoveredLine, setHoveredPoint } = useBuilderStore(); + const { hoveredPoint, hoveredLine, setHoveredPoint } = useBuilderStore(); const { selectedPoints } = useSelectedPoints(); const { userId, organization } = getUserData(); const { selectedVersionStore } = useVersionContext(); @@ -47,6 +48,13 @@ function Point({ point }: { readonly point: Point }) { const boxScale: [number, number, number] = Constants.pointConfig.boxScale; const colors = getColor(point); + const [initialPositions, setInitialPositions] = useState<{ + aisles?: Aisle[], + walls?: Wall[], + floors?: Floor[], + zones?: Zone[] + }>({}); + useEffect(() => { handleCanvasCursors('default'); }, [toolMode]) @@ -152,6 +160,20 @@ function Point({ point }: { readonly point: Point }) { const currentPosition = new THREE.Vector3(...point.position); const offset = new THREE.Vector3().subVectors(currentPosition, hit); setDragOffset(offset); + + if (point.pointType === 'Aisle') { + const aisles = getAislesByPointId(point.pointUuid); + setInitialPositions({ aisles }); + } else if (point.pointType === 'Wall') { + const walls = getWallsByPointId(point.pointUuid); + setInitialPositions({ walls }); + } else if (point.pointType === 'Floor') { + const floors = getFloorsByPointId(point.pointUuid); + setInitialPositions({ floors }); + } else if (point.pointType === 'Zone') { + const zones = getZonesByPointId(point.pointUuid); + setInitialPositions({ zones }); + } } }; @@ -159,6 +181,7 @@ function Point({ point }: { readonly point: Point }) { handleCanvasCursors('default'); setDragOffset(null); if (toolMode !== 'move') return; + if (point.pointType === 'Aisle') { const updatedAisles = getAislesByPointId(point.pointUuid); if (updatedAisles.length > 0 && projectId) { @@ -180,6 +203,23 @@ function Point({ point }: { readonly point: Point }) { type: updatedAisle.type }) }) + + if (initialPositions.aisles && initialPositions.aisles.length > 0) { + const updatedPoints = initialPositions.aisles.map((aisle) => ({ + type: "Aisle" as const, + lineData: aisle, + newData: updatedAisles.find(a => a.aisleUuid === aisle.aisleUuid), + timeStamp: new Date().toISOString(), + })); + + push2D({ + type: 'Draw', + actions: [{ + actionType: 'Lines-Update', + points: updatedPoints, + }] + }); + } } } else if (point.pointType === 'Wall') { const updatedWalls = getWallsByPointId(point.pointUuid); @@ -203,6 +243,23 @@ function Point({ point }: { readonly point: Point }) { socket.emit('v1:model-Wall:add', data); }); } + + if (initialPositions.walls && initialPositions.walls.length > 0) { + const updatedPoints = initialPositions.walls.map((wall) => ({ + type: "Wall" as const, + lineData: wall, + newData: updatedWalls.find(w => w.wallUuid === wall.wallUuid), + timeStamp: new Date().toISOString(), + })); + + push2D({ + type: 'Draw', + actions: [{ + actionType: 'Lines-Update', + points: updatedPoints, + }] + }); + } } else if (point.pointType === 'Floor') { const updatedFloors = getFloorsByPointId(point.pointUuid); if (updatedFloors && updatedFloors.length > 0 && projectId) { @@ -225,6 +282,23 @@ function Point({ point }: { readonly point: Point }) { socket.emit('v1:model-Floor:add', data); }); } + + if (initialPositions.floors && initialPositions.floors.length > 0) { + const updatedPoints = initialPositions.floors.map((floor) => ({ + type: "Floor" as const, + lineData: floor, + newData: updatedFloors.find(f => f.floorUuid === floor.floorUuid), + timeStamp: new Date().toISOString(), + })); + + push2D({ + type: 'Draw', + actions: [{ + actionType: 'Lines-Update', + points: updatedPoints, + }] + }); + } } else if (point.pointType === 'Zone') { const updatedZones = getZonesByPointId(point.pointUuid); if (updatedZones && updatedZones.length > 0 && projectId) { @@ -247,13 +321,33 @@ function Point({ point }: { readonly point: Point }) { socket.emit('v1:zone:add', data); }); } + + if (initialPositions.zones && initialPositions.zones.length > 0) { + const updatedPoints = initialPositions.zones.map((zone) => ({ + type: "Zone" as const, + lineData: zone, + newData: updatedZones.find(z => z.zoneUuid === zone.zoneUuid), + timeStamp: new Date().toISOString(), + })); + + push2D({ + type: 'Draw', + actions: [{ + actionType: 'Lines-Update', + points: updatedPoints, + }] + }); + } } + + setInitialPositions({}); } const handlePointClick = (point: Point) => { if (toolMode === '2D-Delete') { if (point.pointType === 'Aisle') { const removedAisles = removeAislePoint(point.pointUuid); + setHoveredPoint(null); if (removedAisles.length > 0) { removedAisles.forEach(aisle => { if (projectId) { @@ -273,9 +367,25 @@ function Point({ point }: { readonly point: Point }) { } socket.emit('v1:model-aisle:delete', data); + } }); - setHoveredPoint(null); + + const removedAislesData = removedAisles.map((aisle) => ({ + type: "Aisle" as const, + lineData: aisle, + timeStamp: new Date().toISOString(), + })); + + push2D({ + type: 'Draw', + actions: [ + { + actionType: 'Lines-Delete', + points: removedAislesData + } + ] + }); } } if (point.pointType === 'Wall') { @@ -302,9 +412,26 @@ function Point({ point }: { readonly point: Point }) { socket.emit('v1:model-Wall:delete', data); } }); + + const removedWallsData = removedWalls.map((wall) => ({ + type: "Wall" as const, + lineData: wall, + timeStamp: new Date().toISOString(), + })); + + push2D({ + type: 'Draw', + actions: [ + { + actionType: 'Lines-Delete', + points: removedWallsData + } + ] + }); } } if (point.pointType === 'Floor') { + const Floors = getFloorsByPointId(point.pointUuid); const { removedFloors, updatedFloors } = removeFloorPoint(point.pointUuid); setHoveredPoint(null); if (removedFloors.length > 0) { @@ -328,6 +455,22 @@ function Point({ point }: { readonly point: Point }) { socket.emit('v1:model-Floor:delete', data); } }); + + const removedFloorsData = removedFloors.map((floor) => ({ + type: "Floor" as const, + lineData: floor, + timeStamp: new Date().toISOString(), + })); + + push2D({ + type: 'Draw', + actions: [ + { + actionType: 'Lines-Delete', + points: removedFloorsData + } + ] + }); } if (updatedFloors.length > 0) { updatedFloors.forEach(floor => { @@ -350,9 +493,27 @@ function Point({ point }: { readonly point: Point }) { socket.emit('v1:model-Floor:add', data); } }); + + const updatedFloorsData = updatedFloors.map((floor) => ({ + type: "Floor" as const, + lineData: Floors.find(f => f.floorUuid === floor.floorUuid) || floor, + newData: floor, + timeStamp: new Date().toISOString(), + })); + + push2D({ + type: 'Draw', + actions: [ + { + actionType: 'Lines-Update', + points: updatedFloorsData + } + ] + }); } } if (point.pointType === 'Zone') { + const Zones = getZonesByPointId(point.pointUuid); const { removedZones, updatedZones } = removeZonePoint(point.pointUuid); setHoveredPoint(null); if (removedZones.length > 0) { @@ -376,6 +537,22 @@ function Point({ point }: { readonly point: Point }) { socket.emit('v1:zone:delete', data); } }); + + const removedZonesData = removedZones.map((zone) => ({ + type: "Zone" as const, + lineData: zone, + timeStamp: new Date().toISOString(), + })); + + push2D({ + type: 'Draw', + actions: [ + { + actionType: 'Lines-Delete', + points: removedZonesData + } + ] + }); } if (updatedZones.length > 0) { updatedZones.forEach(zone => { @@ -398,6 +575,23 @@ function Point({ point }: { readonly point: Point }) { socket.emit('v1:zone:add', data); } }); + + const updatedZonesData = updatedZones.map((zone) => ({ + type: "Zone" as const, + lineData: Zones.find(z => z.zoneUuid === zone.zoneUuid) || zone, + newData: zone, + timeStamp: new Date().toISOString(), + })); + + push2D({ + type: 'Draw', + actions: [ + { + actionType: 'Lines-Update', + points: updatedZonesData + } + ] + }); } } handleCanvasCursors('default'); @@ -422,7 +616,6 @@ function Point({ point }: { readonly point: Point }) { return null; } - return ( <> {!isSelected ? @@ -453,7 +646,7 @@ function Point({ point }: { readonly point: Point }) { onPointerOut={() => { if (hoveredPoint) { setHoveredPoint(null); - if(!hoveredLine){ + if (!hoveredLine) { handleCanvasCursors('default'); } } diff --git a/app/src/modules/builder/wall/wallCreator/wallCreator.tsx b/app/src/modules/builder/wall/wallCreator/wallCreator.tsx index a80a62d..52d5d7e 100644 --- a/app/src/modules/builder/wall/wallCreator/wallCreator.tsx +++ b/app/src/modules/builder/wall/wallCreator/wallCreator.tsx @@ -22,8 +22,9 @@ function WallCreator() { const { toolMode } = useToolMode(); const { activeLayer } = useActiveLayer(); const { socket } = useSocketStore(); - const { wallStore } = useSceneContext(); + const { wallStore, undoRedo2DStore } = useSceneContext(); const { addWall, getWallPointById, removeWall, getWallByPoints } = wallStore(); + const { push2D } = undoRedo2DStore(); const drag = useRef(false); const isLeftMouseDown = useRef(false); const { selectedVersionStore } = useVersionContext(); @@ -91,6 +92,7 @@ function WallCreator() { const closestPoint = new THREE.Vector3().lerpVectors(point1Vec, point2Vec, t); removeWall(wall.wallUuid); + if (projectId) { // API @@ -142,6 +144,7 @@ function WallCreator() { wallHeight: wallHeight, decals: [] } + addWall(wall2); // API @@ -171,8 +174,36 @@ function WallCreator() { wallHeight: wallHeight, decals: [] } + addWall(wall3); + push2D({ + type: 'Draw', + actions: [ + { + actionType: 'Lines-Create', + points: [ + { + type: 'Wall', + lineData: wall3, + timeStamp: new Date().toISOString(), + }, { + type: 'Wall', + lineData: wall2, + timeStamp: new Date().toISOString(), + } + ] + }, { + actionType: 'Line-Delete', + point: { + type: 'Wall', + lineData: wall, + timeStamp: new Date().toISOString(), + } + } + ], + }) + // API // if (projectId) { @@ -202,7 +233,8 @@ function WallCreator() { wallThickness: wallThickness, wallHeight: wallHeight, decals: [] - }; + } + addWall(wall1); // API @@ -232,6 +264,7 @@ function WallCreator() { wallHeight: wallHeight, decals: [] } + addWall(wall2); // API @@ -261,8 +294,40 @@ function WallCreator() { wallHeight: wallHeight, decals: [] } + addWall(wall3); + push2D({ + type: 'Draw', + actions: [ + { + actionType: 'Lines-Create', + points: [ + { + type: 'Wall', + lineData: wall3, + timeStamp: new Date().toISOString(), + }, { + type: 'Wall', + lineData: wall1, + timeStamp: new Date().toISOString(), + }, { + type: 'Wall', + lineData: wall2, + timeStamp: new Date().toISOString(), + } + ] + }, { + actionType: 'Line-Delete', + point: { + type: 'Wall', + lineData: wall, + timeStamp: new Date().toISOString(), + } + } + ], + }) + // API // if (projectId) { @@ -328,9 +393,24 @@ function WallCreator() { wallThickness: wallThickness, wallHeight: wallHeight, decals: [] - }; + } + addWall(wall); + push2D({ + type: 'Draw', + actions: [ + { + actionType: 'Line-Create', + point: { + type: 'Wall', + lineData: wall, + timeStamp: new Date().toISOString(), + } + } + ], + }) + // API // if (projectId) { diff --git a/app/src/modules/builder/zone/zoneCreator/zoneCreator.tsx b/app/src/modules/builder/zone/zoneCreator/zoneCreator.tsx index f1f1b6a..bed501f 100644 --- a/app/src/modules/builder/zone/zoneCreator/zoneCreator.tsx +++ b/app/src/modules/builder/zone/zoneCreator/zoneCreator.tsx @@ -19,8 +19,9 @@ function ZoneCreator() { const { toolMode } = useToolMode(); const { activeLayer } = useActiveLayer(); const { socket } = useSocketStore(); - const { zoneStore } = useSceneContext(); - const { zones, addZone, getZonePointById, getZoneByPoints } = zoneStore(); + const { zoneStore, undoRedo2DStore } = useSceneContext(); + const { addZone, getZonePointById } = zoneStore(); + const { push2D } = undoRedo2DStore(); const drag = useRef(false); const isLeftMouseDown = useRef(false); const { selectedVersionStore } = useVersionContext(); @@ -102,6 +103,21 @@ function ZoneCreator() { }; addZone(zone); + + push2D({ + type: 'Draw', + actions: [ + { + actionType: 'Line-Create', + point: { + type: 'Zone', + lineData: zone, + timeStamp: new Date().toISOString(), + } + } + ], + }) + if (projectId) { // API @@ -139,6 +155,21 @@ function ZoneCreator() { }; addZone(zone); + + push2D({ + type: 'Draw', + actions: [ + { + actionType: 'Line-Create', + point: { + type: 'Zone', + lineData: zone, + timeStamp: new Date().toISOString(), + } + } + ], + }) + if (projectId) { // API @@ -186,6 +217,21 @@ function ZoneCreator() { }; addZone(zone); + + push2D({ + type: 'Draw', + actions: [ + { + actionType: 'Line-Create', + point: { + type: 'Zone', + lineData: zone, + timeStamp: new Date().toISOString(), + } + } + ], + }) + if (projectId) { // API @@ -238,7 +284,7 @@ function ZoneCreator() { canvasElement.removeEventListener("click", onMouseClick); canvasElement.removeEventListener("contextmenu", onContext); }; - }, [gl, camera, scene, raycaster, pointer, plane, toggleView, toolMode, activeLayer, socket, tempPoints, isCreating, addZone, getZonePointById, getZoneByPoints, zoneColor, zoneHeight, snappedPosition, snappedPoint]); + }, [gl, camera, scene, raycaster, pointer, plane, toggleView, toolMode, activeLayer, socket, tempPoints, isCreating, addZone, getZonePointById, zoneColor, zoneHeight, snappedPosition, snappedPoint]); return ( <> diff --git a/app/src/modules/scene/controls/controls.tsx b/app/src/modules/scene/controls/controls.tsx index 975ab54..77f234c 100644 --- a/app/src/modules/scene/controls/controls.tsx +++ b/app/src/modules/scene/controls/controls.tsx @@ -14,6 +14,7 @@ import TransformControl from "./transformControls/transformControls"; import { useParams } from "react-router-dom"; import { getUserData } from "../../../functions/getUserData"; import SelectionControls2D from "./selectionControls/selection2D/selectionControls2D"; +import UndoRedo2DControls from "./undoRedoControls/undoRedo2D/undoRedo2DControls"; export default function Controls() { const controlsRef = useRef(null); @@ -142,6 +143,8 @@ export default function Controls() { + + diff --git a/app/src/modules/scene/controls/undoRedoControls/handlers/useRedoHandler.ts b/app/src/modules/scene/controls/undoRedoControls/handlers/useRedoHandler.ts new file mode 100644 index 0000000..e5f31a5 --- /dev/null +++ b/app/src/modules/scene/controls/undoRedoControls/handlers/useRedoHandler.ts @@ -0,0 +1,355 @@ +import { useParams } from "react-router-dom"; +import { getUserData } from "../../../../../functions/getUserData"; +import { useVersionContext } from "../../../../builder/version/versionContext"; +import { useSceneContext } from "../../../sceneContext"; +import { useSocketStore } from "../../../../../store/builder/store"; + +// import { upsertWallApi } from "../../../../../services/factoryBuilder/wall/upsertWallApi"; +// import { deleteWallApi } from "../../../../../services/factoryBuilder/wall/deleteWallApi"; + +// import { upsertZoneApi } from "../../../../../services/factoryBuilder/zone/upsertZoneApi"; +// import { deleteZoneApi } from "../../../../../services/factoryBuilder/zone/deleteZoneApi"; + +// import { upsertFloorApi } from "../../../../../services/factoryBuilder/floor/upsertFloorApi"; +// import { deleteFloorApi } from "../../../../../services/factoryBuilder/floor/deleteFloorApi"; + +// import { upsertAisleApi } from "../../../../../services/factoryBuilder/aisle/upsertAisleApi"; +// import { deleteAisleApi } from "../../../../../services/factoryBuilder/aisle/deleteAisleApi"; + +function useRedoHandler() { + const { undoRedo2DStore, wallStore, floorStore, zoneStore, aisleStore } = useSceneContext(); + const { redo2D, peekRedo2D } = undoRedo2DStore(); + const { addWall, removeWall, updateWall } = wallStore(); + const { addFloor, removeFloor, updateFloor } = floorStore(); + const { addZone, removeZone, updateZone } = zoneStore(); + const { addAisle, removeAisle, updateAisle } = aisleStore(); + const { selectedVersionStore } = useVersionContext(); + const { selectedVersion } = selectedVersionStore(); + const { userId, organization } = getUserData(); + const { projectId } = useParams(); + const { socket } = useSocketStore(); + + const handleRedo = () => { + const redoData = peekRedo2D(); + if (!redoData) return; + + if (redoData.type === 'Draw') { + const { actions } = redoData; + + actions.forEach(action => { + const { actionType } = action; + + if ('point' in action) { + const point = action.point; + + if (actionType === 'Line-Create') { + handleCreate(point); + } else if (actionType === 'Line-Update') { + handleUpdate(point); + } else if (actionType === 'Line-Delete') { + handleRemove(point); + } + + } else if ('points' in action) { + const points = action.points; + + if (actionType === 'Lines-Create') { + points.forEach(handleCreate); + } else if (actionType === 'Lines-Update') { + points.forEach(handleUpdate); + } else if (actionType === 'Lines-Delete') { + points.forEach(handleRemove); + } + } + }); + } else if (redoData.type === 'UI') { + // Handle UI actions if needed + } + + redo2D(); + }; + + const handleCreate = (point: UndoRedo2DDataTypeSchema) => { + switch (point.type) { + case 'Wall': createWallFromBackend(point.lineData); break; + case 'Floor': createFloorFromBackend(point.lineData); break; + case 'Zone': createZoneFromBackend(point.lineData); break; + case 'Aisle': createAisleFromBackend(point.lineData); break; + } + }; + + const handleRemove = (point: UndoRedo2DDataTypeSchema) => { + switch (point.type) { + case 'Wall': removeWallFromBackend(point.lineData.wallUuid); break; + case 'Floor': removeFloorFromBackend(point.lineData.floorUuid); break; + case 'Zone': removeZoneFromBackend(point.lineData.zoneUuid); break; + case 'Aisle': removeAisleFromBackend(point.lineData.aisleUuid); break; + } + }; + + const handleUpdate = (point: UndoRedo2DDataTypeSchema) => { + if (!point.newData) return; + switch (point.type) { + case 'Wall': updateWallFromBackend(point.newData.wallUuid, point.newData); break; + case 'Floor': updateFloorFromBackend(point.newData.floorUuid, point.newData); break; + case 'Zone': updateZoneFromBackend(point.newData.zoneUuid, point.newData); break; + case 'Aisle': updateAisleFromBackend(point.newData.aisleUuid, point.newData); break; + } + }; + + const createWallFromBackend = (wallData: Wall) => { + addWall(wallData); + if (projectId) { + // API + + // upsertWallApi(projectId, selectedVersion?.versionId || '', wallData); + + // SOCKET + + const data = { + wallData: wallData, + projectId: projectId, + versionId: selectedVersion?.versionId || '', + userId: userId, + organization: organization + } + + socket.emit('v1:model-Wall:add', data); + } + }; + + const removeWallFromBackend = (wallUuid: string) => { + removeWall(wallUuid); + if (projectId) { + // API + + // deleteWallApi(projectId, selectedVersion?.versionId || '', wallUuid); + + // SOCKET + + const data = { + wallUuid: wallUuid, + projectId: projectId, + versionId: selectedVersion?.versionId || '', + userId: userId, + organization: organization + } + + socket.emit('v1:model-Wall:delete', data); + } + }; + + const updateWallFromBackend = (wallUuid: string, updatedData: Wall) => { + updateWall(wallUuid, updatedData); + if (projectId) { + // API + + // upsertWallApi(projectId, selectedVersion?.versionId || '', updatedData); + + // SOCKET + + const data = { + wallData: updatedData, + projectId: projectId, + versionId: selectedVersion?.versionId || '', + userId: userId, + organization: organization + } + + socket.emit('v1:model-Wall:add', data); + } + }; + + const createFloorFromBackend = (floorData: Floor) => { + addFloor(floorData); + if (projectId) { + // API + + // upsertFloorApi(projectId, selectedVersion?.versionId || '', floorData); + + // SOCKET + + const data = { + floorData: floorData, + projectId: projectId, + versionId: selectedVersion?.versionId || '', + userId: userId, + organization: organization + } + + socket.emit('v1:model-Floor:add', data); + } + }; + + const removeFloorFromBackend = (floorUuid: string) => { + removeFloor(floorUuid); + if (projectId) { + // API + + // deleteFloorApi(projectId, selectedVersion?.versionId || '', floorUuid); + + // SOCKET + + const data = { + floorUuid: floorUuid, + projectId: projectId, + versionId: selectedVersion?.versionId || '', + userId: userId, + organization: organization + } + + socket.emit('v1:model-Floor:delete', data); + } + }; + + const updateFloorFromBackend = (floorUuid: string, updatedData: Floor) => { + updateFloor(floorUuid, updatedData); + if (projectId) { + // API + + // upsertFloorApi(projectId, selectedVersion?.versionId || '', updatedData); + + // SOCKET + + const data = { + floorData: updatedData, + projectId: projectId, + versionId: selectedVersion?.versionId || '', + userId: userId, + organization: organization + } + + socket.emit('v1:model-Floor:add', data); + } + }; + + const createZoneFromBackend = (zoneData: Zone) => { + addZone(zoneData); + if (projectId) { + // API + + // upsertZoneApi(projectId, selectedVersion?.versionId || '', zoneData); + + // SOCKET + + const data = { + zoneData: zoneData, + projectId: projectId, + versionId: selectedVersion?.versionId || '', + userId: userId, + organization: organization + } + + socket.emit('v1:zone:add', data); + } + }; + + const removeZoneFromBackend = (zoneUuid: string) => { + removeZone(zoneUuid); + if (projectId) { + // API + + // deleteZoneApi(projectId, selectedVersion?.versionId || '', zoneUuid); + + // SOCKET + + const data = { + zoneUuid, + projectId, + versionId: selectedVersion?.versionId || '', + userId, + organization + }; + + socket.emit('v1:zone:delete', data); + } + }; + + const updateZoneFromBackend = (zoneUuid: string, updatedData: Zone) => { + updateZone(zoneUuid, updatedData); + if (projectId) { + // API + + // upsertZoneApi(projectId, selectedVersion?.versionId || '', updatedData); + + // SOCKET + + const data = { + zoneData: updatedData, + projectId, + versionId: selectedVersion?.versionId || '', + userId, + organization + }; + + socket.emit('v1:zone:add', data); + } + }; + + const createAisleFromBackend = (aisleData: Aisle) => { + addAisle(aisleData); + if (projectId) { + // API + + // upsertAisleApi(projectId, selectedVersion?.versionId || '', aisleData); + + // SOCKET + + const data = { + aisleData, + projectId, + versionId: selectedVersion?.versionId || '', + userId, + organization + }; + + socket.emit('v1:model-aisle:add', data); + } + }; + + const removeAisleFromBackend = (aisleUuid: string) => { + removeAisle(aisleUuid); + if (projectId) { + // API + + // deleteAisleApi(projectId, selectedVersion?.versionId || '', aisleUuid); + + // SOCKET + + const data = { + aisleUuid, + projectId, + versionId: selectedVersion?.versionId || '', + userId, + organization + }; + + socket.emit('v1:model-aisle:delete', data); + } + }; + + const updateAisleFromBackend = (aisleUuid: string, updatedData: Aisle) => { + updateAisle(aisleUuid, updatedData); + if (projectId) { + // API + + // upsertAisleApi(projectId, selectedVersion?.versionId || '', updatedData); + + // SOCKET + + const data = { + aisleData: updatedData, + projectId, + versionId: selectedVersion?.versionId || '', + userId, + organization + }; + + socket.emit('v1:model-aisle:add', data); + } + }; + + return { handleRedo }; +} + +export default useRedoHandler; diff --git a/app/src/modules/scene/controls/undoRedoControls/handlers/useUndoHandler.ts b/app/src/modules/scene/controls/undoRedoControls/handlers/useUndoHandler.ts new file mode 100644 index 0000000..357f36e --- /dev/null +++ b/app/src/modules/scene/controls/undoRedoControls/handlers/useUndoHandler.ts @@ -0,0 +1,356 @@ +import { useParams } from "react-router-dom"; +import { getUserData } from "../../../../../functions/getUserData"; +import { useVersionContext } from "../../../../builder/version/versionContext"; +import { useSceneContext } from "../../../sceneContext"; +import { useSocketStore } from "../../../../../store/builder/store"; + +// import { upsertWallApi } from "../../../../../services/factoryBuilder/wall/upsertWallApi"; +// import { deleteWallApi } from "../../../../../services/factoryBuilder/wall/deleteWallApi"; + +// import { upsertZoneApi } from "../../../../../services/factoryBuilder/zone/upsertZoneApi"; +// import { deleteWallApi } from "../../../../../services/factoryBuilder/wall/deleteWallApi"; + +// import { upsertFloorApi } from "../../../../../services/factoryBuilder/floor/upsertFloorApi"; +// import { deleteFloorApi } from "../../../../../services/factoryBuilder/floor/deleteFloorApi"; + +// import { upsertAisleApi } from "../../../../../services/factoryBuilder/aisle/upsertAisleApi"; +// import { deleteAisleApi } from "../../../../../services/factoryBuilder/aisle/deleteAisleApi"; + +function useUndoHandler() { + const { undoRedo2DStore, wallStore, floorStore, zoneStore, aisleStore } = useSceneContext(); + const { undo2D, peekUndo2D } = undoRedo2DStore(); + const { addWall, removeWall, updateWall } = wallStore(); + const { addFloor, removeFloor, updateFloor } = floorStore(); + const { addZone, removeZone, updateZone } = zoneStore(); + const { addAisle, removeAisle, updateAisle } = aisleStore(); + const { selectedVersionStore } = useVersionContext(); + const { selectedVersion } = selectedVersionStore(); + const { userId, organization } = getUserData(); + const { projectId } = useParams(); + const { socket } = useSocketStore(); + + const handleUndo = () => { + const unDoData = peekUndo2D(); + if (!unDoData) return; + + if (unDoData.type === 'Draw') { + const { actions } = unDoData; + + actions.forEach(action => { + const { actionType } = action; + + if ('point' in action) { + const point = action.point; + + if (actionType === 'Line-Create') { + handleRemove(point); + } else if (actionType === 'Line-Update') { + handleUpdate(point); + } else if (actionType === 'Line-Delete') { + handleCreate(point); + } + + } else if ('points' in action) { + const points = action.points; + + if (actionType === 'Lines-Create') { + points.forEach(handleRemove); + } else if (actionType === 'Lines-Update') { + points.forEach(handleUpdate); + } else if (actionType === 'Lines-Delete') { + points.forEach(handleCreate); + } + } + }); + } else if (unDoData.type === 'UI') { + // Handle UI actions if needed + } + + undo2D(); + + }; + + const handleCreate = (point: UndoRedo2DDataTypeSchema) => { + switch (point.type) { + case 'Wall': createWallFromBackend(point.lineData); break; + case 'Floor': createFloorFromBackend(point.lineData); break; + case 'Zone': createZoneFromBackend(point.lineData); break; + case 'Aisle': createAisleFromBackend(point.lineData); break; + } + }; + + const handleRemove = (point: UndoRedo2DDataTypeSchema) => { + switch (point.type) { + case 'Wall': removeWallFromBackend(point.lineData.wallUuid); break; + case 'Floor': removeFloorFromBackend(point.lineData.floorUuid); break; + case 'Zone': removeZoneFromBackend(point.lineData.zoneUuid); break; + case 'Aisle': removeAisleFromBackend(point.lineData.aisleUuid); break; + } + }; + + const handleUpdate = (point: UndoRedo2DDataTypeSchema) => { + switch (point.type) { + case 'Wall': updateWallFromBackend(point.lineData.wallUuid, point.lineData); break; + case 'Floor': updateFloorFromBackend(point.lineData.floorUuid, point.lineData); break; + case 'Zone': updateZoneFromBackend(point.lineData.zoneUuid, point.lineData); break; + case 'Aisle': updateAisleFromBackend(point.lineData.aisleUuid, point.lineData); break; + } + }; + + + const createWallFromBackend = (wallData: Wall) => { + addWall(wallData); + if (projectId) { + // API + + // upsertWallApi(projectId, selectedVersion?.versionId || '', wallData); + + // SOCKET + + const data = { + wallData: wallData, + projectId: projectId, + versionId: selectedVersion?.versionId || '', + userId: userId, + organization: organization + } + + socket.emit('v1:model-Wall:add', data); + } + }; + + const removeWallFromBackend = (wallUuid: string) => { + removeWall(wallUuid); + if (projectId) { + // API + + // deleteWallApi(projectId, selectedVersion?.versionId || '', wallUuid); + + // SOCKET + + const data = { + wallUuid: wallUuid, + projectId: projectId, + versionId: selectedVersion?.versionId || '', + userId: userId, + organization: organization + } + + socket.emit('v1:model-Wall:delete', data); + } + }; + + const updateWallFromBackend = (wallUuid: string, updatedData: Wall) => { + updateWall(wallUuid, updatedData); + if (projectId) { + // API + + // upsertWallApi(projectId, selectedVersion?.versionId || '', updatedData); + + // SOCKET + + const data = { + wallData: updatedData, + projectId: projectId, + versionId: selectedVersion?.versionId || '', + userId: userId, + organization: organization + } + + socket.emit('v1:model-Wall:add', data); + } + }; + + const createFloorFromBackend = (floorData: Floor) => { + addFloor(floorData); + if (projectId) { + // API + + // upsertFloorApi(projectId, selectedVersion?.versionId || '', floorData); + + // SOCKET + + const data = { + floorData: floorData, + projectId: projectId, + versionId: selectedVersion?.versionId || '', + userId: userId, + organization: organization + } + + socket.emit('v1:model-Floor:add', data); + } + }; + + const removeFloorFromBackend = (floorUuid: string) => { + removeFloor(floorUuid); + if (projectId) { + // API + + // deleteFloorApi(projectId, selectedVersion?.versionId || '', floorUuid); + + // SOCKET + + const data = { + floorUuid: floorUuid, + projectId: projectId, + versionId: selectedVersion?.versionId || '', + userId: userId, + organization: organization + } + + socket.emit('v1:model-Floor:delete', data); + } + }; + + const updateFloorFromBackend = (floorUuid: string, updatedData: Floor) => { + updateFloor(floorUuid, updatedData); + if (projectId) { + // API + + // upsertFloorApi(projectId, selectedVersion?.versionId || '', updatedData); + + // SOCKET + + const data = { + floorData: updatedData, + projectId: projectId, + versionId: selectedVersion?.versionId || '', + userId: userId, + organization: organization + } + + socket.emit('v1:model-Floor:add', data); + } + }; + + const createZoneFromBackend = (zoneData: Zone) => { + addZone(zoneData); + if (projectId) { + // API + + // upsertZoneApi(projectId, selectedVersion?.versionId || '', zoneData); + + // SOCKET + + const data = { + zoneData: zoneData, + projectId: projectId, + versionId: selectedVersion?.versionId || '', + userId: userId, + organization: organization + } + + socket.emit('v1:zone:add', data); + } + }; + + const removeZoneFromBackend = (zoneUuid: string) => { + removeZone(zoneUuid); + if (projectId) { + // API + + // deleteZoneApi(projectId, selectedVersion?.versionId || '', zoneUuid); + + // SOCKET + + const data = { + zoneUuid, + projectId, + versionId: selectedVersion?.versionId || '', + userId, + organization + }; + + socket.emit('v1:zone:delete', data); + } + }; + + const updateZoneFromBackend = (zoneUuid: string, updatedData: Zone) => { + updateZone(zoneUuid, updatedData); + if (projectId) { + // API + + // upsertZoneApi(projectId, selectedVersion?.versionId || '', updatedData); + + // SOCKET + + const data = { + zoneData: updatedData, + projectId, + versionId: selectedVersion?.versionId || '', + userId, + organization + }; + + socket.emit('v1:zone:add', data); + } + }; + + const createAisleFromBackend = (aisleData: Aisle) => { + addAisle(aisleData); + if (projectId) { + // API + + // upsertAisleApi(projectId, selectedVersion?.versionId || '', aisleData); + + // SOCKET + + const data = { + aisleData, + projectId, + versionId: selectedVersion?.versionId || '', + userId, + organization + }; + + socket.emit('v1:model-aisle:add', data); + } + }; + + const removeAisleFromBackend = (aisleUuid: string) => { + removeAisle(aisleUuid); + if (projectId) { + // API + + // deleteAisleApi(projectId, selectedVersion?.versionId || '', aisleUuid); + + // SOCKET + + const data = { + aisleUuid, + projectId, + versionId: selectedVersion?.versionId || '', + userId, + organization + }; + + socket.emit('v1:model-aisle:delete', data); + } + }; + + const updateAisleFromBackend = (aisleUuid: string, updatedData: Aisle) => { + updateAisle(aisleUuid, updatedData); + if (projectId) { + // API + + // upsertAisleApi(projectId, selectedVersion?.versionId || '', updatedData); + + // SOCKET + + const data = { + aisleData: updatedData, + projectId, + versionId: selectedVersion?.versionId || '', + userId, + organization + }; + + socket.emit('v1:model-aisle:add', data); + } + }; + + return { handleUndo }; +} + +export default useUndoHandler; \ No newline at end of file diff --git a/app/src/modules/scene/controls/undoRedoControls/undoRedo2D/undoRedo2DControls.tsx b/app/src/modules/scene/controls/undoRedoControls/undoRedo2D/undoRedo2DControls.tsx new file mode 100644 index 0000000..d45518c --- /dev/null +++ b/app/src/modules/scene/controls/undoRedoControls/undoRedo2D/undoRedo2DControls.tsx @@ -0,0 +1,49 @@ +import { useEffect } from 'react' +import { useSceneContext } from '../../../sceneContext' +import { detectModifierKeys } from '../../../../../utils/shortcutkeys/detectModifierKeys'; +import { useSocketStore, useToggleView } from '../../../../../store/builder/store'; +import { useVersionContext } from '../../../../builder/version/versionContext'; + +import useUndoHandler from '../handlers/useUndoHandler'; +import useRedoHandler from '../handlers/useRedoHandler'; + +function UndoRedo2DControls() { + const { undoRedo2DStore } = useSceneContext(); + const { undoStack, redoStack } = undoRedo2DStore(); + const { toggleView } = useToggleView(); + const { handleUndo } = useUndoHandler(); + const { handleRedo } = useRedoHandler(); + const { socket } = useSocketStore(); + const { selectedVersionStore } = useVersionContext(); + const { selectedVersion } = selectedVersionStore(); + + useEffect(() => { + console.log(undoStack, redoStack); + }, [undoStack, redoStack]); + + useEffect(() => { + const handleKeyDown = (event: KeyboardEvent) => { + const keyCombination = detectModifierKeys(event); + + if (keyCombination === 'Ctrl+Z') { + handleUndo(); + } + + if (keyCombination === 'Ctrl+Y') { + handleRedo(); + } + }; + + if (toggleView) { + window.addEventListener('keydown', handleKeyDown); + } + + return () => { + window.removeEventListener('keydown', handleKeyDown); + }; + }, [toggleView, undoStack, redoStack, socket, selectedVersion]); + + return null; +} + +export default UndoRedo2DControls; diff --git a/app/src/modules/scene/sceneContext.tsx b/app/src/modules/scene/sceneContext.tsx index 187d66a..bf65c36 100644 --- a/app/src/modules/scene/sceneContext.tsx +++ b/app/src/modules/scene/sceneContext.tsx @@ -7,6 +7,8 @@ import { createAisleStore, AisleStoreType } from '../../store/builder/useAisleSt import { createZoneStore, ZoneStoreType } from '../../store/builder/useZoneStore'; import { createFloorStore, FloorStoreType } from '../../store/builder/useFloorStore'; +import { createUndoRedo2DStore, UndoRedo2DStoreType } from '../../store/builder/useUndoRedo2DStore'; + import { createEventStore, EventStoreType } from '../../store/simulation/useEventsStore'; import { createProductStore, ProductStoreType } from '../../store/simulation/useProductStore'; @@ -27,6 +29,8 @@ type SceneContextValue = { zoneStore: ZoneStoreType, floorStore: FloorStoreType, + undoRedo2DStore: UndoRedo2DStoreType, + eventStore: EventStoreType, productStore: ProductStoreType, @@ -62,6 +66,8 @@ export function SceneProvider({ const zoneStore = useMemo(() => createZoneStore(), []); const floorStore = useMemo(() => createFloorStore(), []); + const undoRedo2DStore = useMemo(() => createUndoRedo2DStore(), []); + const eventStore = useMemo(() => createEventStore(), []); const productStore = useMemo(() => createProductStore(), []); @@ -82,6 +88,7 @@ export function SceneProvider({ aisleStore.getState().clearAisles(); zoneStore.getState().clearZones(); floorStore.getState().clearFloors(); + undoRedo2DStore.getState().clearUndoRedo2D(); eventStore.getState().clearEvents(); productStore.getState().clearProducts(); materialStore.getState().clearMaterials(); @@ -92,7 +99,7 @@ export function SceneProvider({ storageUnitStore.getState().clearStorageUnits(); humanStore.getState().clearHumans(); humanEventManagerRef.current.humanStates = []; - }, [assetStore, wallAssetStore, wallStore, aisleStore, zoneStore, floorStore, eventStore, productStore, materialStore, armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore, humanStore]); + }, [assetStore, wallAssetStore, wallStore, aisleStore, zoneStore, undoRedo2DStore, floorStore, eventStore, productStore, materialStore, armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore, humanStore]); const contextValue = useMemo(() => ( { @@ -102,6 +109,7 @@ export function SceneProvider({ aisleStore, zoneStore, floorStore, + undoRedo2DStore, eventStore, productStore, materialStore, @@ -115,7 +123,7 @@ export function SceneProvider({ clearStores, layout } - ), [assetStore, wallAssetStore, wallStore, aisleStore, zoneStore, floorStore, eventStore, productStore, materialStore, armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore, humanStore, clearStores, layout]); + ), [assetStore, wallAssetStore, wallStore, aisleStore, zoneStore, floorStore, undoRedo2DStore, eventStore, productStore, materialStore, armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore, humanStore, clearStores, layout]); return ( diff --git a/app/src/store/builder/useFloorStore.ts b/app/src/store/builder/useFloorStore.ts index efb431b..a045884 100644 --- a/app/src/store/builder/useFloorStore.ts +++ b/app/src/store/builder/useFloorStore.ts @@ -28,7 +28,7 @@ interface FloorStore { getFloorById: (uuid: string) => Floor | undefined; getFloorsByPointId: (uuid: string) => Floor[] | []; - getFloorByPoints: (points: Point[]) => Floor | undefined; + getFloorsByPoints: (points: [Point, Point]) => Floor[] | []; getFloorPointById: (uuid: string) => Point | undefined; getConnectedPoints: (uuid: string) => Point[]; } @@ -74,10 +74,13 @@ export const createFloorStore = () => { const updatedFloors: Floor[] = []; set(state => { + const newFloors: Floor[] = []; + for (const floor of state.floors) { const pointIndex = floor.points.findIndex(p => p.pointUuid === pointUuid); + if (pointIndex === -1) { - updatedFloors.push(JSON.parse(JSON.stringify(floor))); + newFloors.push(floor); continue; } @@ -87,11 +90,13 @@ export const createFloorStore = () => { removedFloors.push(JSON.parse(JSON.stringify(floor))); continue; } - floor.points = remainingPoints; - updatedFloors.push(JSON.parse(JSON.stringify(floor))); + + const updatedFloor = { ...floor, points: remainingPoints }; + updatedFloors.push(JSON.parse(JSON.stringify(updatedFloor))); + newFloors.push(updatedFloor); } - state.floors = updatedFloors; + state.floors = newFloors; }); return { removedFloors, updatedFloors }; @@ -102,6 +107,7 @@ export const createFloorStore = () => { const updatedFloors: Floor[] = []; set(state => { + const newFloors: Floor[] = []; for (const floor of state.floors) { const indices = floor.points.map((p, i) => ({ uuid: p.pointUuid, index: i })); @@ -110,7 +116,7 @@ export const createFloorStore = () => { const idxB = indices.find(i => i.uuid === pointB.pointUuid)?.index ?? -1; if (idxA === -1 || idxB === -1) { - updatedFloors.push(JSON.parse(JSON.stringify(floor))); + newFloors.push(floor); continue; } @@ -120,7 +126,7 @@ export const createFloorStore = () => { (idxB === 0 && idxA === floor.points.length - 1); if (!areAdjacent) { - updatedFloors.push(JSON.parse(JSON.stringify(floor))); + newFloors.push(floor); continue; } @@ -129,14 +135,15 @@ export const createFloorStore = () => { ); if (remainingPoints.length > 2) { - floor.points = remainingPoints; - updatedFloors.push(JSON.parse(JSON.stringify(floor))); + const updatedFloor = { ...floor, points: remainingPoints }; + updatedFloors.push(JSON.parse(JSON.stringify(updatedFloor))); + newFloors.push(updatedFloor); } else { removedFloors.push(JSON.parse(JSON.stringify(floor))); } } - state.floors = updatedFloors; + state.floors = newFloors; }); return { removedFloors, updatedFloors }; @@ -253,12 +260,32 @@ export const createFloorStore = () => { }); }, - getFloorByPoints: (points) => { - return get().floors.find(floor => { - const floorPointIds = new Set(floor.points.map(p => p.pointUuid)); - const givenPointIds = new Set(points.map(p => p.pointUuid)); - return floorPointIds.size === givenPointIds.size && [...floorPointIds].every(id => givenPointIds.has(id)); - }); + getFloorsByPoints: ([pointA, pointB]) => { + const Floors: Floor[] = []; + + for (const floor of get().floors) { + const indices = floor.points.map((p, i) => ({ uuid: p.pointUuid, index: i })); + + const idxA = indices.find(i => i.uuid === pointA.pointUuid)?.index ?? -1; + const idxB = indices.find(i => i.uuid === pointB.pointUuid)?.index ?? -1; + + if (idxA === -1 || idxB === -1) { + continue; + } + + const areAdjacent = + Math.abs(idxA - idxB) === 1 || + (idxA === 0 && idxB === floor.points.length - 1) || + (idxB === 0 && idxA === floor.points.length - 1); + + if (!areAdjacent) { + continue; + } + + Floors.push(JSON.parse(JSON.stringify(floor))); + } + + return Floors; }, getFloorPointById: (pointUuid) => { diff --git a/app/src/store/builder/useUndoRedo2DStore.ts b/app/src/store/builder/useUndoRedo2DStore.ts new file mode 100644 index 0000000..9df0185 --- /dev/null +++ b/app/src/store/builder/useUndoRedo2DStore.ts @@ -0,0 +1,78 @@ +import { create } from 'zustand'; +import { immer } from 'zustand/middleware/immer'; +import { undoRedoConfig } from '../../types/world/worldConstants'; + +type UndoRedo2DStore = { + undoStack: UndoRedo2DTypes[]; + redoStack: UndoRedo2DTypes[]; + + push2D: (entry: UndoRedo2DTypes) => void; + undo2D: () => UndoRedo2DTypes | undefined; + redo2D: () => UndoRedo2DTypes | undefined; + clearUndoRedo2D: () => void; + + peekUndo2D: () => UndoRedo2DTypes | undefined; + peekRedo2D: () => UndoRedo2DTypes | undefined; +}; + +export const createUndoRedo2DStore = () => { + return create()( + immer((set, get) => ({ + undoStack: [], + redoStack: [], + + push2D: (entry) => { + set((state) => { + state.undoStack.push(entry); + + if (state.undoStack.length > undoRedoConfig.undoRedoCount) { + state.undoStack.shift(); + } + + state.redoStack = []; + }); + }, + + undo2D: () => { + let lastAction: UndoRedo2DTypes | undefined; + set((state) => { + lastAction = state.undoStack.pop(); + if (lastAction) { + state.redoStack.unshift(lastAction); + } + }); + return lastAction; + }, + + redo2D: () => { + let redoAction: UndoRedo2DTypes | undefined; + set((state) => { + redoAction = state.redoStack.shift(); + if (redoAction) { + state.undoStack.push(redoAction); + } + }); + return redoAction; + }, + + clearUndoRedo2D: () => { + set((state) => { + state.undoStack = []; + state.redoStack = []; + }); + }, + + peekUndo2D: () => { + const stack = get().undoStack; + return stack.length > 0 ? stack[stack.length - 1] : undefined; + }, + + peekRedo2D: () => { + const stack = get().redoStack; + return stack.length > 0 ? stack[0] : undefined; + }, + })) + ) +} + +export type UndoRedo2DStoreType = ReturnType; \ No newline at end of file diff --git a/app/src/store/builder/useZoneStore.ts b/app/src/store/builder/useZoneStore.ts index 1a93e57..17134c7 100644 --- a/app/src/store/builder/useZoneStore.ts +++ b/app/src/store/builder/useZoneStore.ts @@ -21,7 +21,7 @@ interface ZoneStore { getZoneById: (uuid: string) => Zone | undefined; getZonesByPointId: (uuid: string) => Zone[] | []; - getZoneByPoints: (points: Point[]) => Zone | undefined; + getZonesByPoints: (points: Point[]) => Zone[] | []; getZonePointById: (uuid: string) => Point | undefined; getConnectedPoints: (uuid: string) => Point[]; } @@ -76,10 +76,13 @@ export const createZoneStore = () => { const updatedZones: Zone[] = []; set(state => { + const newZones: Zone[] = []; + for (const zone of state.zones) { const pointIndex = zone.points.findIndex(p => p.pointUuid === pointUuid); + if (pointIndex === -1) { - updatedZones.push(JSON.parse(JSON.stringify(zone))); + newZones.push(zone); continue; } @@ -89,11 +92,13 @@ export const createZoneStore = () => { removedZones.push(JSON.parse(JSON.stringify(zone))); continue; } - zone.points = remainingPoints; - updatedZones.push(JSON.parse(JSON.stringify(zone))); + + const updatedZone = { ...zone, points: remainingPoints }; + updatedZones.push(JSON.parse(JSON.stringify(updatedZone))); + newZones.push(updatedZone); } - state.zones = updatedZones; + state.zones = newZones; }); return { removedZones, updatedZones }; @@ -104,6 +109,7 @@ export const createZoneStore = () => { const updatedZones: Zone[] = []; set(state => { + const newZones: Zone[] = []; for (const zone of state.zones) { const indices = zone.points.map((p, i) => ({ uuid: p.pointUuid, index: i })); @@ -112,7 +118,7 @@ export const createZoneStore = () => { const idxB = indices.find(i => i.uuid === pointB.pointUuid)?.index ?? -1; if (idxA === -1 || idxB === -1) { - updatedZones.push(JSON.parse(JSON.stringify(zone))); + newZones.push(zone); continue; } @@ -122,7 +128,7 @@ export const createZoneStore = () => { (idxB === 0 && idxA === zone.points.length - 1); if (!areAdjacent) { - updatedZones.push(JSON.parse(JSON.stringify(zone))); + newZones.push(zone); continue; } @@ -131,14 +137,15 @@ export const createZoneStore = () => { ); if (remainingPoints.length > 2) { - zone.points = remainingPoints; - updatedZones.push(JSON.parse(JSON.stringify(zone))); + const updatedZone = { ...zone, points: remainingPoints }; + updatedZones.push(JSON.parse(JSON.stringify(updatedZone))); + newZones.push(updatedZone); } else { removedZones.push(JSON.parse(JSON.stringify(zone))); } } - state.zones = updatedZones; + state.zones = newZones; }); return { removedZones, updatedZones }; @@ -180,12 +187,32 @@ export const createZoneStore = () => { }); }, - getZoneByPoints: (points) => { - return get().zones.find(zone => { - const zonePointIds = new Set(zone.points.map(p => p.pointUuid)); - const givenPointIds = new Set(points.map(p => p.pointUuid)); - return zonePointIds.size === givenPointIds.size && [...zonePointIds].every(id => givenPointIds.has(id)); - }); + getZonesByPoints: ([pointA, pointB]) => { + const Zones: Zone[] = []; + + for (const zone of get().zones) { + const indices = zone.points.map((p, i) => ({ uuid: p.pointUuid, index: i })); + + const idxA = indices.find(i => i.uuid === pointA.pointUuid)?.index ?? -1; + const idxB = indices.find(i => i.uuid === pointB.pointUuid)?.index ?? -1; + + if (idxA === -1 || idxB === -1) { + continue; + } + + const areAdjacent = + Math.abs(idxA - idxB) === 1 || + (idxA === 0 && idxB === zone.points.length - 1) || + (idxB === 0 && idxA === zone.points.length - 1); + + if (!areAdjacent) { + continue; + } + + Zones.push(JSON.parse(JSON.stringify(zone))); + } + + return Zones; }, getZonePointById: (pointUuid) => { diff --git a/app/src/types/builderTypes.d.ts b/app/src/types/builderTypes.d.ts index b48cd12..318050a 100644 --- a/app/src/types/builderTypes.d.ts +++ b/app/src/types/builderTypes.d.ts @@ -215,3 +215,41 @@ interface Aisle { } type Aisles = Aisle[]; + + +// Undo/Redo 2D + +type UndoRedo2DDataTypeSchema = + | { type: 'Wall'; lineData: Wall; newData?: Wall; timeStamp: string } + | { type: 'Floor'; lineData: Floor; newData?: Floor; timeStamp: string } + | { type: 'Zone'; lineData: Zone; newData?: Zone; timeStamp: string } + | { type: 'Aisle'; lineData: Aisle; newData?: Aisle; timeStamp: string }; + +type UndoRedo2DLineActionSchema = { + actionType: 'Line-Create' | 'Line-Update' | 'Line-Delete'; + point: UndoRedo2DDataTypeSchema; +} + +type UndoRedo2DLinesActionSchema = { + actionType: 'Lines-Create' | 'Lines-Update' | 'Lines-Delete'; + points: UndoRedo2DDataTypeSchema[]; +} + +type UndoRedo2DAction = UndoRedo2DLineActionSchema | UndoRedo2DLinesActionSchema; + +type UndoRedo2DDraw = { + type: 'Draw'; + actions: UndoRedo2DAction[]; +}; + +type UndoRedo2DUi = { + type: 'UI'; + action: any; // Define UI actions as needed +} + +type UndoRedo2DTypes = UndoRedo2DDraw | UndoRedo2DUi + +type UndoRedo2D = { + undoStack: UndoRedo2DTypes[]; + redoStack: UndoRedo2DTypes[]; +}; \ No newline at end of file diff --git a/app/src/types/world/worldConstants.ts b/app/src/types/world/worldConstants.ts index 0fe8f72..71d9caf 100644 --- a/app/src/types/world/worldConstants.ts +++ b/app/src/types/world/worldConstants.ts @@ -1,375 +1,383 @@ const savedTheme: string | null = localStorage.getItem("theme"); export type Controls = { - azimuthRotateSpeed: number; - polarRotateSpeed: number; - truckSpeed: number; - minDistance: number; - maxDistance: number; - maxPolarAngle: number; - leftMouse: number; - forwardSpeed: number; - backwardSpeed: number; - leftSpeed: number; - rightSpeed: number; + azimuthRotateSpeed: number; + polarRotateSpeed: number; + truckSpeed: number; + minDistance: number; + maxDistance: number; + maxPolarAngle: number; + leftMouse: number; + forwardSpeed: number; + backwardSpeed: number; + leftSpeed: number; + rightSpeed: number; }; export type ThirdPersonControls = { - azimuthRotateSpeed: number; - polarRotateSpeed: number; - truckSpeed: number; - maxDistance: number; - maxPolarAngle: number; - minZoom: number; - maxZoom: number; - targetOffset: number; - cameraHeight: number; - leftMouse: number; - rightMouse: number; - wheelMouse: number; - middleMouse: number; + azimuthRotateSpeed: number; + polarRotateSpeed: number; + truckSpeed: number; + maxDistance: number; + maxPolarAngle: number; + minZoom: number; + maxZoom: number; + targetOffset: number; + cameraHeight: number; + leftMouse: number; + rightMouse: number; + wheelMouse: number; + middleMouse: number; }; export type ControlsTransition = { - leftMouse: number; - rightMouse: number; - wheelMouse: number; - middleMouse: number; + leftMouse: number; + rightMouse: number; + wheelMouse: number; + middleMouse: number; }; export type TwoDimension = { - defaultPosition: [x: number, y: number, z: number]; - defaultTarget: [x: number, y: number, z: number]; - defaultAzimuth: number; - minDistance: number; - leftMouse: number; - rightMouse: number; + defaultPosition: [x: number, y: number, z: number]; + defaultTarget: [x: number, y: number, z: number]; + defaultAzimuth: number; + minDistance: number; + leftMouse: number; + rightMouse: number; }; export type ThreeDimension = { - defaultPosition: [x: number, y: number, z: number]; - defaultTarget: [x: number, y: number, z: number]; - defaultRotation: [x: number, y: number, z: number]; - defaultAzimuth: number; - boundaryBottom: [x: number, y: number, z: number]; - boundaryTop: [x: number, y: number, z: number]; - minDistance: number; - leftMouse: number; - rightMouse: number; + defaultPosition: [x: number, y: number, z: number]; + defaultTarget: [x: number, y: number, z: number]; + defaultRotation: [x: number, y: number, z: number]; + defaultAzimuth: number; + boundaryBottom: [x: number, y: number, z: number]; + boundaryTop: [x: number, y: number, z: number]; + minDistance: number; + leftMouse: number; + rightMouse: number; }; export type GridConfig = { - size: number; - divisions: number; - primaryColor: string; - secondaryColor: string; - position2D: [x: number, y: number, z: number]; - position3D: [x: number, y: number, z: number]; + size: number; + divisions: number; + primaryColor: string; + secondaryColor: string; + position2D: [x: number, y: number, z: number]; + position3D: [x: number, y: number, z: number]; }; export type PlaneConfig = { - position2D: [x: number, y: number, z: number]; - position3D: [x: number, y: number, z: number]; - rotation: number; - width: number; - height: number; - color: string; + position2D: [x: number, y: number, z: number]; + position3D: [x: number, y: number, z: number]; + rotation: number; + width: number; + height: number; + color: string; }; export type ShadowConfig = { - shadowOffset: number; - shadowmapSizewidth: number; - shadowmapSizeheight: number; - shadowcamerafar: number; - shadowcameranear: number; - shadowcameratop: number; - shadowcamerabottom: number; - shadowcameraleft: number; - shadowcameraright: number; - shadowbias: number; - shadownormalBias: number; - shadowMaterialPosition: [x: number, y: number, z: number]; - shadowMaterialRotation: [x: number, y: number, z: number]; - shadowMaterialOpacity: number; + shadowOffset: number; + shadowmapSizewidth: number; + shadowmapSizeheight: number; + shadowcamerafar: number; + shadowcameranear: number; + shadowcameratop: number; + shadowcamerabottom: number; + shadowcameraleft: number; + shadowcameraright: number; + shadowbias: number; + shadownormalBias: number; + shadowMaterialPosition: [x: number, y: number, z: number]; + shadowMaterialRotation: [x: number, y: number, z: number]; + shadowMaterialOpacity: number; }; export type SkyConfig = { - defaultTurbidity: number; - maxTurbidity: number; - minTurbidity: number; - defaultRayleigh: number; - mieCoefficient: number; - mieDirectionalG: number; - skyDistance: number; + defaultTurbidity: number; + maxTurbidity: number; + minTurbidity: number; + defaultRayleigh: number; + mieCoefficient: number; + mieDirectionalG: number; + skyDistance: number; }; export type AssetConfig = { - defaultScaleBeforeGsap: [number, number, number]; - defaultScaleAfterGsap: [number, number, number]; + defaultScaleBeforeGsap: [number, number, number]; + defaultScaleAfterGsap: [number, number, number]; }; export type PointConfig = { - defaultInnerColor: string; - defaultOuterColor: string; - deleteColor: string; - boxScale: [number, number, number]; - wallOuterColor: string; - floorOuterColor: string; - aisleOuterColor: string; - zoneOuterColor: string; - snappingThreshold: number; - helperColor: string; + defaultInnerColor: string; + defaultOuterColor: string; + deleteColor: string; + boxScale: [number, number, number]; + wallOuterColor: string; + floorOuterColor: string; + aisleOuterColor: string; + zoneOuterColor: string; + snappingThreshold: number; + helperColor: string; }; export type LineConfig = { - tubularSegments: number; - radius: number; - radialSegments: number; - wallName: string; - floorName: string; - aisleName: string; - zoneName: string; - referenceName: string; - lineIntersectionPoints: number; - defaultColor: string; - wallColor: string; - floorColor: string; - aisleColor: string; - zoneColor: string; - deleteColor: string; - helperColor: string; + tubularSegments: number; + radius: number; + radialSegments: number; + wallName: string; + floorName: string; + aisleName: string; + zoneName: string; + referenceName: string; + lineIntersectionPoints: number; + defaultColor: string; + wallColor: string; + floorColor: string; + aisleColor: string; + zoneColor: string; + deleteColor: string; + helperColor: string; }; export type WallConfig = { - defaultColor: string; - height: number; - width: number; + defaultColor: string; + height: number; + width: number; }; export type FloorConfig = { - defaultColor: string; - height: number; - textureScale: number; + defaultColor: string; + height: number; + textureScale: number; }; export type RoofConfig = { - defaultColor: string; - height: number; + defaultColor: string; + height: number; }; export type AisleConfig = { - width: number; - height: number; - defaultColor: string; + width: number; + height: number; + defaultColor: string; }; export type ZoneConfig = { - defaultColor: string; - height: number; - color: string; + defaultColor: string; + height: number; + color: string; }; export type ColumnConfig = { - defaultColor: string; + defaultColor: string; }; export type OutlineConfig = { - assetSelectColor: number; - assetDeleteColor: number; + assetSelectColor: number; + assetDeleteColor: number; }; export type DistanceConfig = { - minDistance: number; - maxDistance: number; + minDistance: number; + maxDistance: number; +}; + +export type undoRedoCount = { + undoRedoCount: number; }; export const firstPersonControls: Controls = { - azimuthRotateSpeed: 0.3, // Speed of rotation around the azimuth axis - polarRotateSpeed: 0.3, // Speed of rotation around the polar axis - truckSpeed: 10, // Speed of truck movement - minDistance: 0, // Minimum distance from the target - maxDistance: 0, // Maximum distance from the target - maxPolarAngle: Math.PI, // Maximum polar angle - leftMouse: 1, // Mouse button for rotation (ROTATE) - forwardSpeed: 0.1, // Speed of forward movement - backwardSpeed: -0.1, // Speed of backward movement - leftSpeed: -0.1, // Speed of left movement - rightSpeed: 0.1, // Speed of right movement + azimuthRotateSpeed: 0.3, // Speed of rotation around the azimuth axis + polarRotateSpeed: 0.3, // Speed of rotation around the polar axis + truckSpeed: 10, // Speed of truck movement + minDistance: 0, // Minimum distance from the target + maxDistance: 0, // Maximum distance from the target + maxPolarAngle: Math.PI, // Maximum polar angle + leftMouse: 1, // Mouse button for rotation (ROTATE) + forwardSpeed: 0.1, // Speed of forward movement + backwardSpeed: -0.1, // Speed of backward movement + leftSpeed: -0.1, // Speed of left movement + rightSpeed: 0.1, // Speed of right movement }; export const thirdPersonControls: ThirdPersonControls = { - azimuthRotateSpeed: 1, // Speed of rotation around the azimuth axis - polarRotateSpeed: 1, // Speed of rotation around the polar axis - truckSpeed: 2, // Speed of truck movement - maxDistance: 100, // Maximum distance from the target - maxPolarAngle: Math.PI / 2 - 0.05, // Maximum polar angle - minZoom: 6, // Minimum zoom level - maxZoom: 100, // Maximum zoom level - targetOffset: 20, // Offset of the target from the camera - cameraHeight: 30, // Height of the camera - leftMouse: 2, // Mouse button for panning - rightMouse: 1, // Mouse button for rotation - wheelMouse: 8, // Mouse button for zooming - middleMouse: 8, // Mouse button for zooming + azimuthRotateSpeed: 1, // Speed of rotation around the azimuth axis + polarRotateSpeed: 1, // Speed of rotation around the polar axis + truckSpeed: 2, // Speed of truck movement + maxDistance: 100, // Maximum distance from the target + maxPolarAngle: Math.PI / 2 - 0.05, // Maximum polar angle + minZoom: 6, // Minimum zoom level + maxZoom: 100, // Maximum zoom level + targetOffset: 20, // Offset of the target from the camera + cameraHeight: 30, // Height of the camera + leftMouse: 2, // Mouse button for panning + rightMouse: 1, // Mouse button for rotation + wheelMouse: 8, // Mouse button for zooming + middleMouse: 8, // Mouse button for zooming }; export const controlsTransition: ControlsTransition = { - leftMouse: 0, // Mouse button for no action - rightMouse: 0, // Mouse button for no action - wheelMouse: 0, // Mouse button for no action - middleMouse: 0, // Mouse button for no action + leftMouse: 0, // Mouse button for no action + rightMouse: 0, // Mouse button for no action + wheelMouse: 0, // Mouse button for no action + middleMouse: 0, // Mouse button for no action }; export const twoDimension: TwoDimension = { - defaultPosition: [0, 100, 0], // Default position of the camera - defaultTarget: [0, 0, 0], // Default target of the camera - defaultAzimuth: 0, // Default azimuth of the camera - minDistance: 25, // Minimum distance from the target - leftMouse: 2, // Mouse button for panning - rightMouse: 0, // Mouse button for no action + defaultPosition: [0, 100, 0], // Default position of the camera + defaultTarget: [0, 0, 0], // Default target of the camera + defaultAzimuth: 0, // Default azimuth of the camera + minDistance: 25, // Minimum distance from the target + leftMouse: 2, // Mouse button for panning + rightMouse: 0, // Mouse button for no action }; export const camPositionUpdateInterval: number = 200; // Interval for updating the camera position export const gridConfig: GridConfig = { - size: 150, // Size of the grid - divisions: 75, // Number of divisions in the grid - primaryColor: savedTheme === "dark" ? "#131313" : "#d5d5d5", // Primary color of the grid - secondaryColor: savedTheme === "dark" ? "#434343" : "#e3e3e3", // Secondary color of the grid + size: 150, // Size of the grid + divisions: 75, // Number of divisions in the grid + primaryColor: savedTheme === "dark" ? "#131313" : "#d5d5d5", // Primary color of the grid + secondaryColor: savedTheme === "dark" ? "#434343" : "#e3e3e3", // Secondary color of the grid - position2D: [0, 0.1, 0], // Position of the grid in 2D view - position3D: [0, -0.5, 0], // Position of the grid in 3D view + position2D: [0, 0.1, 0], // Position of the grid in 2D view + position3D: [0, -0.5, 0], // Position of the grid in 3D view }; export const threeDimension: ThreeDimension = { - defaultPosition: [0, 40, 30], // Default position of the camera - defaultTarget: [0, 0, 0], // Default target of the camera - defaultRotation: [0, 0, 0], // Default rotation of the camera - defaultAzimuth: 0, // Default azimuth of the camera - boundaryBottom: [-gridConfig.size / 2, 0, -gridConfig.size / 2], // Bottom boundary of the camera movement - boundaryTop: [gridConfig.size / 2, 100, gridConfig.size / 2], // Top boundary of the camera movement - minDistance: 1, // Minimum distance from the target - leftMouse: 2, // Mouse button for panning - rightMouse: 1, // Mouse button for rotation + defaultPosition: [0, 40, 30], // Default position of the camera + defaultTarget: [0, 0, 0], // Default target of the camera + defaultRotation: [0, 0, 0], // Default rotation of the camera + defaultAzimuth: 0, // Default azimuth of the camera + boundaryBottom: [-gridConfig.size / 2, 0, -gridConfig.size / 2], // Bottom boundary of the camera movement + boundaryTop: [gridConfig.size / 2, 100, gridConfig.size / 2], // Top boundary of the camera movement + minDistance: 1, // Minimum distance from the target + leftMouse: 2, // Mouse button for panning + rightMouse: 1, // Mouse button for rotation }; export const planeConfig: PlaneConfig = { - position2D: [0, -0.5, 0], // Position of the plane - position3D: [0, -0.65, 0], // Position of the plane - rotation: -Math.PI / 2, // Rotation of the plane + position2D: [0, -0.5, 0], // Position of the plane + position3D: [0, -0.65, 0], // Position of the plane + rotation: -Math.PI / 2, // Rotation of the plane - width: 150, // Width of the plane - height: 150, // Height of the plane - color: savedTheme === "dark" ? "#323232" : "#f3f3f3", // Color of the plane + width: 150, // Width of the plane + height: 150, // Height of the plane + color: savedTheme === "dark" ? "#323232" : "#f3f3f3", // Color of the plane }; export const shadowConfig: ShadowConfig = { - shadowOffset: 50, // Offset of the shadow - // shadowmapSizewidth: 1024, // Width of the shadow map - // shadowmapSizeheight: 1024, // Height of the shadow map - shadowmapSizewidth: 2048, // Width of the shadow map - shadowmapSizeheight: 2048, // Height of the shadow map - // shadowmapSizewidth: 8192, // Width of the shadow map - // shadowmapSizeheight: 8192, // Height of the shadow map - shadowcamerafar: 70, // Far plane of the shadow camera - shadowcameranear: 0.1, // Near plane of the shadow camera - shadowcameratop: 30, // Top plane of the shadow camera - shadowcamerabottom: -30, // Bottom plane of the shadow camera - shadowcameraleft: -30, // Left plane of the shadow camera - shadowcameraright: 30, // Right plane of the shadow camera - shadowbias: -0.001, // Bias of the shadow - shadownormalBias: 0.02, // Normal bias of the shadow - shadowMaterialPosition: [0, 0.01, 0], // Position of the shadow material - shadowMaterialRotation: [-Math.PI / 2, 0, 0], // Rotation of the shadow material - shadowMaterialOpacity: 0.1, // Opacity of the shadow material + shadowOffset: 50, // Offset of the shadow + // shadowmapSizewidth: 1024, // Width of the shadow map + // shadowmapSizeheight: 1024, // Height of the shadow map + shadowmapSizewidth: 2048, // Width of the shadow map + shadowmapSizeheight: 2048, // Height of the shadow map + // shadowmapSizewidth: 8192, // Width of the shadow map + // shadowmapSizeheight: 8192, // Height of the shadow map + shadowcamerafar: 70, // Far plane of the shadow camera + shadowcameranear: 0.1, // Near plane of the shadow camera + shadowcameratop: 30, // Top plane of the shadow camera + shadowcamerabottom: -30, // Bottom plane of the shadow camera + shadowcameraleft: -30, // Left plane of the shadow camera + shadowcameraright: 30, // Right plane of the shadow camera + shadowbias: -0.001, // Bias of the shadow + shadownormalBias: 0.02, // Normal bias of the shadow + shadowMaterialPosition: [0, 0.01, 0], // Position of the shadow material + shadowMaterialRotation: [-Math.PI / 2, 0, 0], // Rotation of the shadow material + shadowMaterialOpacity: 0.1, // Opacity of the shadow material }; export const skyConfig: SkyConfig = { - defaultTurbidity: 10.0, // Default turbidity of the sky - maxTurbidity: 20.0, // Maximum turbidity of the sky - minTurbidity: 0.0, // Minimum turbidity of the sky - defaultRayleigh: 1.9, // Default Rayleigh scattering coefficient - mieCoefficient: 0.1, // Mie scattering coefficient - mieDirectionalG: 1.0, // Mie directional G - skyDistance: 2000, // Distance of the sky + defaultTurbidity: 10.0, // Default turbidity of the sky + maxTurbidity: 20.0, // Maximum turbidity of the sky + minTurbidity: 0.0, // Minimum turbidity of the sky + defaultRayleigh: 1.9, // Default Rayleigh scattering coefficient + mieCoefficient: 0.1, // Mie scattering coefficient + mieDirectionalG: 1.0, // Mie directional G + skyDistance: 2000, // Distance of the sky }; export const assetConfig: AssetConfig = { - defaultScaleBeforeGsap: [0.1, 0.1, 0.1], // Default scale of the assets - defaultScaleAfterGsap: [1, 1, 1], // Default scale of the assets + defaultScaleBeforeGsap: [0.1, 0.1, 0.1], // Default scale of the assets + defaultScaleAfterGsap: [1, 1, 1], // Default scale of the assets }; export const pointConfig: PointConfig = { - defaultInnerColor: "#ffffff", // Default inner color of the points - defaultOuterColor: "#ffffff", // Default outer color of the points - deleteColor: "#ff0000", // Color of the points when deleting - boxScale: [0.5, 0.5, 0.5], // Scale of the points - wallOuterColor: "#C7C7C7", // Outer color of the wall points - floorOuterColor: "#808080", // Outer color of the floor points - aisleOuterColor: "#FBBC05", // Outer color of the aisle points - zoneOuterColor: "#007BFF", // Outer color of the zone points - snappingThreshold: 1, // Threshold for snapping - helperColor: "#C164FF", // Color of the helper lines + defaultInnerColor: "#ffffff", // Default inner color of the points + defaultOuterColor: "#ffffff", // Default outer color of the points + deleteColor: "#ff0000", // Color of the points when deleting + boxScale: [0.5, 0.5, 0.5], // Scale of the points + wallOuterColor: "#C7C7C7", // Outer color of the wall points + floorOuterColor: "#808080", // Outer color of the floor points + aisleOuterColor: "#FBBC05", // Outer color of the aisle points + zoneOuterColor: "#007BFF", // Outer color of the zone points + snappingThreshold: 1, // Threshold for snapping + helperColor: "#C164FF", // Color of the helper lines }; export const lineConfig: LineConfig = { - tubularSegments: 64, // Number of tubular segments - radius: 0.15, // Radius of the lines - radialSegments: 8, // Number of radial segments - wallName: "WallLine", // Name of the wall lines - floorName: "FloorLine", // Name of the floor lines - aisleName: "AisleLine", // Name of the aisle lines - zoneName: "ZoneLine", // Name of the zone lines - referenceName: "ReferenceLine", // Name of the reference lines - lineIntersectionPoints: 300, // Number of intersection points - defaultColor: "#000000", // Default color of the lines - wallColor: "#C7C7C7", // Color of the wall lines - floorColor: "#808080", // Color of the floor lines - aisleColor: "#FBBC05", // Color of the aisle lines - zoneColor: "#007BFF", // Color of the zone lines - deleteColor: "#ff0000", // Color of the line when deleting - helperColor: "#C164FF", // Color of the helper lines + tubularSegments: 64, // Number of tubular segments + radius: 0.15, // Radius of the lines + radialSegments: 8, // Number of radial segments + wallName: "WallLine", // Name of the wall lines + floorName: "FloorLine", // Name of the floor lines + aisleName: "AisleLine", // Name of the aisle lines + zoneName: "ZoneLine", // Name of the zone lines + referenceName: "ReferenceLine", // Name of the reference lines + lineIntersectionPoints: 300, // Number of intersection points + defaultColor: "#000000", // Default color of the lines + wallColor: "#C7C7C7", // Color of the wall lines + floorColor: "#808080", // Color of the floor lines + aisleColor: "#FBBC05", // Color of the aisle lines + zoneColor: "#007BFF", // Color of the zone lines + deleteColor: "#ff0000", // Color of the line when deleting + helperColor: "#C164FF", // Color of the helper lines }; export const wallConfig: WallConfig = { - defaultColor: "#f2f2f2", // Default color of the walls - height: 7.5, // Height of the walls - width: 0.05, // Width of the walls + defaultColor: "#f2f2f2", // Default color of the walls + height: 7.5, // Height of the walls + width: 0.05, // Width of the walls }; export const floorConfig: FloorConfig = { - defaultColor: "grey", // Default color of the floors - height: 0.1, // Height of the floors - textureScale: 1, // Scale of the floor texture + defaultColor: "grey", // Default color of the floors + height: 0.1, // Height of the floors + textureScale: 1, // Scale of the floor texture }; export const roofConfig: RoofConfig = { - defaultColor: "grey", // Default color of the roofs - height: 0.1, // Height of the roofs + defaultColor: "grey", // Default color of the roofs + height: 0.1, // Height of the roofs }; export const aisleConfig: AisleConfig = { - width: 0.1, // Width of the aisles - height: 0.01, // Height of the aisles - defaultColor: '#E2AC09', // Default color of the aisles + width: 0.1, // Width of the aisles + height: 0.01, // Height of the aisles + defaultColor: '#E2AC09', // Default color of the aisles }; export const zoneConfig: ZoneConfig = { - defaultColor: "black", // Default color of the zones - height: 3, - color: "#8656DF", // Color of the zones + defaultColor: "black", // Default color of the zones + height: 3, + color: "#8656DF", // Color of the zones }; export const columnConfig: ColumnConfig = { - defaultColor: "White", // Default color of the columns + defaultColor: "White", // Default color of the columns }; export const outlineConfig: OutlineConfig = { - assetSelectColor: 0x0054fe, // Color of the selected assets - assetDeleteColor: 0xff0000, // Color of the deleted assets + assetSelectColor: 0x0054fe, // Color of the selected assets + assetDeleteColor: 0xff0000, // Color of the deleted assets }; export const distanceConfig: DistanceConfig = { - minDistance: 20, - maxDistance: 75, + minDistance: 20, + maxDistance: 75, }; + +export const undoRedoConfig: undoRedoCount = { + undoRedoCount: 50, +} \ No newline at end of file