added available paths

This commit is contained in:
2025-08-28 09:43:42 +05:30
parent 5117e48527
commit a0e5115c6c
9 changed files with 931 additions and 470 deletions

View File

@@ -172,6 +172,7 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai
}
}
});
const updatePoint = (index: number, pos: THREE.Vector3) => {

View File

@@ -29,19 +29,20 @@ export const getPathsByPointId = (pointId: any, paths: PathData) => {
export const setPathPosition = (
pointUuid: string,
position: [number, number, number],
setPaths: React.Dispatch<React.SetStateAction<PathData>>
setPaths: React.Dispatch<React.SetStateAction<PathData>>,
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);
};

View File

@@ -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]);
};

View File

@@ -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<PathData>([]);
// const [paths, setPaths] = useState<PathData>([]);
// const [paths, setPaths] = useState<PathData>(() => {
// const stored = localStorage.getItem("paths");
// return stored ? JSON.parse(stored) : [];
// });
const { paths, setPaths } = useCreatedPaths();
const { activeTool } = useActiveTool();
const { toolMode } = useToolMode();
const [draftPoints, setDraftPoints] = useState<PointData[]>([]);
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<PointData | null>(null);
const { activeSubTool } = useActiveSubTool();
const { activeTool } = useActiveTool();
const [pathPointsList, setPathPointsList] = useState<PointData[]>([]);
const [selectedPointIndices, setSelectedPointIndices] = useState<number[]>(
[]
);
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<string>();
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) => (
<PathHandler
key={path.pathId}
selectedPath={path}

View File

@@ -55,14 +55,17 @@ export default function PathHandler({
const [start, end] = points.map((p) => 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 (wont 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 (
<>
<DragControls

View File

@@ -1,11 +1,27 @@
import { DragControls } from "@react-three/drei";
import React, { useCallback, useEffect, useMemo, useState } from "react";
import { useActiveTool, useToolMode } from "../../../../store/builder/store";
import { Plane, Vector3 } from "three";
import { useThree } from "@react-three/fiber";
import { DragControls, Line } from "@react-three/drei";
import React, {
useCallback,
useEffect,
useMemo,
useRef,
useState,
} from "react";
import {
useActiveTool,
useCreatedPaths,
useToolMode,
} from "../../../../store/builder/store";
import { CubicBezierCurve3, Plane, Quaternion, Vector3 } from "three";
import { useFrame, useThree } from "@react-three/fiber";
import { handleCanvasCursors } from "../../../../utils/mouseUtils/handleCanvasCursors";
import { getPathsByPointId, setPathPosition } from "./function/getPaths";
import { aStar } from "../structuredPath/functions/aStar";
import {
useAnimationPlaySpeed,
usePlayButtonStore,
} from "../../../../store/usePlayButtonStore";
import { useSceneContext } from "../../../scene/sceneContext";
import { usePathManager } from "./function/usePathManager";
type PointData = {
pointId: string;
position: [number, number, number];
@@ -31,6 +47,8 @@ type PointHandlerProps = {
hoveredLine: PathDataInterface | null;
pointIndex: any;
points: PointData[];
selected: number[];
setSelected: React.Dispatch<React.SetStateAction<number[]>>;
};
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<PointData[]>([]);
const [shortestEdges, setShortestEdges] = useState<PathData>([]);
const [shortestPaths, setShortestPaths] = useState<PathData>([]);
const POINT_SNAP_THRESHOLD = 0.5; // Distance threshold for snapping in meters
const [selectedPointIndices, setSelectedPointIndices] = useState<number[]>(
[]
);
const [vehicleUuids, setVehicleUuids] = useState<any>();
const CAN_POINT_SNAP = true;
const CAN_ANGLE_SNAP = true;
const ANGLE_SNAP_DISTANCE_THRESHOLD = 0.5;
const [selectedPointIndices, setSelectedPointIndices] = useState<number[]>(
[]
);
const [shortestEdges, setShortestEdges] = useState<PathData>([]);
const { speed } = useAnimationPlaySpeed();
const { assetStore } = useSceneContext();
const { assets } = assetStore();
const vehicleMovementState = useRef<any>({});
const [activeVehicleIndex, setActiveVehicleIndex] = useState(0);
const [vehicleData, setVehicleData] = useState<VehicleDetails[]>([]);
const { paths, setPaths } = useCreatedPaths();
const [managerData, setManagerData] = useState<Manager>();
// 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 (
<>
<DragControls
@@ -496,6 +838,14 @@ export default function PointHandler({
<meshBasicMaterial color="pink" />
</mesh>
</DragControls>
{shortestEdges.map((edge) => (
<Line
key={`sp-${edge.pathId}`}
points={edge.pathPoints.map((p) => p.position)}
color="yellow"
lineWidth={3}
/>
))}
</>
);
}

View File

@@ -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<THREE.Mesh>(null);
const handleBRef = useRef<THREE.Mesh>(null);
const lineRef = useRef<any>(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 */}

View File

@@ -33,7 +33,7 @@ function Vehicles() {
<PathCreator />
{/* <StructuredPath /> */}
{/* <PreDefinedPath /> */}
{/* <VehicleInstances /> */}
<VehicleInstances />
{isVehicleSelected && selectedEventSphere && !isPlaying && <VehicleUI />}
</>
);

View File

@@ -4,74 +4,74 @@ import { io } from "socket.io-client";
import * as CONSTANTS from "../../types/world/worldConstants";
export const useSocketStore = create<any>((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<any>((set: any, get: any) => ({
// socket: null,
@@ -129,516 +129,543 @@ export const useSocketStore = create<any>((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<any>((set: any) => ({
organization: "",
setOrganization: (x: any) => set(() => ({ organization: x })),
organization: "",
setOrganization: (x: any) => set(() => ({ organization: x })),
}));
export const useToggleView = create<any>((set: any) => ({
toggleView: false,
setToggleView: (x: any) => set(() => ({ toggleView: x })),
toggleView: false,
setToggleView: (x: any) => set(() => ({ toggleView: x })),
}));
export const useRoomsState = create<any>((set: any) => ({
roomsState: [],
setRoomsState: (x: any) => set(() => ({ roomsState: x })),
roomsState: [],
setRoomsState: (x: any) => set(() => ({ roomsState: x })),
}));
export const useSelectedItem = create<any>((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<any>((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<SelectedAssetsState>((set) => ({
selectedAssets: [],
setSelectedAssets: (assets) => set({ selectedAssets: assets }),
selectedAssets: [],
setSelectedAssets: (assets) => set({ selectedAssets: assets }),
}));
export const useLayers = create<any>((set: any) => ({
Layers: 1,
setLayers: (x: any) => set(() => ({ Layers: x })),
Layers: 1,
setLayers: (x: any) => set(() => ({ Layers: x })),
}));
export const useCamPosition = create<any>((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<any>((set: any) => ({
menuVisible: false,
setMenuVisible: (x: any) => set(() => ({ menuVisible: x })),
menuVisible: false,
setMenuVisible: (x: any) => set(() => ({ menuVisible: x })),
}));
export const useToolMode = create<any>((set: any) => ({
toolMode: null,
setToolMode: (x: any) => set(() => ({ toolMode: x })),
toolMode: null,
setToolMode: (x: any) => set(() => ({ toolMode: x })),
}));
export const useSelectedWallItem = create<any>((set: any) => ({
selectedWallItem: null,
setSelectedWallItem: (x: any) => set(() => ({ selectedWallItem: x })),
selectedWallItem: null,
setSelectedWallItem: (x: any) => set(() => ({ selectedWallItem: x })),
}));
export const useSelectedFloorItem = create<any>((set: any) => ({
selectedFloorItem: null,
setSelectedFloorItem: (x: any) => set(() => ({ selectedFloorItem: x })),
selectedFloorItem: null,
setSelectedFloorItem: (x: any) => set(() => ({ selectedFloorItem: x })),
}));
export const useDeletableFloorItem = create<any>((set: any) => ({
deletableFloorItem: null,
setDeletableFloorItem: (x: any) => set(() => ({ deletableFloorItem: x })),
deletableFloorItem: null,
setDeletableFloorItem: (x: any) => set(() => ({ deletableFloorItem: x })),
}));
export const useSetScale = create<any>((set: any) => ({
scale: null,
setScale: (x: any) => set(() => ({ scale: x })),
scale: null,
setScale: (x: any) => set(() => ({ scale: x })),
}));
export const useRoofVisibility = create<any>((set: any) => ({
roofVisibility: false,
setRoofVisibility: (x: any) => set(() => ({ roofVisibility: x })),
roofVisibility: false,
setRoofVisibility: (x: any) => set(() => ({ roofVisibility: x })),
}));
export const useWallVisibility = create<any>((set: any) => ({
wallVisibility: false,
setWallVisibility: (x: any) => set(() => ({ wallVisibility: x })),
wallVisibility: false,
setWallVisibility: (x: any) => set(() => ({ wallVisibility: x })),
}));
export const useShadows = create<any>((set: any) => ({
shadows: false,
setShadows: (x: any) => set(() => ({ shadows: x })),
shadows: false,
setShadows: (x: any) => set(() => ({ shadows: x })),
}));
export const useSunPosition = create<any>((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<any>((set: any) => ({
removeLayer: false,
setRemoveLayer: (x: any) => set(() => ({ removeLayer: x })),
removeLayer: false,
setRemoveLayer: (x: any) => set(() => ({ removeLayer: x })),
}));
export const useRemovedLayer = create<any>((set: any) => ({
removedLayer: null,
setRemovedLayer: (x: any) => set(() => ({ removedLayer: x })),
removedLayer: null,
setRemovedLayer: (x: any) => set(() => ({ removedLayer: x })),
}));
export const useProjectName = create<any>((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<any>((set: any) => ({
activeLayer: 1,
setActiveLayer: (x: any) => set({ activeLayer: x }),
activeLayer: 1,
setActiveLayer: (x: any) => set({ activeLayer: x }),
}));
export const useResetCamera = create<any>((set: any) => ({
resetCamera: false,
setResetCamera: (x: any) => set({ resetCamera: x }),
resetCamera: false,
setResetCamera: (x: any) => set({ resetCamera: x }),
}));
export const useAddAction = create<any>((set: any) => ({
addAction: null,
setAddAction: (x: any) => set({ addAction: x }),
addAction: null,
setAddAction: (x: any) => set({ addAction: x }),
}));
export const useActiveTool = create<any>((set: any) => ({
activeTool: "cursor",
setActiveTool: (x: any) => set({ activeTool: x }),
activeTool: "cursor",
setActiveTool: (x: any) => set({ activeTool: x }),
}));
export const useActiveSubTool = create<any>((set: any) => ({
activeSubTool: "cursor",
setActiveSubTool: (x: any) => set({ activeSubTool: x }),
activeSubTool: "cursor",
setActiveSubTool: (x: any) => set({ activeSubTool: x }),
}));
export const useElevation = create<any>((set: any) => ({
elevation: 45,
setElevation: (x: any) => set({ elevation: x }),
elevation: 45,
setElevation: (x: any) => set({ elevation: x }),
}));
export const useAzimuth = create<any>((set: any) => ({
azimuth: -160,
setAzimuth: (x: any) => set({ azimuth: x }),
azimuth: -160,
setAzimuth: (x: any) => set({ azimuth: x }),
}));
export const useRenderDistance = create<any>((set: any) => ({
renderDistance: 40,
setRenderDistance: (x: any) => set({ renderDistance: x }),
renderDistance: 40,
setRenderDistance: (x: any) => set({ renderDistance: x }),
}));
export const useCamMode = create<any>((set: any) => ({
camMode: "ThirdPerson",
setCamMode: (x: any) => set({ camMode: x }),
camMode: "ThirdPerson",
setCamMode: (x: any) => set({ camMode: x }),
}));
export const useUserName = create<any>((set: any) => ({
userName: "",
setUserName: (x: any) => set({ userName: x }),
userName: "",
setUserName: (x: any) => set({ userName: x }),
}));
export const useRenameModeStore = create<any>((set: any) => ({
isRenameMode: false,
setIsRenameMode: (state: boolean) => set({ isRenameMode: state }),
isRenameMode: false,
setIsRenameMode: (state: boolean) => set({ isRenameMode: state }),
}));
export const useObjectPosition = create<any>((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<any>((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<any>((set: any) => ({
drieTemp: undefined,
setDrieTemp: (x: any) => set({ drieTemp: x }),
drieTemp: undefined,
setDrieTemp: (x: any) => set({ drieTemp: x }),
}));
export const useActiveUsers = create<any>((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<any>((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<any>((set: any) => ({
zoneTarget: [],
setZoneTarget: (x: any) => set({ zoneTarget: x }),
zoneTarget: [],
setZoneTarget: (x: any) => set({ zoneTarget: x }),
}));
export const usezonePosition = create<any>((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<EditPositionState>((set) => ({
Edit: false,
setEdit: (value) => set({ Edit: value }),
Edit: false,
setEdit: (value) => set({ Edit: value }),
}));
export const useAsset3dWidget = create<any>((set: any) => ({
widgetSelect: "",
setWidgetSelect: (x: any) => set({ widgetSelect: x }),
widgetSelect: "",
setWidgetSelect: (x: any) => set({ widgetSelect: x }),
}));
export const useWidgetSubOption = create<any>((set: any) => ({
widgetSubOption: "2D",
setWidgetSubOption: (x: any) => set({ widgetSubOption: x }),
widgetSubOption: "2D",
setWidgetSubOption: (x: any) => set({ widgetSubOption: x }),
}));
export const useLimitDistance = create<any>((set: any) => ({
limitDistance: true,
setLimitDistance: (x: any) => set({ limitDistance: x }),
limitDistance: true,
setLimitDistance: (x: any) => set({ limitDistance: x }),
}));
export const useTileDistance = create<any>((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<any>((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<ZoneAssetState>((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<VersionHistoryState>((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<ShortcutStore>((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<any>((set: any) => ({
machineCount: 0,
setMachineCount: (x: any) => set({ machineCount: x }),
machineCount: 0,
setMachineCount: (x: any) => set({ machineCount: x }),
}));
export const useMachineUptime = create<any>((set: any) => ({
machineActiveTime: 0,
setMachineActiveTime: (x: any) => set({ machineActiveTime: x }),
machineActiveTime: 0,
setMachineActiveTime: (x: any) => set({ machineActiveTime: x }),
}));
export const useMachineDowntime = create<any>((set: any) => ({
machineIdleTime: 0,
setMachineIdleTime: (x: any) => set({ machineIdleTime: x }),
machineIdleTime: 0,
setMachineIdleTime: (x: any) => set({ machineIdleTime: x }),
}));
export const useMaterialCycle = create<any>((set: any) => ({
materialCycleTime: 0,
setMaterialCycleTime: (x: any) => set({ materialCycleTime: x }),
materialCycleTime: 0,
setMaterialCycleTime: (x: any) => set({ materialCycleTime: x }),
}));
export const useThroughPutData = create<any>((set: any) => ({
throughputData: 0,
setThroughputData: (x: any) => set({ throughputData: x }),
throughputData: 0,
setThroughputData: (x: any) => set({ throughputData: x }),
}));
export const useProductionCapacityData = create<any>((set: any) => ({
productionCapacityData: 0,
setProductionCapacityData: (x: any) => set({ productionCapacityData: x }),
productionCapacityData: 0,
setProductionCapacityData: (x: any) => set({ productionCapacityData: x }),
}));
export const useProcessBar = create<any>((set: any) => ({
processBar: [],
setProcessBar: (x: any) => set({ processBar: x }),
processBar: [],
setProcessBar: (x: any) => set({ processBar: x }),
}));
export const useDfxUpload = create<any>((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<string, string>;
setInputValues: (values: Record<string, string>) => void;
updateInputValue: (label: string, value: string) => void; // <- New
inputValues: Record<string, string>;
setInputValues: (values: Record<string, string>) => void;
updateInputValue: (label: string, value: string) => void; // <- New
};
export const useInputValues = create<InputValuesStore>((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<ROISummaryStore>((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<CompareStore>((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<SaveVersionStore>((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<ViewSceneState>((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<any>((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<any>((set: any) => ({
selectedPath: "auto",
setSelectedPath: (x: any) => set({ selectedPath: x }),
selectedPath: "auto",
setSelectedPath: (x: any) => set({ selectedPath: x }),
}));
export const useContextActionStore = create<any>((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<any>((set: any) => ({
paths: [],
setPaths: (x: PathData) => set({ paths: x }),
allPaths: [],
setAllPaths: (x: allPaths) => set({ allPaths: x }),
}));