From a0e5115c6c2fd2cb8ea0cfca2d18621a9bb7c60c Mon Sep 17 00:00:00 2001 From: Poovizhi Date: Thu, 28 Aug 2025 09:43:42 +0530 Subject: [PATCH] added available paths --- .../instances/animator/vehicleAnimator.tsx | 1 + .../vehicle/pathCreator/function/getPaths.ts | 29 +- .../pathCreator/function/usePathManager.ts | 46 ++ .../vehicle/pathCreator/pathCreator.tsx | 79 +- .../vehicle/pathCreator/pathHandler.tsx | 11 +- .../vehicle/pathCreator/pointHandler.tsx | 530 +++++++++++--- .../vehicle/structuredPath/pointHandlers.tsx | 12 +- .../modules/simulation/vehicle/vehicles.tsx | 2 +- app/src/store/builder/store.ts | 691 +++++++++--------- 9 files changed, 931 insertions(+), 470 deletions(-) create mode 100644 app/src/modules/simulation/vehicle/pathCreator/function/usePathManager.ts diff --git a/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx b/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx index 184111e..208f879 100644 --- a/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx +++ b/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx @@ -172,6 +172,7 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai } } + }); const updatePoint = (index: number, pos: THREE.Vector3) => { diff --git a/app/src/modules/simulation/vehicle/pathCreator/function/getPaths.ts b/app/src/modules/simulation/vehicle/pathCreator/function/getPaths.ts index af6836e..bdf560b 100644 --- a/app/src/modules/simulation/vehicle/pathCreator/function/getPaths.ts +++ b/app/src/modules/simulation/vehicle/pathCreator/function/getPaths.ts @@ -29,19 +29,20 @@ export const getPathsByPointId = (pointId: any, paths: PathData) => { export const setPathPosition = ( pointUuid: string, position: [number, number, number], - setPaths: React.Dispatch> + setPaths: React.Dispatch>, + paths: PathData ) => { - setPaths((prevPaths) => - prevPaths.map((path: any) => { - if (path?.pathPoints.some((p: any) => p.pointId === pointUuid)) { - return { - ...path, - pathPoints: path.pathPoints.map((p: any) => - p.pointId === pointUuid ? { ...p, position } : p - ) as [PointData, PointData], // πŸ‘ˆ force back to tuple - }; - } - return path; - }) - ); + const newPaths = paths.map((path: any) => { + if (path?.pathPoints.some((p: any) => p.pointId === pointUuid)) { + return { + ...path, + pathPoints: path.pathPoints.map((p: any) => + p.pointId === pointUuid ? { ...p, position } : p + ) as [PointData, PointData], // πŸ‘ˆ force back to tuple + }; + } + return path; + }); + + setPaths(newPaths); }; diff --git a/app/src/modules/simulation/vehicle/pathCreator/function/usePathManager.ts b/app/src/modules/simulation/vehicle/pathCreator/function/usePathManager.ts new file mode 100644 index 0000000..646e1e8 --- /dev/null +++ b/app/src/modules/simulation/vehicle/pathCreator/function/usePathManager.ts @@ -0,0 +1,46 @@ +import { useCallback, useEffect, useMemo } from "react"; +import { useCreatedPaths } from "../../../../../store/builder/store"; + +export const usePathManager = (pathId?: string, vehicleId?: string | null) => { + const { paths, allPaths, setAllPaths } = useCreatedPaths(); + console.log("allPaths: ", allPaths); + + useEffect(() => { + if (!paths || paths.length === 0) return; + + const newPaths = paths.map((val: any) => ({ + pathId: val.pathId, + isAvailable: true, + vehicleId: null, + })); + + const merged = [...allPaths]; + newPaths.forEach((p: any) => { + if (!merged.find((m) => m.pathId === p.pathId)) { + merged.push(p); + } + }); + + if (merged.length !== allPaths.length) { + setAllPaths(merged); + } + }, [paths, allPaths, setAllPaths]); + + useEffect(() => { + if (!pathId || !vehicleId) return; + + const updated = allPaths.map((p: any) => + p.pathId === pathId ? { ...p, vehicleId, isAvailable: false } : p + ); + + const hasChanged = JSON.stringify(updated) !== JSON.stringify(allPaths); + if (hasChanged) { + setAllPaths(updated); + } + }, [pathId, vehicleId, allPaths, setAllPaths]); + + return useMemo(() => { + if (!pathId) return undefined; + return allPaths.find((p: any) => p.pathId === pathId); + }, [pathId, allPaths]); +}; diff --git a/app/src/modules/simulation/vehicle/pathCreator/pathCreator.tsx b/app/src/modules/simulation/vehicle/pathCreator/pathCreator.tsx index 1722fe9..7e7b64e 100644 --- a/app/src/modules/simulation/vehicle/pathCreator/pathCreator.tsx +++ b/app/src/modules/simulation/vehicle/pathCreator/pathCreator.tsx @@ -8,10 +8,9 @@ import React, { useState, } from "react"; import { LineCurve3, MathUtils, Plane, Vector3 } from "three"; -import { Vector3Array } from "../../../../types/world/worldTypes"; import { - useActiveSubTool, useActiveTool, + useCreatedPaths, useToolMode, } from "../../../../store/builder/store"; import PointHandler from "./pointHandler"; @@ -36,15 +35,19 @@ interface PathDataInterface { type PathData = PathDataInterface[]; export default function PathCreator() { - const [paths, setPaths] = useState([]); + // const [paths, setPaths] = useState([]); + // const [paths, setPaths] = useState(() => { + // const stored = localStorage.getItem("paths"); + // return stored ? JSON.parse(stored) : []; + // }); + const { paths, setPaths } = useCreatedPaths(); + const { activeTool } = useActiveTool(); + const { toolMode } = useToolMode(); + const [draftPoints, setDraftPoints] = useState([]); const [mousePos, setMousePos] = useState<[number, number, number] | null>( null ); - const { toolMode } = useToolMode(); - - const plane = useMemo(() => new Plane(new Vector3(0, 1, 0), 0), []); - const { scene, raycaster, gl } = useThree(); const [snappedPosition, setSnappedPosition] = useState< [number, number, number] | null >(null); @@ -54,21 +57,33 @@ export default function PathCreator() { null ); const [hoveredPoint, setHoveredPoint] = useState(null); - - const { activeSubTool } = useActiveSubTool(); - const { activeTool } = useActiveTool(); const [pathPointsList, setPathPointsList] = useState([]); + const [selectedPointIndices, setSelectedPointIndices] = useState( + [] + ); + const plane = useMemo(() => new Plane(new Vector3(0, 1, 0), 0), []); + + const { scene, raycaster, gl } = useThree(); + const POINT_SNAP_THRESHOLD = 0.5; const CAN_POINT_SNAP = true; + useEffect(() => {}, [paths]); + const getAllOtherPathPoints = useCallback((): PointData[] => { if (draftPoints.length === 0) return []; return ( - paths?.flatMap((path) => - path.pathPoints.filter((pt) => pt.pointId !== draftPoints[0].pointId) + paths?.flatMap((path: any) => + path.pathPoints.filter( + (pt: PointData) => pt.pointId !== draftPoints[0].pointId + ) ) ?? [] ); }, [paths, draftPoints]); + useEffect(() => { + const stored = localStorage.getItem("paths"); + setPaths(stored ? JSON.parse(stored) : []); + }, []); const snapPathPoint = useCallback( (position: [number, number, number]) => { @@ -134,13 +149,11 @@ export default function PathCreator() { }); useEffect(() => {}, [paths]); + const getPathPointById = (uuid: any) => { for (const path of paths) { - const point = path.pathPoints.find((p) => p.pointId === uuid); - console.log( - "point: ", - path.pathPoints.map((val) => val) - ); + const point = path.pathPoints.find((p: PointData) => p.pointId === uuid); + if (point) return point; } return undefined; @@ -170,7 +183,9 @@ export default function PathCreator() { paths ); if (clickedPath) { - const hitPath = paths.find((p) => p.pathId === clickedPath.pathId); + const hitPath = paths.find( + (p: PathDataInterface) => p.pathId === clickedPath.pathId + ); if (!hitPath) return; @@ -197,7 +212,13 @@ export default function PathCreator() { t = Math.max(0, Math.min(1, t)); const closestPoint = new Vector3().lerpVectors(point1Vec, point2Vec, t); - setPaths((prev) => prev.filter((p) => p.pathId !== clickedPath.pathId)); + const filteredPath = paths.filter( + (p: PathDataInterface) => p.pathId !== clickedPath.pathId + ); + setPaths(filteredPath); + // setPaths((prev: PathData) => + // prev.filter((p) => p.pathId !== clickedPath.pathId) + // ); const point1: PointData = { pointId: clickedPath?.pathPoints[0].pointId, @@ -222,7 +243,8 @@ export default function PathCreator() { pathPoints: [point2, splitPoint], }; setDraftPoints([splitPoint]); - setPaths((prev) => [...prev, path1, path2]); + + setPaths([...paths, path1, path2]); } else { const newPath: PathDataInterface = { pathId: MathUtils.generateUUID(), @@ -237,7 +259,8 @@ export default function PathCreator() { pathPoints: [point2, splitPoint], }; - setPaths((prev) => [...prev, newPath, firstPath, secondPath]); + setPaths([...paths, newPath, firstPath, secondPath]); + setDraftPoints([splitPoint]); } @@ -287,8 +310,7 @@ export default function PathCreator() { pathId: MathUtils.generateUUID(), pathPoints: [draftPoints[0], newPoint], }; - - setPaths((prev) => [...prev, newPath]); + setPaths([...paths, newPath]); setDraftPoints([newPoint]); } }; @@ -322,7 +344,8 @@ export default function PathCreator() { const allPoints = useMemo(() => { const points: PointData[] = []; const seen = new Set(); - paths.forEach((path) => { + console.log("paths: ", paths); + paths?.forEach((path: PathDataInterface) => { path.pathPoints.forEach((p) => { if (!seen.has(p.pointId)) { seen.add(p.pointId); @@ -334,8 +357,10 @@ export default function PathCreator() { }, [paths]); useEffect(() => { - console.log("allPoints: ", allPoints); + console.log("paths ", paths); + localStorage.setItem("paths", JSON.stringify(paths)); }, [paths]); + return ( <> {/* Draft points (red) */} @@ -358,6 +383,8 @@ export default function PathCreator() { setHoveredPoint={setHoveredPoint} hoveredLine={hoveredLine} hoveredPoint={hoveredPoint} + selected={selectedPointIndices} + setSelected={setSelectedPointIndices} /> ))} @@ -372,7 +399,7 @@ export default function PathCreator() { )} {/* Permanent paths */} - {paths.map((path) => ( + {paths.map((path: PathDataInterface) => ( new Vector3(...p.position)); return new LineCurve3(start, end); }, [points]); + const removePath = (pathId: string) => { setPaths((prevPaths) => prevPaths.filter((p) => p.pathId !== pathId)); }; + const handlePathClick = (pointId: string) => { if (toolMode === "3D-Delete") { removePath(pointId); } }; + const handleDragStart = (points: [PointData, PointData]) => { if (activeTool !== "cursor") return; const intersectionPoint = new Vector3(); @@ -77,6 +80,7 @@ export default function PathHandler({ setInitialPositions({ paths: pathSet }); } }; + // const handleDrag = (points: [PointData, PointData]) => { // if (isHovered && dragOffset) { // const intersectionPoint = new Vector3(); @@ -106,7 +110,7 @@ export default function PathHandler({ // } // } // }; - + const handleDrag = (points: [PointData, PointData]) => { if (isHovered && dragOffset) { const intersectionPoint = new Vector3(); @@ -135,13 +139,14 @@ export default function PathHandler({ ]; // βœ… Move both points separately (won’t overwrite other updates) - setPathPosition(points[0].pointId, newStart, setPaths); - setPathPosition(points[1].pointId, newEnd, setPaths); + setPathPosition(points[0].pointId, newStart, setPaths, paths); + setPathPosition(points[1].pointId, newEnd, setPaths, paths); } } }; const handleDragEnd = (points: [PointData, PointData]) => {}; + return ( <> >; }; function dist(a: PointData, b: PointData): number { return Math.sqrt( @@ -39,6 +57,13 @@ function dist(a: PointData, b: PointData): number { (a.position[2] - b.position[2]) ** 2 ); } +type SegmentPoint = { + position: Vector3; + originalPoint?: PointData; + pathId?: string; + startId?: string; + endId?: string; +}; /** --- A* Algorithm --- */ type AStarResult = { @@ -153,16 +178,31 @@ function nodePathToEdges( return edges; } +type VehicleDetails = { + vehicleId: string; + vehiclePosition: [number, number, number]; +}; +type Manager = { + pathId: string; + vehicleId: string; +}; export default function PointHandler({ point, - setPaths, - paths, + // setPaths, + // paths, setHoveredPoint, hoveredLine, hoveredPoint, pointIndex, points, + setSelected, + selected, }: PointHandlerProps) { + const { isPlaying } = usePlayButtonStore(); + const [multiPaths, setMultiPaths] = useState< + { id: number; path: PathData }[] + >([]); + const pathIdRef = useRef(1); // To ensure unique incremental IDs const { toolMode } = useToolMode(); const { activeTool } = useActiveTool(); const { scene, raycaster } = useThree(); @@ -172,29 +212,82 @@ export default function PointHandler({ const [initialPositions, setInitialPositions] = useState<{ paths?: any; }>({}); - const [selectedPoints, setSelectedPoints] = useState([]); - const [shortestEdges, setShortestEdges] = useState([]); + const [shortestPaths, setShortestPaths] = useState([]); const POINT_SNAP_THRESHOLD = 0.5; // Distance threshold for snapping in meters - const [selectedPointIndices, setSelectedPointIndices] = useState( - [] - ); + const [vehicleUuids, setVehicleUuids] = useState(); const CAN_POINT_SNAP = true; const CAN_ANGLE_SNAP = true; const ANGLE_SNAP_DISTANCE_THRESHOLD = 0.5; + const [selectedPointIndices, setSelectedPointIndices] = useState( + [] + ); + const [shortestEdges, setShortestEdges] = useState([]); + const { speed } = useAnimationPlaySpeed(); + const { assetStore } = useSceneContext(); + const { assets } = assetStore(); + const vehicleMovementState = useRef({}); + const [activeVehicleIndex, setActiveVehicleIndex] = useState(0); + const [vehicleData, setVehicleData] = useState([]); + const { paths, setPaths } = useCreatedPaths(); + const [managerData, setManagerData] = useState(); + // useEffect(() => { + // const findVehicle = assets + // .filter((val) => val.eventData?.type === "Vehicle") + // ?.map((val) => val.modelUuid); + + // + // setVehicleUuids(findVehicle); + + // vehicleMovementState.current = {}; + // findVehicle.forEach((uuid) => { + // vehicleMovementState.current[uuid] = { index: 0, progress: 0 }; + // }); + // }, [assets]); + useEffect(() => { + const findVehicle = assets + .filter((val) => val.eventData?.type === "Vehicle") + ?.map((val) => val.modelUuid); + const findVehicleDatas = assets + .filter((val) => val.eventData?.type === "Vehicle") + ?.map((val) => val); + findVehicleDatas.forEach((val) => { + const vehicledId = val.modelUuid; + const vehiclePosition: [number, number, number] = val.position; + + setVehicleData((prev) => [ + ...prev, + { vehicleId: vehicledId, vehiclePosition }, + ]); + }); + + setVehicleUuids(findVehicle); + setActiveVehicleIndex(0); // Reset to first vehicle + + vehicleMovementState.current = {}; + findVehicle.forEach((uuid) => { + vehicleMovementState.current[uuid] = { + index: 0, + progress: 0, + hasStarted: false, + }; + }); + }, [assets]); const removePathByPoint = (pointId: string): PathDataInterface[] => { const removedPaths: PathDataInterface[] = []; - setPaths((prevPaths) => - prevPaths.filter((path) => { - const hasPoint = path.pathPoints.some((p) => p.pointId === pointId); - if (hasPoint) { - removedPaths.push(JSON.parse(JSON.stringify(path))); // keep a copy - return false; // remove this path - } - return true; // keep this path - }) - ); + const newPaths = paths.filter((path: PathDataInterface) => { + const hasPoint = path.pathPoints.some( + (p: PointData) => p.pointId === pointId + ); + if (hasPoint) { + removedPaths.push(JSON.parse(JSON.stringify(path))); // keep a copy + return false; // remove this path + } + return true; // keep this path + }); + + setPaths(newPaths); return removedPaths; }; @@ -288,8 +381,8 @@ export default function PointHandler({ const getAllOtherPathPoints = useCallback((): PointData[] => { return ( - paths?.flatMap((path) => - path.pathPoints.filter((pt) => pt.pointId !== point.pointId) + paths?.flatMap((path: PathDataInterface) => + path.pathPoints.filter((pt: PointData) => pt.pointId !== point.pointId) ) ?? [] ); }, [paths]); @@ -317,43 +410,7 @@ export default function PointHandler({ }, [getAllOtherPathPoints] ); - let isHandlingShiftClick = false; - // const handlePointClick = (e: any, point: PointData) => { - // if (toolMode === "3D-Delete") { - // removePathByPoint(point.pointId); - // } - // if (e.shiftKey) { - // setSelectedPointIndices((prev) => { - // if (prev.length === 0) return [pointIndex]; - // if (prev.length === 1) { - // // defer shortest path calculation - // setTimeout(() => { - // console.log("points: ", points); - // const p1 = points[prev[0]]; - // console.log(' p1: ', p1); - // const p2 = points[pointIndex]; - // console.log('p2: ', p2); - // const result = aStarShortestPath( - // p1.pointId, - // p2.pointId, - // points, - // paths - // ); - // if (result) { - // const edges = nodePathToEdges(result.pointIds, points, paths); - // console.log("edges: ", edges); - // setShortestEdges(edges); - // } else { - // setShortestEdges([]); - // } - // }, 0); - // return [prev[0], pointIndex]; - // } - // return [pointIndex]; - // }); - // } - // }; const handlePointClick = (e: any, point: PointData) => { e.stopPropagation(); if (toolMode === "3D-Delete") { @@ -362,53 +419,82 @@ export default function PointHandler({ } if (e.shiftKey) { - if (isHandlingShiftClick) return; // prevent double-handling - isHandlingShiftClick = true; - - setTimeout(() => { - isHandlingShiftClick = false; - }, 100); // reset the flag after a short delay - - setSelectedPointIndices((prev) => { - // console.log("Clicked point index:", pointIndex); - console.log("Previous selection:", prev); + const pointIndex = points.findIndex((p) => p.pointId === point.pointId); + if (pointIndex === -1) { + return; + } + setSelected((prev) => { if (prev.length === 0) { - console.log("first works"); return [pointIndex]; } + // if (prev.length === 1) { + // setTimeout(() => { + // + // const prevPoint = points[prev[0]]; + // + // const newPoint = points[pointIndex]; + // + // const result = aStarShortestPath( + // prevPoint.pointId, + // newPoint.pointId, + // points, + // paths + // ); + // if (result) { + // const edges = nodePathToEdges(result.pointIds, points, paths); + // + // setShortestPaths(edges); + // setShortestEdges(edges); + // } else { + // setShortestPaths([]); + // setShortestEdges([]); + // } + // if (prevPoint.pointId === newPoint.pointId) { + // return prev; + // } + // }, 0); + + // return [prev[0], pointIndex]; + // } + + // More than two points β€” reset if (prev.length === 1) { - if (prev[0] === pointIndex) { - console.log("Same point selected twice β€” ignoring"); - return prev; - } + setTimeout(() => { + const prevPoint = points[prev[0]]; + const newPoint = points[pointIndex]; - const p1 = points[prev[0]]; - const p2 = points[pointIndex]; + if (prevPoint.pointId === newPoint.pointId) return; - console.log("Point 1:", p1); - console.log("Point 2:", p2); - - if (p1 && p2) { const result = aStarShortestPath( - p1.pointId, - p2.pointId, + prevPoint.pointId, + newPoint.pointId, points, paths ); if (result) { const edges = nodePathToEdges(result.pointIds, points, paths); + + // Create a new path object + const newPathObj = { + id: pathIdRef.current++, + path: edges, + }; + setShortestPaths(edges); setShortestEdges(edges); - } else { - setShortestEdges([]); + // Append it to the list of paths + setMultiPaths((prevPaths) => [...prevPaths, newPathObj]); } - } + + // Reset selection to allow new pair selection + }, 0); return [prev[0], pointIndex]; } + setShortestPaths([]); return [pointIndex]; }); } @@ -426,6 +512,7 @@ export default function PointHandler({ setInitialPositions({ paths: pathIntersection }); } }; + const handleDrag = (point: PointData) => { if (isHovered && dragOffset) { const intersectionPoint = new Vector3(); @@ -442,7 +529,7 @@ export default function PointHandler({ // βœ… Pass newPosition and pointId const pathSnapped = snapPathAngle(newPosition, point.pointId); const finalSnapped = snapPathPoint(pathSnapped.position); - setPathPosition(point.pointId, finalSnapped.position, setPaths); + setPathPosition(point.pointId, finalSnapped.position, setPaths, paths); } } }; @@ -454,10 +541,265 @@ export default function PointHandler({ } }; - useEffect(() => { - console.log("selectedPoints: ", selectedPoints); - }, [selectedPoints]); + const pathSegments = useMemo(() => { + if (!shortestPaths || shortestPaths.length === 0) return []; + const segments: SegmentPoint[] = []; + + shortestPaths.forEach((path) => { + const [start, end] = path.pathPoints; + + const startPos = new Vector3(...start.position); + const endPos = new Vector3(...end.position); + + segments.push( + { position: startPos, originalPoint: start, startId: start.pointId }, + { position: endPos, originalPoint: end, endId: end.pointId } + ); + }); + + return segments.filter( + (v, i, arr) => i === 0 || !v.position.equals(arr[i - 1].position) + ); + }, [shortestPaths]); + + // useFrame((_, delta) => { + // if (!isPlaying || pathSegments.length < 2) return; + + // vehicleUuids.forEach((uuid: any) => { + // const object = scene.getObjectByProperty("uuid", uuid); + // if (!object) return; + + // const state = vehicleMovementState.current[uuid]; + // if (!state) return; + + // const startSeg = pathSegments[state.index]; + // const endSeg = pathSegments[state.index + 1]; + // if (!startSeg || !endSeg) return; + + // const segmentDistance = startSeg.position.distanceTo(endSeg.position); + // state.progress += (speed * delta) / segmentDistance; + + // while (state.progress >= 1) { + // state.progress -= 1; + // state.index++; + // if (state.index >= pathSegments.length - 1) { + // state.index = 0; + // state.progress = 0; + // object.position.copy(pathSegments[0].position); + // object.quaternion.identity(); // reset rotation + // } + // } + + // const newPos = startSeg.position + // .clone() + // .lerp(endSeg.position, state.progress); + // object.position.copy(newPos); + + // const forward = new Vector3(0, 0, 1); + // const targetDir = endSeg.position + // .clone() + // .sub(startSeg.position) + // .normalize(); + // const targetQuat = new Quaternion().setFromUnitVectors( + // forward, + // targetDir + // ); + + // object.quaternion.slerp(targetQuat, 0.1); + // }); + // }); + + function getPathIdByPoints( + startId: string | undefined, + endId: string | undefined, + shortestPaths: any[] + ) { + for (const path of shortestPaths) { + for (let i = 0; i < path.pathPoints.length - 1; i++) { + const s = path.pathPoints[i]; + const e = path.pathPoints[i + 1]; + + if ( + (s.pointId === startId && e.pointId === endId) || + (s.pointId === endId && e.pointId === startId) // handle both directions + ) { + return path.pathId; + } + } + } + return null; // not found + } + + // + useFrame((_, delta) => { + // + if (!isPlaying || pathSegments.length < 2 || vehicleData.length === 0) + return; + + const vehicle = vehicleData[activeVehicleIndex]; + if (!vehicle) return; + + const uuid = vehicle.vehicleId; + const vehicleStartPos = new Vector3(...vehicle.vehiclePosition); + + const object = scene.getObjectByProperty("uuid", uuid); + if (!object) return; + + const state = vehicleMovementState.current[uuid]; + if (!state) return; + + const pathStart = pathSegments[0].position; + + // Step 1: Move vehicle to the start of the path + if (!state.hasStarted) { + const distanceToStart = object.position.distanceTo(pathStart); + const step = speed * delta; + + if (distanceToStart <= step) { + object.position.copy(pathStart); + object.quaternion.identity(); + state.hasStarted = true; // start path animation next frame + return; + } + + // Move toward path start + const direction = pathStart.clone().sub(object.position); + const distance = direction.length(); + + if (distance > step) { + direction.normalize(); + object.position.add(direction.clone().multiplyScalar(step)); + + // ROTATE toward direction of movement + const forward = new Vector3(0, 0, 1); // <-- adjust this based on your model + const targetQuat = new Quaternion().setFromUnitVectors( + forward, + direction + ); + object.quaternion.slerp(targetQuat, 0.1); // smooth rotation + } else { + // Snap to start segment when close enough + object.position.copy(pathStart); + object.quaternion.identity(); // reset orientation or leave as-is + vehicleMovementState.current[uuid] = { index: 0, progress: 0 }; + } + + return; // still approaching start + } + + // Step 2: Follow the path + const startSeg = pathSegments[state.index]; + const endSeg = pathSegments[state.index + 1]; + if (!startSeg || !endSeg) return; + const currentPathId = getPathIdByPoints( + startSeg.startId || startSeg.endId, + endSeg.endId || endSeg.startId, + shortestPaths + ); + setManagerData({ pathId: currentPathId, vehicleId: uuid }); + + const segmentDistance = startSeg.position.distanceTo(endSeg.position); + state.progress += (speed * delta) / segmentDistance; + + while (state.progress >= 1) { + state.progress -= 1; + state.index++; + + if (state.index >= pathSegments.length - 1) { + // Path complete + state.index = 0; + state.progress = 0; + state.hasStarted = false; // reset for next loop + object.position.copy(vehicleStartPos); // go back to start + object.quaternion.identity(); + + // Move to next vehicle + setActiveVehicleIndex((prevIndex) => + prevIndex + 1 >= vehicleData.length ? 0 : prevIndex + 1 + ); + + return; + } + } + + const newPos = startSeg.position + .clone() + .lerp(endSeg.position, state.progress); + object.position.copy(newPos); + + const forward = new Vector3(0, 0, 1); + const targetDir = endSeg.position + .clone() + .sub(startSeg.position) + .normalize(); + const targetQuat = new Quaternion().setFromUnitVectors(forward, targetDir); + object.quaternion.slerp(targetQuat, 0.1); + }); + + // useFrame((_, delta) => { + // if (!isPlaying || pathSegments.length < 2 || vehicleData.length === 0) + // return; + // const vehicle = vehicleData[activeVehicleIndex]; + // if (!vehicle) return; + + // const uuid = vehicle.vehicleId; + // const vehiclePosition = vehicle.vehiclePosition; + + // const object = scene.getObjectByProperty("uuid", uuid); + // if (!object) return; + + // const state = vehicleMovementState.current[uuid]; + // if (!state) return; + + // const startSeg = pathSegments[state.index]; + // const endSeg = pathSegments[state.index + 1]; + // if (!startSeg || !endSeg) return; + + // const segmentDistance = startSeg.position.distanceTo(endSeg.position); + // state.progress += (speed * delta) / segmentDistance; + + // while (state.progress >= 1) { + // state.progress -= 1; + // state.index++; + + // // If finished path + // if (state.index >= pathSegments.length - 1) { + // state.index = 0; + // state.progress = 0; + // object.position.copy(pathSegments[0].position); + // object.quaternion.identity(); + + // // Move to next vehicle + // setActiveVehicleIndex((prevIndex) => + // prevIndex + 1 >= vehicleUuids.length ? 0 : prevIndex + 1 + // ); + // return; // Stop updating this frame + // } + // } + + // const newPos = startSeg.position + // .clone() + // .lerp(endSeg.position, state.progress); + // object.position.copy(newPos); + + // const forward = new Vector3(0, 0, 1); + // const targetDir = endSeg.position + // .clone() + // .sub(startSeg.position) + // .normalize(); + // const targetQuat = new Quaternion().setFromUnitVectors(forward, targetDir); + + // object.quaternion.slerp(targetQuat, 0.1); + // }); + useEffect(() => {}, [multiPaths]); + const manager = usePathManager(managerData?.pathId, managerData?.vehicleId); + + useEffect(() => { + // if (managerData) { + // console.log("manager: ", manager); + // } + }, [managerData]); return ( <> + {shortestEdges.map((edge) => ( + p.position)} + color="yellow" + lineWidth={3} + /> + ))} ); } diff --git a/app/src/modules/simulation/vehicle/structuredPath/pointHandlers.tsx b/app/src/modules/simulation/vehicle/structuredPath/pointHandlers.tsx index 0ef25e3..5f666d4 100644 --- a/app/src/modules/simulation/vehicle/structuredPath/pointHandlers.tsx +++ b/app/src/modules/simulation/vehicle/structuredPath/pointHandlers.tsx @@ -446,7 +446,7 @@ type PointData = { interface PathDataInterface { pathId: string; - pathPoints: [PointData, PointData]; // always two points + pathPoints: [PointData, PointData]; } type PathData = PathDataInterface[]; @@ -602,7 +602,7 @@ export default function PointHandlers({ const handleARef = useRef(null); const handleBRef = useRef(null); const lineRef = useRef(null); - const { gl, controls, raycaster } = useThree(); + const { gl, controls, raycaster } = useThree(); const [dragging, setDragging] = useState< null | "main" | "handleA" | "handleB" @@ -616,11 +616,13 @@ export default function PointHandlers({ if (e.shiftKey) { setSelected((prev) => { + console.log("prev: ", prev); + console.log("pointIndex: ", pointIndex); if (prev.length === 0) return [pointIndex]; if (prev.length === 1) { // defer shortest path calculation setTimeout(() => { - console.log('points: ', points); + console.log("points: ", points); const p1 = points[prev[0]]; const p2 = points[pointIndex]; const result = aStarShortestPath( @@ -631,7 +633,7 @@ export default function PointHandlers({ ); if (result) { const edges = nodePathToEdges(result.pointIds, points, paths); - console.log('edges: ', edges); + console.log("edges: ", edges); setShortestEdges(edges); setShortestPath(edges); } else { @@ -767,6 +769,8 @@ export default function PointHandlers({ } }); + + return ( <> {/* Main point */} diff --git a/app/src/modules/simulation/vehicle/vehicles.tsx b/app/src/modules/simulation/vehicle/vehicles.tsx index 95bef00..3049822 100644 --- a/app/src/modules/simulation/vehicle/vehicles.tsx +++ b/app/src/modules/simulation/vehicle/vehicles.tsx @@ -33,7 +33,7 @@ function Vehicles() { {/* */} {/* */} - {/* */} + {isVehicleSelected && selectedEventSphere && !isPlaying && } ); diff --git a/app/src/store/builder/store.ts b/app/src/store/builder/store.ts index 6c3c12e..bcbe317 100644 --- a/app/src/store/builder/store.ts +++ b/app/src/store/builder/store.ts @@ -4,74 +4,74 @@ import { io } from "socket.io-client"; import * as CONSTANTS from "../../types/world/worldConstants"; export const useSocketStore = create((set: any, get: any) => ({ - socket: null, - initializeSocket: ( - email?: string, - organization?: string, - token?: string, - refreshToken?: string - ) => { - const existingSocket = get().socket; - if (existingSocket) { - return; - } + socket: null, + initializeSocket: ( + email?: string, + organization?: string, + token?: string, + refreshToken?: string + ) => { + const existingSocket = get().socket; + if (existingSocket) { + return; + } - const socket = io( - `http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Builder_v1`, - { - reconnection: true, - auth: { token, refreshToken }, - } - ); + const socket = io( + `http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Builder_v1`, + { + reconnection: true, + auth: { token, refreshToken }, + } + ); - const visualizationSocket = io( - `http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Visualization_v1`, - { - reconnection: true, - auth: { token, refreshToken }, - } - ); + const visualizationSocket = io( + `http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Visualization_v1`, + { + reconnection: true, + auth: { token, refreshToken }, + } + ); - const dashBoardSocket = io( - `http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/dashboard`, - { - reconnection: true, - auth: { token, refreshToken }, - } - ); - const projectSocket = io( - `http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/project`, - { - reconnection: true, - auth: { token, refreshToken }, - } - ); - const threadSocket = io( - `http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/thread`, - { - reconnection: true, - auth: { token, refreshToken }, - } - ); + const dashBoardSocket = io( + `http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/dashboard`, + { + reconnection: true, + auth: { token, refreshToken }, + } + ); + const projectSocket = io( + `http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/project`, + { + reconnection: true, + auth: { token, refreshToken }, + } + ); + const threadSocket = io( + `http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/thread`, + { + reconnection: true, + auth: { token, refreshToken }, + } + ); - set({ - socket, - visualizationSocket, - dashBoardSocket, - projectSocket, - threadSocket, - }); - }, - disconnectSocket: () => { - set((state: any) => { - state.socket?.disconnect(); - state.visualizationSocket?.disconnect(); - state.dashBoardSocket?.disconnect(); - state.projectSocket?.disconnect(); - state.threadSocket?.disconnect(); - return { socket: null }; - }); - }, + set({ + socket, + visualizationSocket, + dashBoardSocket, + projectSocket, + threadSocket, + }); + }, + disconnectSocket: () => { + set((state: any) => { + state.socket?.disconnect(); + state.visualizationSocket?.disconnect(); + state.dashBoardSocket?.disconnect(); + state.projectSocket?.disconnect(); + state.threadSocket?.disconnect(); + return { socket: null }; + }); + }, })); // export const useSocketStore = create((set: any, get: any) => ({ // socket: null, @@ -129,516 +129,543 @@ export const useSocketStore = create((set: any, get: any) => ({ // }, // })); export const useLoadingProgress = create<{ - loadingProgress: number; - setLoadingProgress: (x: number) => void; + loadingProgress: number; + setLoadingProgress: (x: number) => void; }>((set) => ({ - loadingProgress: 1, - setLoadingProgress: (x: number) => set({ loadingProgress: x }), + loadingProgress: 1, + setLoadingProgress: (x: number) => set({ loadingProgress: x }), })); export const useOrganization = create((set: any) => ({ - organization: "", - setOrganization: (x: any) => set(() => ({ organization: x })), + organization: "", + setOrganization: (x: any) => set(() => ({ organization: x })), })); export const useToggleView = create((set: any) => ({ - toggleView: false, - setToggleView: (x: any) => set(() => ({ toggleView: x })), + toggleView: false, + setToggleView: (x: any) => set(() => ({ toggleView: x })), })); export const useRoomsState = create((set: any) => ({ - roomsState: [], - setRoomsState: (x: any) => set(() => ({ roomsState: x })), + roomsState: [], + setRoomsState: (x: any) => set(() => ({ roomsState: x })), })); export const useSelectedItem = create((set: any) => ({ - selectedItem: { - name: "", - id: "", - type: undefined, - category: "", - subType: "", - }, - setSelectedItem: (x: any) => set(() => ({ selectedItem: x })), + selectedItem: { + name: "", + id: "", + type: undefined, + category: "", + subType: "", + }, + setSelectedItem: (x: any) => set(() => ({ selectedItem: x })), })); export const useNavMesh = create((set: any) => ({ - navMesh: null, - setNavMesh: (x: any) => set({ navMesh: x }), + navMesh: null, + setNavMesh: (x: any) => set({ navMesh: x }), })); type SelectedAssetsState = { - selectedAssets: Object3D[]; - setSelectedAssets: (assets: Object3D[]) => void; + selectedAssets: Object3D[]; + setSelectedAssets: (assets: Object3D[]) => void; }; export const useSelectedAssets = create((set) => ({ - selectedAssets: [], - setSelectedAssets: (assets) => set({ selectedAssets: assets }), + selectedAssets: [], + setSelectedAssets: (assets) => set({ selectedAssets: assets }), })); export const useLayers = create((set: any) => ({ - Layers: 1, - setLayers: (x: any) => set(() => ({ Layers: x })), + Layers: 1, + setLayers: (x: any) => set(() => ({ Layers: x })), })); export const useCamPosition = create((set: any) => ({ - camPosition: { x: undefined, y: undefined, z: undefined }, - setCamPosition: (newCamPosition: any) => set({ camPosition: newCamPosition }), + camPosition: { x: undefined, y: undefined, z: undefined }, + setCamPosition: (newCamPosition: any) => set({ camPosition: newCamPosition }), })); export const useMenuVisible = create((set: any) => ({ - menuVisible: false, - setMenuVisible: (x: any) => set(() => ({ menuVisible: x })), + menuVisible: false, + setMenuVisible: (x: any) => set(() => ({ menuVisible: x })), })); export const useToolMode = create((set: any) => ({ - toolMode: null, - setToolMode: (x: any) => set(() => ({ toolMode: x })), + toolMode: null, + setToolMode: (x: any) => set(() => ({ toolMode: x })), })); export const useSelectedWallItem = create((set: any) => ({ - selectedWallItem: null, - setSelectedWallItem: (x: any) => set(() => ({ selectedWallItem: x })), + selectedWallItem: null, + setSelectedWallItem: (x: any) => set(() => ({ selectedWallItem: x })), })); export const useSelectedFloorItem = create((set: any) => ({ - selectedFloorItem: null, - setSelectedFloorItem: (x: any) => set(() => ({ selectedFloorItem: x })), + selectedFloorItem: null, + setSelectedFloorItem: (x: any) => set(() => ({ selectedFloorItem: x })), })); export const useDeletableFloorItem = create((set: any) => ({ - deletableFloorItem: null, - setDeletableFloorItem: (x: any) => set(() => ({ deletableFloorItem: x })), + deletableFloorItem: null, + setDeletableFloorItem: (x: any) => set(() => ({ deletableFloorItem: x })), })); export const useSetScale = create((set: any) => ({ - scale: null, - setScale: (x: any) => set(() => ({ scale: x })), + scale: null, + setScale: (x: any) => set(() => ({ scale: x })), })); export const useRoofVisibility = create((set: any) => ({ - roofVisibility: false, - setRoofVisibility: (x: any) => set(() => ({ roofVisibility: x })), + roofVisibility: false, + setRoofVisibility: (x: any) => set(() => ({ roofVisibility: x })), })); export const useWallVisibility = create((set: any) => ({ - wallVisibility: false, - setWallVisibility: (x: any) => set(() => ({ wallVisibility: x })), + wallVisibility: false, + setWallVisibility: (x: any) => set(() => ({ wallVisibility: x })), })); export const useShadows = create((set: any) => ({ - shadows: false, - setShadows: (x: any) => set(() => ({ shadows: x })), + shadows: false, + setShadows: (x: any) => set(() => ({ shadows: x })), })); export const useSunPosition = create((set: any) => ({ - sunPosition: { x: undefined, y: undefined, z: undefined }, - setSunPosition: (newSuntPosition: any) => - set({ sunPosition: newSuntPosition }), + sunPosition: { x: undefined, y: undefined, z: undefined }, + setSunPosition: (newSuntPosition: any) => + set({ sunPosition: newSuntPosition }), })); export const useRemoveLayer = create((set: any) => ({ - removeLayer: false, - setRemoveLayer: (x: any) => set(() => ({ removeLayer: x })), + removeLayer: false, + setRemoveLayer: (x: any) => set(() => ({ removeLayer: x })), })); export const useRemovedLayer = create((set: any) => ({ - removedLayer: null, - setRemovedLayer: (x: any) => set(() => ({ removedLayer: x })), + removedLayer: null, + setRemovedLayer: (x: any) => set(() => ({ removedLayer: x })), })); export const useProjectName = create((set: any) => ({ - projectName: "Creating Your Project", - setProjectName: (x: any) => set({ projectName: x }), + projectName: "Creating Your Project", + setProjectName: (x: any) => set({ projectName: x }), })); export const useActiveLayer = create((set: any) => ({ - activeLayer: 1, - setActiveLayer: (x: any) => set({ activeLayer: x }), + activeLayer: 1, + setActiveLayer: (x: any) => set({ activeLayer: x }), })); export const useResetCamera = create((set: any) => ({ - resetCamera: false, - setResetCamera: (x: any) => set({ resetCamera: x }), + resetCamera: false, + setResetCamera: (x: any) => set({ resetCamera: x }), })); export const useAddAction = create((set: any) => ({ - addAction: null, - setAddAction: (x: any) => set({ addAction: x }), + addAction: null, + setAddAction: (x: any) => set({ addAction: x }), })); export const useActiveTool = create((set: any) => ({ - activeTool: "cursor", - setActiveTool: (x: any) => set({ activeTool: x }), + activeTool: "cursor", + setActiveTool: (x: any) => set({ activeTool: x }), })); export const useActiveSubTool = create((set: any) => ({ - activeSubTool: "cursor", - setActiveSubTool: (x: any) => set({ activeSubTool: x }), + activeSubTool: "cursor", + setActiveSubTool: (x: any) => set({ activeSubTool: x }), })); export const useElevation = create((set: any) => ({ - elevation: 45, - setElevation: (x: any) => set({ elevation: x }), + elevation: 45, + setElevation: (x: any) => set({ elevation: x }), })); export const useAzimuth = create((set: any) => ({ - azimuth: -160, - setAzimuth: (x: any) => set({ azimuth: x }), + azimuth: -160, + setAzimuth: (x: any) => set({ azimuth: x }), })); export const useRenderDistance = create((set: any) => ({ - renderDistance: 40, - setRenderDistance: (x: any) => set({ renderDistance: x }), + renderDistance: 40, + setRenderDistance: (x: any) => set({ renderDistance: x }), })); export const useCamMode = create((set: any) => ({ - camMode: "ThirdPerson", - setCamMode: (x: any) => set({ camMode: x }), + camMode: "ThirdPerson", + setCamMode: (x: any) => set({ camMode: x }), })); export const useUserName = create((set: any) => ({ - userName: "", - setUserName: (x: any) => set({ userName: x }), + userName: "", + setUserName: (x: any) => set({ userName: x }), })); export const useRenameModeStore = create((set: any) => ({ - isRenameMode: false, - setIsRenameMode: (state: boolean) => set({ isRenameMode: state }), + isRenameMode: false, + setIsRenameMode: (state: boolean) => set({ isRenameMode: state }), })); export const useObjectPosition = create((set: any) => ({ - objectPosition: { x: undefined, y: undefined, z: undefined }, - setObjectPosition: (newObjectPosition: any) => - set({ objectPosition: newObjectPosition }), + objectPosition: { x: undefined, y: undefined, z: undefined }, + setObjectPosition: (newObjectPosition: any) => + set({ objectPosition: newObjectPosition }), })); export const useObjectRotation = create((set: any) => ({ - objectRotation: { x: undefined, y: undefined, z: undefined }, - setObjectRotation: (newObjectRotation: any) => - set({ objectRotation: newObjectRotation }), + objectRotation: { x: undefined, y: undefined, z: undefined }, + setObjectRotation: (newObjectRotation: any) => + set({ objectRotation: newObjectRotation }), })); export const useDrieTemp = create((set: any) => ({ - drieTemp: undefined, - setDrieTemp: (x: any) => set({ drieTemp: x }), + drieTemp: undefined, + setDrieTemp: (x: any) => set({ drieTemp: x }), })); export const useActiveUsers = create((set: any) => ({ - activeUsers: [], - setActiveUsers: (callback: (prev: any[]) => any[] | any[]) => - set((state: { activeUsers: any[] }) => ({ - activeUsers: - typeof callback === "function" ? callback(state.activeUsers) : callback, - })), + activeUsers: [], + setActiveUsers: (callback: (prev: any[]) => any[] | any[]) => + set((state: { activeUsers: any[] }) => ({ + activeUsers: + typeof callback === "function" ? callback(state.activeUsers) : callback, + })), })); export const useDrieUIValue = create((set: any) => ({ - drieUIValue: { touch: null, temperature: null, humidity: null }, + drieUIValue: { touch: null, temperature: null, humidity: null }, - setDrieUIValue: (x: any) => - set((state: any) => ({ drieUIValue: { ...state.drieUIValue, ...x } })), + setDrieUIValue: (x: any) => + set((state: any) => ({ drieUIValue: { ...state.drieUIValue, ...x } })), - setTouch: (value: any) => - set((state: any) => ({ - drieUIValue: { ...state.drieUIValue, touch: value }, - })), - setTemperature: (value: any) => - set((state: any) => ({ - drieUIValue: { ...state.drieUIValue, temperature: value }, - })), - setHumidity: (value: any) => - set((state: any) => ({ - drieUIValue: { ...state.drieUIValue, humidity: value }, - })), + setTouch: (value: any) => + set((state: any) => ({ + drieUIValue: { ...state.drieUIValue, touch: value }, + })), + setTemperature: (value: any) => + set((state: any) => ({ + drieUIValue: { ...state.drieUIValue, temperature: value }, + })), + setHumidity: (value: any) => + set((state: any) => ({ + drieUIValue: { ...state.drieUIValue, humidity: value }, + })), })); export const usezoneTarget = create((set: any) => ({ - zoneTarget: [], - setZoneTarget: (x: any) => set({ zoneTarget: x }), + zoneTarget: [], + setZoneTarget: (x: any) => set({ zoneTarget: x }), })); export const usezonePosition = create((set: any) => ({ - zonePosition: [], - setZonePosition: (x: any) => set({ zonePosition: x }), + zonePosition: [], + setZonePosition: (x: any) => set({ zonePosition: x }), })); interface EditPositionState { - Edit: boolean; - setEdit: (value: boolean) => void; + Edit: boolean; + setEdit: (value: boolean) => void; } export const useEditPosition = create((set) => ({ - Edit: false, - setEdit: (value) => set({ Edit: value }), + Edit: false, + setEdit: (value) => set({ Edit: value }), })); export const useAsset3dWidget = create((set: any) => ({ - widgetSelect: "", - setWidgetSelect: (x: any) => set({ widgetSelect: x }), + widgetSelect: "", + setWidgetSelect: (x: any) => set({ widgetSelect: x }), })); export const useWidgetSubOption = create((set: any) => ({ - widgetSubOption: "2D", - setWidgetSubOption: (x: any) => set({ widgetSubOption: x }), + widgetSubOption: "2D", + setWidgetSubOption: (x: any) => set({ widgetSubOption: x }), })); export const useLimitDistance = create((set: any) => ({ - limitDistance: true, - setLimitDistance: (x: any) => set({ limitDistance: x }), + limitDistance: true, + setLimitDistance: (x: any) => set({ limitDistance: x }), })); export const useTileDistance = create((set: any) => ({ - gridValue: { - size: CONSTANTS.gridConfig.size, - divisions: CONSTANTS.gridConfig.divisions, - }, - planeValue: { - height: CONSTANTS.planeConfig.height, - width: CONSTANTS.planeConfig.width, - }, + gridValue: { + size: CONSTANTS.gridConfig.size, + divisions: CONSTANTS.gridConfig.divisions, + }, + planeValue: { + height: CONSTANTS.planeConfig.height, + width: CONSTANTS.planeConfig.width, + }, - setGridValue: (value: any) => - set((state: any) => ({ - gridValue: { ...state.gridValue, ...value }, - })), + setGridValue: (value: any) => + set((state: any) => ({ + gridValue: { ...state.gridValue, ...value }, + })), - setPlaneValue: (value: any) => - set((state: any) => ({ - planeValue: { ...state.planeValue, ...value }, - })), + setPlaneValue: (value: any) => + set((state: any) => ({ + planeValue: { ...state.planeValue, ...value }, + })), })); export const usePlayAgv = create((set, get) => ({ - PlayAgv: [], - setPlayAgv: (updateFn: (prev: any[]) => any[]) => - set({ PlayAgv: updateFn(get().PlayAgv) }), + PlayAgv: [], + setPlayAgv: (updateFn: (prev: any[]) => any[]) => + set({ PlayAgv: updateFn(get().PlayAgv) }), })); // Define the Asset type type Asset = { - id: string; - name: string; - position?: [number, number, number]; // Optional: 3D position - rotation?: { x: number; y: number; z: number }; // Optional: Euler rotation + id: string; + name: string; + position?: [number, number, number]; // Optional: 3D position + rotation?: { x: number; y: number; z: number }; // Optional: Euler rotation }; // Zustand store type type ZoneAssetState = { - zoneAssetId: Asset | null; - setZoneAssetId: (asset: Asset | null) => void; + zoneAssetId: Asset | null; + setZoneAssetId: (asset: Asset | null) => void; }; // Zustand store export const useZoneAssetId = create((set) => ({ - zoneAssetId: null, - setZoneAssetId: (asset) => set({ zoneAssetId: asset }), + zoneAssetId: null, + setZoneAssetId: (asset) => set({ zoneAssetId: asset }), })); // version visible hidden interface VersionHistoryState { - viewVersionHistory: boolean; - setVersionHistoryVisible: (value: boolean) => void; + viewVersionHistory: boolean; + setVersionHistoryVisible: (value: boolean) => void; } const useVersionHistoryVisibleStore = create((set) => ({ - viewVersionHistory: false, - setVersionHistoryVisible: (value) => set({ viewVersionHistory: value }), + viewVersionHistory: false, + setVersionHistoryVisible: (value) => set({ viewVersionHistory: value }), })); export default useVersionHistoryVisibleStore; interface ShortcutStore { - showShortcuts: boolean; - setShowShortcuts: (value: boolean) => void; - toggleShortcuts: () => void; + showShortcuts: boolean; + setShowShortcuts: (value: boolean) => void; + toggleShortcuts: () => void; } export const useShortcutStore = create((set) => ({ - showShortcuts: false, - setShowShortcuts: (value) => set({ showShortcuts: value }), - toggleShortcuts: () => - set((state) => ({ showShortcuts: !state.showShortcuts })), + showShortcuts: false, + setShowShortcuts: (value) => set({ showShortcuts: value }), + toggleShortcuts: () => + set((state) => ({ showShortcuts: !state.showShortcuts })), })); export const useMachineCount = create((set: any) => ({ - machineCount: 0, - setMachineCount: (x: any) => set({ machineCount: x }), + machineCount: 0, + setMachineCount: (x: any) => set({ machineCount: x }), })); export const useMachineUptime = create((set: any) => ({ - machineActiveTime: 0, - setMachineActiveTime: (x: any) => set({ machineActiveTime: x }), + machineActiveTime: 0, + setMachineActiveTime: (x: any) => set({ machineActiveTime: x }), })); export const useMachineDowntime = create((set: any) => ({ - machineIdleTime: 0, - setMachineIdleTime: (x: any) => set({ machineIdleTime: x }), + machineIdleTime: 0, + setMachineIdleTime: (x: any) => set({ machineIdleTime: x }), })); export const useMaterialCycle = create((set: any) => ({ - materialCycleTime: 0, - setMaterialCycleTime: (x: any) => set({ materialCycleTime: x }), + materialCycleTime: 0, + setMaterialCycleTime: (x: any) => set({ materialCycleTime: x }), })); export const useThroughPutData = create((set: any) => ({ - throughputData: 0, - setThroughputData: (x: any) => set({ throughputData: x }), + throughputData: 0, + setThroughputData: (x: any) => set({ throughputData: x }), })); export const useProductionCapacityData = create((set: any) => ({ - productionCapacityData: 0, - setProductionCapacityData: (x: any) => set({ productionCapacityData: x }), + productionCapacityData: 0, + setProductionCapacityData: (x: any) => set({ productionCapacityData: x }), })); export const useProcessBar = create((set: any) => ({ - processBar: [], - setProcessBar: (x: any) => set({ processBar: x }), + processBar: [], + setProcessBar: (x: any) => set({ processBar: x }), })); export const useDfxUpload = create((set: any) => ({ - dfxuploaded: [], - dfxWallGenerate: [], - objValue: { x: 0, y: 0, z: 0 }, - setDfxUploaded: (x: any) => set({ dfxuploaded: x }), - setDxfWallGenerate: (x: any) => set({ dfxWallGenerate: x }), - setObjValue: (x: any) => set({ objValue: x }), + dfxuploaded: [], + dfxWallGenerate: [], + objValue: { x: 0, y: 0, z: 0 }, + setDfxUploaded: (x: any) => set({ dfxuploaded: x }), + setDxfWallGenerate: (x: any) => set({ dfxWallGenerate: x }), + setObjValue: (x: any) => set({ objValue: x }), })); type InputValuesStore = { - inputValues: Record; - setInputValues: (values: Record) => void; - updateInputValue: (label: string, value: string) => void; // <- New + inputValues: Record; + setInputValues: (values: Record) => void; + updateInputValue: (label: string, value: string) => void; // <- New }; export const useInputValues = create((set) => ({ - inputValues: {}, - setInputValues: (values) => set({ inputValues: values }), - updateInputValue: (label, value) => - set((state) => ({ - inputValues: { - ...state.inputValues, - [label]: value, - }, - })), + inputValues: {}, + setInputValues: (values) => set({ inputValues: values }), + updateInputValue: (label, value) => + set((state) => ({ + inputValues: { + ...state.inputValues, + [label]: value, + }, + })), })); export interface ROISummaryData { - productName: string; - roiPercentage: number; - paybackPeriod: number; - totalCost: number; - revenueGenerated: number; - netProfit: number; - netLoss: number; + productName: string; + roiPercentage: number; + paybackPeriod: number; + totalCost: number; + revenueGenerated: number; + netProfit: number; + netLoss: number; } interface ROISummaryStore { - roiSummary: ROISummaryData; - setRoiSummaryData: (values: ROISummaryData) => void; + roiSummary: ROISummaryData; + setRoiSummaryData: (values: ROISummaryData) => void; } export const useROISummaryData = create((set) => ({ - roiSummary: { - productName: "", - roiPercentage: 0, - paybackPeriod: 0, - totalCost: 0, - revenueGenerated: 0, - netProfit: 0, - netLoss: 0, - }, - setRoiSummaryData: (values) => set({ roiSummary: values }), + roiSummary: { + productName: "", + roiPercentage: 0, + paybackPeriod: 0, + totalCost: 0, + revenueGenerated: 0, + netProfit: 0, + netLoss: 0, + }, + setRoiSummaryData: (values) => set({ roiSummary: values }), })); interface CompareStore { - comparePopUp: boolean; - setComparePopUp: (value: boolean) => void; - toggleComparePopUp: () => void; + comparePopUp: boolean; + setComparePopUp: (value: boolean) => void; + toggleComparePopUp: () => void; } export const useCompareStore = create((set) => ({ - comparePopUp: false, - setComparePopUp: (value) => set({ comparePopUp: value }), - toggleComparePopUp: () => - set((state) => ({ comparePopUp: !state.comparePopUp })), + comparePopUp: false, + setComparePopUp: (value) => set({ comparePopUp: value }), + toggleComparePopUp: () => + set((state) => ({ comparePopUp: !state.comparePopUp })), })); // Save state store interface SaveVersionStore { - isVersionSaved: boolean; - setIsVersionSaved: (value: boolean) => void; + isVersionSaved: boolean; + setIsVersionSaved: (value: boolean) => void; } export const useSaveVersion = create((set) => ({ - isVersionSaved: false, - setIsVersionSaved: (value: boolean) => set({ isVersionSaved: value }), + isVersionSaved: false, + setIsVersionSaved: (value: boolean) => set({ isVersionSaved: value }), })); interface ViewSceneState { - viewSceneLabels: boolean; - setViewSceneLabels: (value: boolean | ((prev: boolean) => boolean)) => void; + viewSceneLabels: boolean; + setViewSceneLabels: (value: boolean | ((prev: boolean) => boolean)) => void; } export const useViewSceneStore = create((set) => ({ - viewSceneLabels: getInitialViewSceneLabels(), - setViewSceneLabels: (value) => { - set((state) => { - const newValue = - typeof value === "function" ? value(state.viewSceneLabels) : value; + viewSceneLabels: getInitialViewSceneLabels(), + setViewSceneLabels: (value) => { + set((state) => { + const newValue = + typeof value === "function" ? value(state.viewSceneLabels) : value; - // Store in localStorage manually - localStorage.setItem("viewSceneLabels", JSON.stringify(newValue)); + // Store in localStorage manually + localStorage.setItem("viewSceneLabels", JSON.stringify(newValue)); - return { viewSceneLabels: newValue }; - }); - }, + return { viewSceneLabels: newValue }; + }); + }, })); function getInitialViewSceneLabels(): boolean { - if (typeof window === "undefined") return false; // SSR safety - const saved = localStorage.getItem("viewSceneLabels"); - return saved ? JSON.parse(saved) : false; + if (typeof window === "undefined") return false; // SSR safety + const saved = localStorage.getItem("viewSceneLabels"); + return saved ? JSON.parse(saved) : false; } export interface CompareProduct { - productUuid: string; - productName: string; - simulationData: { - // costPerUnit: number; - // workingDaysPerYear: number; - // shiftLength: number; - // shiftsPerDay: number; - roiPercentage: number; - // paybackPeriod: number; - // totalCost: number; - // revenueGenerated: number; - netProfit: number; - productionCapacity: number; - paybackPeriod: number; - // netLoss: number; - machineIdleTime: number; - machineActiveTime: number; - throughputData: number; - }; + productUuid: string; + productName: string; + simulationData: { + // costPerUnit: number; + // workingDaysPerYear: number; + // shiftLength: number; + // shiftsPerDay: number; + roiPercentage: number; + // paybackPeriod: number; + // totalCost: number; + // revenueGenerated: number; + netProfit: number; + productionCapacity: number; + paybackPeriod: number; + // netLoss: number; + machineIdleTime: number; + machineActiveTime: number; + throughputData: number; + }; } export const useCompareProductDataStore = create<{ - compareProductsData: CompareProduct[]; - setCompareProductsData: (x: CompareProduct[]) => void; + compareProductsData: CompareProduct[]; + setCompareProductsData: (x: CompareProduct[]) => void; }>((set) => ({ - compareProductsData: [], - setCompareProductsData: (x) => set({ compareProductsData: x }), + compareProductsData: [], + setCompareProductsData: (x) => set({ compareProductsData: x }), })); export const useSelectedComment = create((set: any) => ({ - selectedComment: null, - setSelectedComment: (x: any) => set({ selectedComment: x }), - position2Dstate: {}, - setPosition2Dstate: (x: any) => set({ position2Dstate: x }), - commentPositionState: null, - setCommentPositionState: (x: any) => set({ commentPositionState: x }), + selectedComment: null, + setSelectedComment: (x: any) => set({ selectedComment: x }), + position2Dstate: {}, + setPosition2Dstate: (x: any) => set({ position2Dstate: x }), + commentPositionState: null, + setCommentPositionState: (x: any) => set({ commentPositionState: x }), })); export const useSelectedPath = create((set: any) => ({ - selectedPath: "auto", - setSelectedPath: (x: any) => set({ selectedPath: x }), + selectedPath: "auto", + setSelectedPath: (x: any) => set({ selectedPath: x }), })); export const useContextActionStore = create((set: any) => ({ - contextAction: null, - setContextAction: (x: any) => set({ contextAction: x }), + contextAction: null, + setContextAction: (x: any) => set({ contextAction: x }), +})); +type PointData = { + pointId: string; + position: [number, number, number]; + isCurved?: boolean; + handleA?: [number, number, number] | null; + handleB?: [number, number, number] | null; +}; + +interface PathDataInterface { + pathId: string; + isActive?: boolean; + isCurved?: boolean; + pathPoints: [PointData, PointData]; +} +interface allPaths { + paths: string; + isAvailable: boolean; + vehicleId: string; +} + +type PathData = PathDataInterface[]; +export const useCreatedPaths = create((set: any) => ({ + paths: [], + setPaths: (x: PathData) => set({ paths: x }), + allPaths: [], + setAllPaths: (x: allPaths) => set({ allPaths: x }), }));