From d161b70537456c325a6a8515d276688f8bfe8631 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Tue, 22 Apr 2025 17:24:30 +0530 Subject: [PATCH 01/11] feat: Refactor vehicle management and update storage unit load handling; remove unused vehicle component and enhance vehicle status types --- .../users/functions/getAvatarColor.ts | 13 +- .../modules/scene/tools/measurementTool.tsx | 419 +++++++++--------- app/src/modules/simulation/simulation.tsx | 2 + .../instances/animator/vehicleAnimator.tsx | 7 +- .../modules/simulation/vehicle/vehicle.tsx | 14 - .../modules/simulation/vehicle/vehicles.tsx | 133 ++++++ .../widgets/3d/Dropped3dWidget.tsx | 50 +-- .../store/simulation/useStorageUnitStore.ts | 6 +- app/src/store/simulation/useVehicleStore.ts | 5 - app/src/types/simulationTypes.d.ts | 13 +- 10 files changed, 380 insertions(+), 282 deletions(-) delete mode 100644 app/src/modules/simulation/vehicle/vehicle.tsx create mode 100644 app/src/modules/simulation/vehicle/vehicles.tsx diff --git a/app/src/functions/users/functions/getAvatarColor.ts b/app/src/functions/users/functions/getAvatarColor.ts index f2bd816..d9a5d37 100644 --- a/app/src/functions/users/functions/getAvatarColor.ts +++ b/app/src/functions/users/functions/getAvatarColor.ts @@ -25,19 +25,8 @@ const avatarColors: string[] = [ export function getAvatarColor(index: number, name?: string): string { // Check if the color is already stored in localStorage const localStorageKey = "userAvatarColors"; - // Helper function to check if local storage is available - function isLocalStorageAvailable(): boolean { - try { - const testKey = "__test__"; - localStorage.setItem(testKey, "test"); - localStorage.removeItem(testKey); - return true; - } catch (e) { - return false; - } - } // Check if local storage is available - if (isLocalStorageAvailable() && name) { + if (name) { let userColors = JSON.parse(localStorage.getItem(localStorageKey) || "{}"); // Check if the user already has an assigned color diff --git a/app/src/modules/scene/tools/measurementTool.tsx b/app/src/modules/scene/tools/measurementTool.tsx index 9f9fa03..9a30da3 100644 --- a/app/src/modules/scene/tools/measurementTool.tsx +++ b/app/src/modules/scene/tools/measurementTool.tsx @@ -5,240 +5,225 @@ import { useToolMode } from "../../../store/store"; import { Html } from "@react-three/drei"; const MeasurementTool = () => { - const { gl, raycaster, pointer, camera, scene } = useThree(); - const { toolMode } = useToolMode(); + const { gl, raycaster, pointer, camera, scene } = useThree(); + const { toolMode } = useToolMode(); - const [points, setPoints] = useState([]); - const [tubeGeometry, setTubeGeometry] = useState( - null - ); - const groupRef = useRef(null); - const [startConePosition, setStartConePosition] = - useState(null); - const [endConePosition, setEndConePosition] = useState( - null - ); - const [startConeQuaternion, setStartConeQuaternion] = useState( - new THREE.Quaternion() - ); - const [endConeQuaternion, setEndConeQuaternion] = useState( - new THREE.Quaternion() - ); - const [coneSize, setConeSize] = useState({ radius: 0.2, height: 0.5 }); + const [points, setPoints] = useState([]); + const [tubeGeometry, setTubeGeometry] = useState( + null + ); + const groupRef = useRef(null); + const [startConePosition, setStartConePosition] = + useState(null); + const [endConePosition, setEndConePosition] = useState( + null + ); + const [startConeQuaternion, setStartConeQuaternion] = useState( + new THREE.Quaternion() + ); + const [endConeQuaternion, setEndConeQuaternion] = useState( + new THREE.Quaternion() + ); + const [coneSize, setConeSize] = useState({ radius: 0.2, height: 0.5 }); - const MIN_RADIUS = 0.001, - MAX_RADIUS = 0.1; - const MIN_CONE_RADIUS = 0.01, - MAX_CONE_RADIUS = 0.4; - const MIN_CONE_HEIGHT = 0.035, - MAX_CONE_HEIGHT = 2.0; + const MIN_RADIUS = 0.001, MAX_RADIUS = 0.1; + const MIN_CONE_RADIUS = 0.01, MAX_CONE_RADIUS = 0.4; + const MIN_CONE_HEIGHT = 0.035, MAX_CONE_HEIGHT = 2.0; - useEffect(() => { - const canvasElement = gl.domElement; - let drag = false; - let isLeftMouseDown = false; + useEffect(() => { + const canvasElement = gl.domElement; + let drag = false; + let isLeftMouseDown = false; - const onMouseDown = () => { - isLeftMouseDown = true; - drag = false; - }; + const onMouseDown = () => { + isLeftMouseDown = true; + drag = false; + }; - const onMouseUp = (evt: any) => { - isLeftMouseDown = false; - if (evt.button === 0 && !drag) { - raycaster.setFromCamera(pointer, camera); - const intersects = raycaster - .intersectObjects(scene.children, true) - .filter( - (intersect) => - !intersect.object.name.includes("Roof") && - !intersect.object.name.includes("MeasurementReference") && - !intersect.object.name.includes("agv-collider") && - !(intersect.object.type === "GridHelper") - ); + const onMouseUp = (evt: any) => { + isLeftMouseDown = false; + if (evt.button === 0 && !drag) { + raycaster.setFromCamera(pointer, camera); + const intersects = raycaster + .intersectObjects(scene.children, true) + .filter( + (intersect) => + !intersect.object.name.includes("Roof") && + !intersect.object.name.includes("MeasurementReference") && + !intersect.object.name.includes("agv-collider") && + !(intersect.object.type === "GridHelper") + ); - if (intersects.length > 0) { - const intersectionPoint = intersects[0].point.clone(); - if (points.length < 2) { - setPoints([...points, intersectionPoint]); - } else { - setPoints([intersectionPoint]); - } + if (intersects.length > 0) { + const intersectionPoint = intersects[0].point.clone(); + if (points.length < 2) { + setPoints([...points, intersectionPoint]); + } else { + setPoints([intersectionPoint]); + } + } + } + }; + + const onMouseMove = () => { + if (isLeftMouseDown) drag = true; + }; + + const onContextMenu = (evt: any) => { + evt.preventDefault(); + if (!drag) { + evt.preventDefault(); + setPoints([]); + setTubeGeometry(null); + } + }; + + if (toolMode === "MeasurementScale") { + canvasElement.addEventListener("pointerdown", onMouseDown); + canvasElement.addEventListener("pointermove", onMouseMove); + canvasElement.addEventListener("pointerup", onMouseUp); + canvasElement.addEventListener("contextmenu", onContextMenu); + } else { + resetMeasurement(); + setPoints([]); } - } + + return () => { + canvasElement.removeEventListener("pointerdown", onMouseDown); + canvasElement.removeEventListener("pointermove", onMouseMove); + canvasElement.removeEventListener("pointerup", onMouseUp); + canvasElement.removeEventListener("contextmenu", onContextMenu); + }; + }, [toolMode, camera, raycaster, pointer, scene, points]); + + useFrame(() => { + if (points.length === 1) { + raycaster.setFromCamera(pointer, camera); + const intersects = raycaster + .intersectObjects(scene.children, true) + .filter( + (intersect) => + !intersect.object.name.includes("Roof") && + !intersect.object.name.includes("MeasurementReference") && + !intersect.object.name.includes("agv-collider") && + !(intersect.object.type === "GridHelper") + ); + + if (intersects.length > 0) { + updateMeasurement(points[0], intersects[0].point); + } + } else if (points.length === 2) { + updateMeasurement(points[0], points[1]); + } else { + resetMeasurement(); + } + }); + + const updateMeasurement = (start: THREE.Vector3, end: THREE.Vector3) => { + const distance = start.distanceTo(end); + + const radius = THREE.MathUtils.clamp(distance * 0.02, MIN_RADIUS, MAX_RADIUS); + const coneRadius = THREE.MathUtils.clamp(distance * 0.05, MIN_CONE_RADIUS, MAX_CONE_RADIUS); + const coneHeight = THREE.MathUtils.clamp(distance * 0.2, MIN_CONE_HEIGHT, MAX_CONE_HEIGHT); + + setConeSize({ radius: coneRadius, height: coneHeight }); + + const direction = new THREE.Vector3().subVectors(end, start).normalize(); + + const offset = direction.clone().multiplyScalar(coneHeight * 0.5); + + let tubeStart = start.clone().add(offset); + let tubeEnd = end.clone().sub(offset); + + tubeStart.y = Math.max(tubeStart.y, 0); + tubeEnd.y = Math.max(tubeEnd.y, 0); + + const curve = new THREE.CatmullRomCurve3([tubeStart, tubeEnd]); + setTubeGeometry(new THREE.TubeGeometry(curve, 20, radius, 8, false)); + + setStartConePosition(tubeStart); + setEndConePosition(tubeEnd); + setStartConeQuaternion(getArrowOrientation(start, end)); + setEndConeQuaternion(getArrowOrientation(end, start)); }; - const onMouseMove = () => { - if (isLeftMouseDown) drag = true; - }; - - const onContextMenu = (evt: any) => { - evt.preventDefault(); - if (!drag) { - evt.preventDefault(); - setPoints([]); + const resetMeasurement = () => { setTubeGeometry(null); - } + setStartConePosition(null); + setEndConePosition(null); }; - if (toolMode === "MeasurementScale") { - canvasElement.addEventListener("pointerdown", onMouseDown); - canvasElement.addEventListener("pointermove", onMouseMove); - canvasElement.addEventListener("pointerup", onMouseUp); - canvasElement.addEventListener("contextmenu", onContextMenu); - } else { - resetMeasurement(); - setPoints([]); - } - - return () => { - canvasElement.removeEventListener("pointerdown", onMouseDown); - canvasElement.removeEventListener("pointermove", onMouseMove); - canvasElement.removeEventListener("pointerup", onMouseUp); - canvasElement.removeEventListener("contextmenu", onContextMenu); + const getArrowOrientation = (start: THREE.Vector3, end: THREE.Vector3) => { + const direction = new THREE.Vector3() + .subVectors(end, start) + .normalize() + .negate(); + const quaternion = new THREE.Quaternion(); + quaternion.setFromUnitVectors(new THREE.Vector3(0, 1, 0), direction); + return quaternion; }; - }, [toolMode, camera, raycaster, pointer, scene, points]); - useFrame(() => { - if (points.length === 1) { - raycaster.setFromCamera(pointer, camera); - const intersects = raycaster - .intersectObjects(scene.children, true) - .filter( - (intersect) => - !intersect.object.name.includes("Roof") && - !intersect.object.name.includes("MeasurementReference") && - !intersect.object.name.includes("agv-collider") && - !(intersect.object.type === "GridHelper") - ); + useEffect(() => { + if (points.length === 2) { + // console.log(points[0].distanceTo(points[1])); + } + }, [points]); - if (intersects.length > 0) { - updateMeasurement(points[0], intersects[0].point); - } - } else if (points.length === 2) { - updateMeasurement(points[0], points[1]); - } else { - resetMeasurement(); - } - }); + return ( + + {startConePosition && ( + + + + + )} + {endConePosition && ( + + + + + )} + {tubeGeometry && ( + + + + )} - const updateMeasurement = (start: THREE.Vector3, end: THREE.Vector3) => { - const distance = start.distanceTo(end); - - const radius = THREE.MathUtils.clamp( - distance * 0.02, - MIN_RADIUS, - MAX_RADIUS + {startConePosition && endConePosition && ( + +
+ {startConePosition.distanceTo(endConePosition).toFixed(2)} m +
+ + )} +
); - const coneRadius = THREE.MathUtils.clamp( - distance * 0.05, - MIN_CONE_RADIUS, - MAX_CONE_RADIUS - ); - const coneHeight = THREE.MathUtils.clamp( - distance * 0.2, - MIN_CONE_HEIGHT, - MAX_CONE_HEIGHT - ); - - setConeSize({ radius: coneRadius, height: coneHeight }); - - const direction = new THREE.Vector3().subVectors(end, start).normalize(); - - const offset = direction.clone().multiplyScalar(coneHeight * 0.5); - - let tubeStart = start.clone().add(offset); - let tubeEnd = end.clone().sub(offset); - - tubeStart.y = Math.max(tubeStart.y, 0); - tubeEnd.y = Math.max(tubeEnd.y, 0); - - const curve = new THREE.CatmullRomCurve3([tubeStart, tubeEnd]); - setTubeGeometry(new THREE.TubeGeometry(curve, 20, radius, 8, false)); - - setStartConePosition(tubeStart); - setEndConePosition(tubeEnd); - setStartConeQuaternion(getArrowOrientation(start, end)); - setEndConeQuaternion(getArrowOrientation(end, start)); - }; - - const resetMeasurement = () => { - setTubeGeometry(null); - setStartConePosition(null); - setEndConePosition(null); - }; - - const getArrowOrientation = (start: THREE.Vector3, end: THREE.Vector3) => { - const direction = new THREE.Vector3() - .subVectors(end, start) - .normalize() - .negate(); - const quaternion = new THREE.Quaternion(); - quaternion.setFromUnitVectors(new THREE.Vector3(0, 1, 0), direction); - return quaternion; - }; - - useEffect(() => { - if (points.length === 2) { - console.log(points[0].distanceTo(points[1])); - } - }, [points]); - - return ( - - {startConePosition && ( - - - - - )} - {endConePosition && ( - - - - - )} - {tubeGeometry && ( - - - - )} - - {startConePosition && endConePosition && ( - -
- {startConePosition.distanceTo(endConePosition).toFixed(2)} m -
- - )} -
- ); }; export default MeasurementTool; diff --git a/app/src/modules/simulation/simulation.tsx b/app/src/modules/simulation/simulation.tsx index 3599803..1f30e00 100644 --- a/app/src/modules/simulation/simulation.tsx +++ b/app/src/modules/simulation/simulation.tsx @@ -1,6 +1,7 @@ import React, { useEffect } from 'react'; import { useEventsStore } from '../../store/simulation/useEventsStore'; import { useProductStore } from '../../store/simulation/useProductStore'; +import Vehicles from './vehicle/vehicles'; function Simulation() { const { events } = useEventsStore(); @@ -16,6 +17,7 @@ function Simulation() { return ( <> + ) } diff --git a/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx b/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx index 92c1d44..14cb6fa 100644 --- a/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx +++ b/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx @@ -1,9 +1,10 @@ import React from 'react' function VehicleAnimator() { - return ( -
VehicleAnimator
- ) + return ( + <> + + ) } export default VehicleAnimator \ No newline at end of file diff --git a/app/src/modules/simulation/vehicle/vehicle.tsx b/app/src/modules/simulation/vehicle/vehicle.tsx deleted file mode 100644 index e51effc..0000000 --- a/app/src/modules/simulation/vehicle/vehicle.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import React from 'react' -import VehicleInstances from './instances/vehicleInstances'; - -function Vehicle() { - return ( - <> - - - - - ) -} - -export default Vehicle \ No newline at end of file diff --git a/app/src/modules/simulation/vehicle/vehicles.tsx b/app/src/modules/simulation/vehicle/vehicles.tsx new file mode 100644 index 0000000..7a270d4 --- /dev/null +++ b/app/src/modules/simulation/vehicle/vehicles.tsx @@ -0,0 +1,133 @@ +import React, { useEffect } from 'react' +import VehicleInstances from './instances/vehicleInstances'; + +import { useVehicleStore } from '../../../store/simulation/useVehicleStore'; + +function Vehicles() { + + const { vehicles, addVehicle } = useVehicleStore(); + + const vehicleStatusSample: VehicleStatus[] = [ + { + modelUuid: "veh-123", + modelName: "Autonomous Truck A1", + position: [10, 0, 5], + rotation: [0, 0, 0], + state: "idle", + type: "vehicle", + speed: 2.5, + point: { + uuid: "point-789", + position: [0, 1, 0], + rotation: [0, 0, 0], + action: { + actionUuid: "action-456", + actionName: "Deliver to Zone A", + actionType: "travel", + material: "crate", + unLoadDuration: 15, + loadCapacity: 5, + pickUpPoint: { x: 5, y: 0, z: 3 }, + unLoadPoint: { x: 20, y: 0, z: 10 }, + triggers: [ + { + triggerUuid: "trig-001", + triggerName: "Start Travel", + triggerType: "onComplete", + delay: 0, + triggeredAsset: { + triggeredModel: { modelName: "ArmBot-X", modelUuid: "arm-001" }, + triggeredPoint: { pointName: "Pickup Arm Point", pointUuid: "arm-point-01" }, + triggeredAction: { actionName: "Grab Widget", actionUuid: "grab-001" } + } + }, + { + triggerUuid: "trig-002", + triggerName: "Complete Travel", + triggerType: "onComplete", + delay: 2, + triggeredAsset: null + } + ] + } + }, + productId: "prod-890", + isActive: false, + idleTime: 0, + activeTime: 0, + currentLoad: 0, + distanceTraveled: 0 + }, + { + modelUuid: "veh-123", + modelName: "Autonomous Truck A1", + position: [10, 0, 5], + rotation: [0, 0, 0], + state: "idle", + type: "vehicle", + speed: 2.5, + point: { + uuid: "point-789", + position: [0, 1, 0], + rotation: [0, 0, 0], + action: { + actionUuid: "action-456", + actionName: "Deliver to Zone A", + actionType: "travel", + material: "crate", + unLoadDuration: 15, + loadCapacity: 5, + pickUpPoint: { x: 5, y: 0, z: 3 }, + unLoadPoint: { x: 20, y: 0, z: 10 }, + triggers: [ + { + triggerUuid: "trig-001", + triggerName: "Start Travel", + triggerType: "onStart", + delay: 0, + triggeredAsset: { + triggeredModel: { modelName: "ArmBot-X", modelUuid: "arm-001" }, + triggeredPoint: { pointName: "Pickup Arm Point", pointUuid: "arm-point-01" }, + triggeredAction: { actionName: "Grab Widget", actionUuid: "grab-001" } + } + }, + { + triggerUuid: "trig-002", + triggerName: "Complete Travel", + triggerType: "onComplete", + delay: 2, + triggeredAsset: null + } + ] + } + }, + productId: "prod-890", + isActive: false, + idleTime: 0, + activeTime: 0, + currentLoad: 0, + distanceTraveled: 0 + } + ]; + + + useEffect(() => { + addVehicle('123', vehicleStatusSample[0]); + addVehicle('123', vehicleStatusSample[1]); + }, []) + + useEffect(() => { + console.log('vehicles: ', vehicles); + }, [vehicles]) + + + return ( + <> + + + + + ) +} + +export default Vehicles; \ No newline at end of file diff --git a/app/src/modules/visualization/widgets/3d/Dropped3dWidget.tsx b/app/src/modules/visualization/widgets/3d/Dropped3dWidget.tsx index d09a88f..4ca3c31 100644 --- a/app/src/modules/visualization/widgets/3d/Dropped3dWidget.tsx +++ b/app/src/modules/visualization/widgets/3d/Dropped3dWidget.tsx @@ -44,7 +44,7 @@ export default function Dropped3dWidgets() { const rotationStartRef = useRef<[number, number, number]>([0, 0, 0]); const mouseStartRef = useRef<{ x: number; y: number }>({ x: 0, y: 0 }); const { setSelectedChartId } = useWidgetStore(); - const { measurements, duration} = useChartStore(); + const { measurements, duration } = useChartStore(); let [floorPlanesVertical, setFloorPlanesVertical] = useState( new THREE.Plane(new THREE.Vector3(0, 1, 0)) ); @@ -117,7 +117,6 @@ export default function Dropped3dWidgets() { !intersect.object.name.includes("Roof") && !intersect.object.name.includes("agv-collider") && !intersect.object.name.includes("MeasurementReference") && - !intersect.object.userData.isPathObject && !(intersect.object.type === "GridHelper") ); @@ -154,7 +153,6 @@ export default function Dropped3dWidgets() { !intersect.object.name.includes("Roof") && !intersect.object.name.includes("agv-collider") && !intersect.object.name.includes("MeasurementReference") && - !intersect.object.userData.isPathObject && !(intersect.object.type === "GridHelper") ); // Update widget's position in memory @@ -169,28 +167,28 @@ export default function Dropped3dWidgets() { const onDrop = (event: any) => { event.preventDefault(); event.stopPropagation(); - + hasEntered.current = false; - + const email = localStorage.getItem("email") || ""; const organization = email?.split("@")[1]?.split(".")[0]; - + const newWidget = createdWidgetRef.current; if (!newWidget || !widgetSelect.startsWith("ui")) return; - + // ✅ Extract 2D drop position let [x, y, z] = newWidget.position; - + // ✅ Clamp Y to at least 0 y = Math.max(y, 0); newWidget.position = [x, y, z]; - + // ✅ Prepare polygon from selectedZone.points const points3D = selectedZone.points as Array<[number, number, number]>; const zonePolygonXZ = points3D.map(([x, , z]) => [x, z] as [number, number]); - + const isInside = isPointInPolygon([x, z], zonePolygonXZ); - + // ✅ Remove temp widget const prevWidgets = useZoneWidgetStore.getState().zoneWidgetData[selectedZone.zoneId] || []; const cleanedWidgets = prevWidgets.filter(w => w.id !== newWidget.id); @@ -200,29 +198,29 @@ export default function Dropped3dWidgets() { [selectedZone.zoneId]: cleanedWidgets, }, })); - + // (Optional) Prevent adding if dropped outside zone // if (!isInside) { // createdWidgetRef.current = null; // return; // } - + // ✅ Add widget addWidget(selectedZone.zoneId, newWidget); - + const add3dWidget = { organization, widget: newWidget, zoneId: selectedZone.zoneId, }; - + if (visualizationSocket) { visualizationSocket.emit("v2:viz-3D-widget:add", add3dWidget); } - + createdWidgetRef.current = null; }; - + canvasElement.addEventListener("dragenter", handleDragEnter); @@ -258,7 +256,7 @@ export default function Dropped3dWidgets() { widgetToDuplicate.position[2] + 0.5, ], rotation: widgetToDuplicate.rotation || [0, 0, 0], - Data:{ + Data: { measurements: measurements, duration: duration }, @@ -365,7 +363,7 @@ export default function Dropped3dWidgets() { // floorPlanesVertical, // planeIntersect.current // ); - + // setintersectcontextmenu(intersect1.y); if (rightSelect === "RotateX" || rightSelect === "RotateY") { @@ -385,7 +383,7 @@ export default function Dropped3dWidgets() { rotationStartRef.current = selectedWidget.rotation || [0, 0, 0]; } } - + }; const handleMouseMove = (event: MouseEvent) => { @@ -429,7 +427,7 @@ export default function Dropped3dWidgets() { intersect.z + horizontalZ, ]; - + updateWidgetPosition(selectedZoneId, rightClickSelected, newPosition); } } @@ -437,24 +435,24 @@ export default function Dropped3dWidgets() { if (rightSelect === "Vertical Move") { const intersect = raycaster.ray.intersectPlane(floorPlanesVertical, planeIntersect.current); - + if (intersect && typeof intersectcontextmenu === "number") { const diff = intersect.y - intersectcontextmenu; const unclampedY = selectedWidget.position[1] + diff; const newY = Math.max(0, unclampedY); // Prevent going below floor (y=0) - + setintersectcontextmenu(intersect.y); - + const newPosition: [number, number, number] = [ selectedWidget.position[0], newY, selectedWidget.position[2], ]; - + updateWidgetPosition(selectedZoneId, rightClickSelected, newPosition); } } - + if (rightSelect?.startsWith("Rotate")) { const axis = rightSelect.slice(-1).toLowerCase(); // "x", "y", or "z" const currentX = event.pageX; diff --git a/app/src/store/simulation/useStorageUnitStore.ts b/app/src/store/simulation/useStorageUnitStore.ts index 52e4185..04b4db0 100644 --- a/app/src/store/simulation/useStorageUnitStore.ts +++ b/app/src/store/simulation/useStorageUnitStore.ts @@ -25,7 +25,7 @@ interface StorageUnitStore { setStorageUnitState: (modelUuid: string, newState: StorageUnitStatus['state']) => void; // Load updates - updateStorageUnitLoad: (modelUuid: string, load: number) => void; + updateStorageUnitLoad: (modelUuid: string, incrementBy: number) => void; // Time tracking incrementActiveTime: (modelUuid: string, incrementBy: number) => void; @@ -95,11 +95,11 @@ export const useStorageUnitStore = create()( }, // Load updates - updateStorageUnitLoad: (modelUuid, load) => { + updateStorageUnitLoad: (modelUuid, incrementBy) => { set((state) => { const unit = state.storageUnits.find(s => s.modelUuid === modelUuid); if (unit) { - unit.currentLoad = load; + unit.currentLoad += incrementBy; } }); }, diff --git a/app/src/store/simulation/useVehicleStore.ts b/app/src/store/simulation/useVehicleStore.ts index 4eba3f5..9f7ac50 100644 --- a/app/src/store/simulation/useVehicleStore.ts +++ b/app/src/store/simulation/useVehicleStore.ts @@ -30,7 +30,6 @@ interface VehiclesStore { getVehiclesByProduct: (productId: string) => VehicleStatus[]; getVehiclesByState: (state: string) => VehicleStatus[]; getActiveVehicles: () => VehicleStatus[]; - getIdleVehicles: () => VehicleStatus[]; } export const useVehicleStore = create()( @@ -125,10 +124,6 @@ export const useVehicleStore = create()( getActiveVehicles: () => { return get().vehicles.filter(v => v.isActive); - }, - - getIdleVehicles: () => { - return get().vehicles.filter(v => !v.isActive && v.currentLoad > 0); } })) ); diff --git a/app/src/types/simulationTypes.d.ts b/app/src/types/simulationTypes.d.ts index 8f0c180..3d75662 100644 --- a/app/src/types/simulationTypes.d.ts +++ b/app/src/types/simulationTypes.d.ts @@ -42,7 +42,7 @@ interface VehiclePointSchema { actionUuid: string; actionName: string; actionType: "travel"; - material: string; + material: string | null; unLoadDuration: number; loadCapacity: number; pickUpPoint: { x: number; y: number, z: number } | null; @@ -125,4 +125,13 @@ type productsSchema = { productName: string; productId: string; eventsData: EventsSchema[]; -}[] \ No newline at end of file +}[] + +interface VehicleStatus extends VehicleEventSchema { + productId: string; + isActive: boolean; + idleTime: number; + activeTime: number; + currentLoad: number; + distanceTraveled: number; +} \ No newline at end of file From cd737ed74cfa87c3bb7b28570aec3f874c243136 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Tue, 22 Apr 2025 19:02:44 +0530 Subject: [PATCH 02/11] feat: Implement Points management with PointsCreator component; enhance event handling and transform controls for simulation points --- .../geomentries/assets/addAssetModel.ts | 97 ++++++++++-- .../events/points/creator/pointsCreator.tsx | 148 ++++++++++++++++++ .../simulation/events/points/points.tsx | 12 ++ app/src/modules/simulation/simulation.tsx | 7 +- .../modules/simulation/vehicle/vehicles.tsx | 2 +- app/src/types/simulationTypes.d.ts | 2 +- 6 files changed, 248 insertions(+), 20 deletions(-) create mode 100644 app/src/modules/simulation/events/points/creator/pointsCreator.tsx create mode 100644 app/src/modules/simulation/events/points/points.tsx diff --git a/app/src/modules/builder/geomentries/assets/addAssetModel.ts b/app/src/modules/builder/geomentries/assets/addAssetModel.ts index 5837958..5bdb558 100644 --- a/app/src/modules/builder/geomentries/assets/addAssetModel.ts +++ b/app/src/modules/builder/geomentries/assets/addAssetModel.ts @@ -184,24 +184,9 @@ async function handleModelLoad( ); if (!data || !data.points) return; - console.log('data: ', data); - - const createMarker = (point: THREE.Vector3) => { - const sphere = new THREE.SphereGeometry(0.1, 15); - const material = new THREE.MeshStandardMaterial(); - const mesh = new THREE.Mesh(sphere, material); - mesh.position.copy(point); - return mesh; - }; - - if (data.points && data.points.length > 0) { - data.points.forEach((Point) => { - model.add(createMarker(Point)); - }); - } if (selectedItem.type === "Conveyor") { - const event: ConveyorEventSchema = { + const ConveyorEvent: ConveyorEventSchema = { modelUuid: newFloorItem.modeluuid, modelName: newFloorItem.modelname, position: newFloorItem.position, @@ -225,7 +210,85 @@ async function handleModelLoad( } })) } - addEvent(event); + addEvent(ConveyorEvent); + } else if (selectedItem.type === "Vehicle") { + const vehicleEvent: VehicleEventSchema = { + modelUuid: newFloorItem.modeluuid, + modelName: newFloorItem.modelname, + position: newFloorItem.position, + rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z], + state: "idle", + type: "vehicle", + speed: 1, + point: { + uuid: THREE.MathUtils.generateUUID(), + position: [data.points[0].x, data.points[0].y, data.points[0].z], + rotation: [0, 0, 0], + action: { + actionUuid: THREE.MathUtils.generateUUID(), + actionName: "Vehicle Action", + actionType: "travel", + material: null, + unLoadDuration: 5, + loadCapacity: 10, + pickUpPoint: null, + unLoadPoint: null, + triggers: [] + } + } + }; + addEvent(vehicleEvent); + } else if (selectedItem.type === "ArmBot") { + const roboticArmEvent: RoboticArmEventSchema = { + modelUuid: newFloorItem.modeluuid, + modelName: newFloorItem.modelname, + position: newFloorItem.position, + rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z], + state: "idle", + type: "roboticArm", + speed: 1, + point: { + uuid: THREE.MathUtils.generateUUID(), + position: [data.points[0].x, data.points[0].y, data.points[0].z], + rotation: [0, 0, 0], + actions: [ + { + actionUuid: THREE.MathUtils.generateUUID(), + actionName: "Pick and Place", + actionType: "pickAndPlace", + process: { + startPoint: "start-point-uuid", + endPoint: "end-point-uuid" + }, + triggers: [] + } + ] + } + }; + addEvent(roboticArmEvent); + } else if (selectedItem.type === "Machine") { + const machineEvent: MachineEventSchema = { + modelUuid: newFloorItem.modeluuid, + modelName: newFloorItem.modelname, + position: newFloorItem.position, + rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z], + state: "idle", + type: "machine", + point: { + uuid: THREE.MathUtils.generateUUID(), + position: [data.points[0].x, data.points[0].y, data.points[0].z], + rotation: [0, 0, 0], + action: { + actionUuid: THREE.MathUtils.generateUUID(), + actionName: "Process Action", + actionType: "process", + processTime: 10, + swapMaterial: "material-id", + triggers: [] + } + } + }; + addEvent(machineEvent); } } diff --git a/app/src/modules/simulation/events/points/creator/pointsCreator.tsx b/app/src/modules/simulation/events/points/creator/pointsCreator.tsx new file mode 100644 index 0000000..335f1f5 --- /dev/null +++ b/app/src/modules/simulation/events/points/creator/pointsCreator.tsx @@ -0,0 +1,148 @@ +import React, { useEffect, useRef, useState } from 'react'; +import * as THREE from 'three'; +import { useEventsStore } from '../../../../../store/simulation/useEventsStore'; +import useModuleStore from '../../../../../store/useModuleStore'; +import { TransformControls } from '@react-three/drei'; +import { detectModifierKeys } from '../../../../../utils/shortcutkeys/detectModifierKeys'; + +function PointsCreator() { + const { events, updatePoint, getPointByUuid } = useEventsStore(); + const { activeModule } = useModuleStore(); + const transformRef = useRef(null); + const [transformMode, setTransformMode] = useState<"translate" | "rotate" | null>(null); + const [selectedPoint, setSelectedPoint] = useState(null); + const sphereRefs = useRef<{ [key: string]: THREE.Mesh }>({}); + + useEffect(() => { + setTransformMode(null); + const handleKeyDown = (e: KeyboardEvent) => { + const keyCombination = detectModifierKeys(e); + if (!selectedPoint) return; + if (keyCombination === "G") { + setTransformMode((prev) => (prev === "translate" ? null : "translate")); + } + if (keyCombination === "R") { + setTransformMode((prev) => (prev === "rotate" ? null : "rotate")); + } + }; + + window.addEventListener("keydown", handleKeyDown); + return () => window.removeEventListener("keydown", handleKeyDown); + }, [selectedPoint]); + + const updatePointToState = (selectedPoint: THREE.Mesh) => { + let point = JSON.parse(JSON.stringify(getPointByUuid(selectedPoint.userData.modelUuid, selectedPoint.userData.pointUuid))); + if (point) { + point.position = [selectedPoint.position.x, selectedPoint.position.y, selectedPoint.position.z]; + updatePoint(selectedPoint.userData.modelUuid, selectedPoint.userData.pointUuid, point) + } + } + + return ( + <> + {activeModule === 'simulation' && + <> + + {events.map((event, i) => { + if (event.type === 'transfer') { + return ( + + {event.points.map((point, j) => ( + (sphereRefs.current[point.uuid] = el!)} + onClick={(e) => { + e.stopPropagation(); + setSelectedPoint(sphereRefs.current[point.uuid]); + }} + onPointerMissed={() => { + setSelectedPoint(null); + }} + key={`${i}-${j}`} + position={new THREE.Vector3(...point.position)} + userData={{ modelUuid: event.modelUuid, pointUuid: point.uuid }} + > + + + + ))} + + ); + } else if (event.type === 'vehicle') { + return ( + + (sphereRefs.current[event.point.uuid] = el!)} + onClick={(e) => { + e.stopPropagation(); + setSelectedPoint(sphereRefs.current[event.point.uuid]); + }} + onPointerMissed={() => { + setSelectedPoint(null); + }} + position={new THREE.Vector3(...event.point.position)} + userData={{ modelUuid: event.modelUuid, pointUuid: event.point.uuid }} + > + + + + + ); + } else if (event.type === 'roboticArm') { + return ( + + (sphereRefs.current[event.point.uuid] = el!)} + onClick={(e) => { + e.stopPropagation(); + setSelectedPoint(sphereRefs.current[event.point.uuid]); + }} + onPointerMissed={() => { + setSelectedPoint(null); + }} + position={new THREE.Vector3(...event.point.position)} + userData={{ modelUuid: event.modelUuid, pointUuid: event.point.uuid }} + > + + + + + ); + } else if (event.type === 'machine') { + return ( + + (sphereRefs.current[event.point.uuid] = el!)} + onClick={(e) => { + e.stopPropagation(); + setSelectedPoint(sphereRefs.current[event.point.uuid]); + }} + onPointerMissed={() => { + setSelectedPoint(null); + }} + position={new THREE.Vector3(...event.point.position)} + userData={{ modelUuid: event.modelUuid, pointUuid: event.point.uuid }} + > + + + + + ); + } else { + return null; + } + })} + + {(selectedPoint && transformMode) && + { updatePointToState(selectedPoint) }} /> + } + + } + + ); +} + +export default PointsCreator; diff --git a/app/src/modules/simulation/events/points/points.tsx b/app/src/modules/simulation/events/points/points.tsx new file mode 100644 index 0000000..2a50f2d --- /dev/null +++ b/app/src/modules/simulation/events/points/points.tsx @@ -0,0 +1,12 @@ +import React from 'react' +import PointsCreator from './creator/pointsCreator' + +function Points() { + return ( + <> + + + ) +} + +export default Points \ No newline at end of file diff --git a/app/src/modules/simulation/simulation.tsx b/app/src/modules/simulation/simulation.tsx index 1f30e00..1be292e 100644 --- a/app/src/modules/simulation/simulation.tsx +++ b/app/src/modules/simulation/simulation.tsx @@ -2,6 +2,7 @@ import React, { useEffect } from 'react'; import { useEventsStore } from '../../store/simulation/useEventsStore'; import { useProductStore } from '../../store/simulation/useProductStore'; import Vehicles from './vehicle/vehicles'; +import Points from './events/points/points'; function Simulation() { const { events } = useEventsStore(); @@ -12,12 +13,16 @@ function Simulation() { }, [events]) useEffect(() => { - console.log('products: ', products); + // console.log('products: ', products); }, [products]) return ( <> + + + + ) } diff --git a/app/src/modules/simulation/vehicle/vehicles.tsx b/app/src/modules/simulation/vehicle/vehicles.tsx index 7a270d4..5d6681b 100644 --- a/app/src/modules/simulation/vehicle/vehicles.tsx +++ b/app/src/modules/simulation/vehicle/vehicles.tsx @@ -117,7 +117,7 @@ function Vehicles() { }, []) useEffect(() => { - console.log('vehicles: ', vehicles); + // console.log('vehicles: ', vehicles); }, [vehicles]) diff --git a/app/src/types/simulationTypes.d.ts b/app/src/types/simulationTypes.d.ts index 3d75662..2b3fc1e 100644 --- a/app/src/types/simulationTypes.d.ts +++ b/app/src/types/simulationTypes.d.ts @@ -119,7 +119,7 @@ interface StorageEventSchema extends AssetEventSchema { point: StoragePointSchema; } -type EventsSchema = ConveyorEventSchema | VehicleEventSchema | RoboticArmEventSchema | MachineEventSchema | StorageEventSchema | []; +type EventsSchema = ConveyorEventSchema | VehicleEventSchema | RoboticArmEventSchema | MachineEventSchema | StorageEventSchema; type productsSchema = { productName: string; From bcc908bfca788034573248784421891649cf6f10 Mon Sep 17 00:00:00 2001 From: Poovizhi99 Date: Wed, 23 Apr 2025 09:13:33 +0530 Subject: [PATCH 03/11] added static agv --- .../builder/groups/floorItemsGroup.tsx | 4 +- .../instances/instance/vehicleInstance.tsx | 2 +- .../vehicle/instances/vehicleInstances.tsx | 9 ++- .../modules/simulation/vehicle/vehicles.tsx | 63 ++++++++++++++++--- 4 files changed, 66 insertions(+), 12 deletions(-) diff --git a/app/src/modules/builder/groups/floorItemsGroup.tsx b/app/src/modules/builder/groups/floorItemsGroup.tsx index 23fa80d..04376ce 100644 --- a/app/src/modules/builder/groups/floorItemsGroup.tsx +++ b/app/src/modules/builder/groups/floorItemsGroup.tsx @@ -16,10 +16,10 @@ import addAssetModel from "../geomentries/assets/addAssetModel"; import { getFloorAssets } from "../../../services/factoryBuilder/assest/floorAsset/getFloorItemsApi"; import useModuleStore from "../../../store/useModuleStore"; // import { retrieveGLTF } from "../../../utils/indexDB/idbUtils"; -const assetManagerWorker = new Worker(new URL("../../../services/factoryBuilder/webWorkers/assetManagerWorker.js", import.meta.url)); -const gltfLoaderWorker = new Worker(new URL("../../../services/factoryBuilder/webWorkers/gltfLoaderWorker.js", import.meta.url)); import { useEventsStore } from "../../../store/simulation/useEventsStore"; +const assetManagerWorker = new Worker(new URL("../../../services/factoryBuilder/webWorkers/assetManagerWorker.js", import.meta.url)); +const gltfLoaderWorker = new Worker(new URL("../../../services/factoryBuilder/webWorkers/gltfLoaderWorker.js", import.meta.url)); const FloorItemsGroup = ({ itemsGroup, hoveredDeletableFloorItem, AttachedObject, floorGroup, tempLoader, isTempLoader, plane, }: any) => { const state: Types.ThreeState = useThree(); diff --git a/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx b/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx index 0996b3c..283be58 100644 --- a/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx +++ b/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx @@ -1,7 +1,7 @@ import React from 'react' import VehicleAnimator from '../animator/vehicleAnimator' -function VehicleInstance() { +function VehicleInstance({ agvDetails }: any) { return ( <> diff --git a/app/src/modules/simulation/vehicle/instances/vehicleInstances.tsx b/app/src/modules/simulation/vehicle/instances/vehicleInstances.tsx index 13e15b7..8374080 100644 --- a/app/src/modules/simulation/vehicle/instances/vehicleInstances.tsx +++ b/app/src/modules/simulation/vehicle/instances/vehicleInstances.tsx @@ -1,11 +1,16 @@ import React from 'react' import VehicleInstance from './instance/vehicleInstance' -function VehicleInstances() { +function VehicleInstances({ vehicles }: any) { return ( <> - + {vehicles.map((val: any) => + + + ) + + } ) diff --git a/app/src/modules/simulation/vehicle/vehicles.tsx b/app/src/modules/simulation/vehicle/vehicles.tsx index 7a270d4..b5cf86f 100644 --- a/app/src/modules/simulation/vehicle/vehicles.tsx +++ b/app/src/modules/simulation/vehicle/vehicles.tsx @@ -9,8 +9,8 @@ function Vehicles() { const vehicleStatusSample: VehicleStatus[] = [ { - modelUuid: "veh-123", - modelName: "Autonomous Truck A1", + modelUuid: "2c01ed76-359a-485b-83d4-052cfcdb9d89", + modelName: "AGV", position: [10, 0, 5], rotation: [0, 0, 0], state: "idle", @@ -18,7 +18,7 @@ function Vehicles() { speed: 2.5, point: { uuid: "point-789", - position: [0, 1, 0], + position: [93.42159216649789, 0, 23.790878603572857], rotation: [0, 0, 0], action: { actionUuid: "action-456", @@ -59,9 +59,58 @@ function Vehicles() { distanceTraveled: 0 }, { - modelUuid: "veh-123", - modelName: "Autonomous Truck A1", - position: [10, 0, 5], + modelUuid: "311130b9-4f2e-425a-b3b5-5039cb348806", + modelName: "AGV", + position: [95.69567023145055, 0, 33.18042399595448], + rotation: [0, 0, 0], + state: "idle", + type: "vehicle", + speed: 2.5, + point: { + uuid: "point-789", + position: [0, 1, 0], + rotation: [0, 0, 0], + action: { + actionUuid: "action-456", + actionName: "Deliver to Zone A", + actionType: "travel", + material: "crate", + unLoadDuration: 15, + loadCapacity: 5, + pickUpPoint: { x: 5, y: 0, z: 3 }, + unLoadPoint: { x: 20, y: 0, z: 10 }, + triggers: [ + { + triggerUuid: "trig-001", + triggerName: "Start Travel", + triggerType: "onStart", + delay: 0, + triggeredAsset: { + triggeredModel: { modelName: "ArmBot-X", modelUuid: "arm-001" }, + triggeredPoint: { pointName: "Pickup Arm Point", pointUuid: "arm-point-01" }, + triggeredAction: { actionName: "Grab Widget", actionUuid: "grab-001" } + } + }, + { + triggerUuid: "trig-002", + triggerName: "Complete Travel", + triggerType: "onComplete", + delay: 2, + triggeredAsset: null + } + ] + } + }, + productId: "prod-890", + isActive: false, + idleTime: 0, + activeTime: 0, + currentLoad: 0, + distanceTraveled: 0 + }, { + modelUuid: "fa54132c-8333-4832-becb-5281f5e11549", + modelName: "AGV", + position: [102.71483985219794, 0, 23.66321267938962], rotation: [0, 0, 0], state: "idle", type: "vehicle", @@ -124,7 +173,7 @@ function Vehicles() { return ( <> - + ) From 4ad5e1255b864672ff1ca83f0019cf2d782ba617 Mon Sep 17 00:00:00 2001 From: Poovizhi99 Date: Wed, 23 Apr 2025 12:25:52 +0530 Subject: [PATCH 04/11] added functionalities for vehicle --- .../instances/animator/vehicleAnimator.tsx | 36 +++++++++- .../instances/instance/vehicleInstance.tsx | 65 +++++++++++++++++-- .../vehicle/instances/vehicleInstances.tsx | 9 +-- .../modules/simulation/vehicle/vehicles.tsx | 1 + 4 files changed, 97 insertions(+), 14 deletions(-) diff --git a/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx b/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx index 14cb6fa..db6bedb 100644 --- a/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx +++ b/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx @@ -1,6 +1,38 @@ -import React from 'react' +import { useFrame, useThree } from '@react-three/fiber'; +import React, { useEffect, useState } from 'react' -function VehicleAnimator() { +interface VehicleAnimatorProps { + path: [number, number, number][]; + handleCallBack: () => void; + currentPhase: string; + agvUuid: number +} + + +function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid }: VehicleAnimatorProps) { + + const [currentPath, setCurrentPath] = useState<[number, number, number][]>([]); + const { scene } = useThree(); + + useEffect(() => { + + if (currentPhase === 'stationed-pickup' && path.length > 0) { + + + setCurrentPath(path); + + } + + }, [currentPhase, path]) + + useFrame(() => { + if (currentPath.length === 0) return; + const object = scene.getObjectByProperty("uuid", agvUuid); + if (!object) return; + + + + }) return ( <> diff --git a/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx b/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx index 283be58..e381311 100644 --- a/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx +++ b/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx @@ -1,14 +1,67 @@ -import React from 'react' +import React, { useCallback, useEffect, useState } from 'react' import VehicleAnimator from '../animator/vehicleAnimator' +import * as THREE from "three"; +import { NavMeshQuery } from '@recast-navigation/core'; +import { useNavMesh } from '../../../../../store/store'; +import { usePlayButtonStore } from '../../../../../store/usePlayButtonStore'; +import { useVehicleStore } from '../../../../../store/simulation/useVehicleStore'; function VehicleInstance({ agvDetails }: any) { - return ( - <> + const { navMesh } = useNavMesh(); + const { isPlaying } = usePlayButtonStore(); + const { setVehicleActive, setVehicleState } = useVehicleStore(); + const [currentPhase, setCurrentPhase] = useState<(string)>("stationed"); + const [path, setPath] = useState<[number, number, number][]>([]); - + const computePath = useCallback((start: any, end: any) => { - - ) + + try { + const navMeshQuery = new NavMeshQuery(navMesh); + const { path: segmentPath } = navMeshQuery.computePath(start, end); + return ( + segmentPath?.map( + ({ x, y, z }) => [x, y + 0.1, z] as [number, number, number] + ) || [] + ); + } catch { + return []; + } + }, [navMesh]); + + useEffect(() => { + // const pickupToDropPath = computePath(pickup, drop); + // const dropToPickupPath = computePath(drop, pickup); + + if (isPlaying) { + if (!agvDetails.isActive && agvDetails.state == "idle" && currentPhase == "stationed") { + const toPickupPath = computePath(new THREE.Vector3(agvDetails.position[0], agvDetails.position[1], agvDetails.position[2]), agvDetails.point.action.pickUpPoint); + setPath(toPickupPath) + setVehicleActive(agvDetails.modelUuid, true) + setVehicleState(agvDetails.modelUuid, "running") + setCurrentPhase("stationed-pickup") + // + } + } + }, [agvDetails, currentPhase, path, isPlaying]) + + function handleCallBack() { + if (currentPhase === "stationed-pickup") { + setVehicleActive(agvDetails.modelUuid, false) + setVehicleState(agvDetails.modelUuid, "idle") + setCurrentPhase("picking") + setPath([]) + } + } + + + return ( + <> + + + + + ) } export default VehicleInstance \ No newline at end of file diff --git a/app/src/modules/simulation/vehicle/instances/vehicleInstances.tsx b/app/src/modules/simulation/vehicle/instances/vehicleInstances.tsx index 8374080..f3f1435 100644 --- a/app/src/modules/simulation/vehicle/instances/vehicleInstances.tsx +++ b/app/src/modules/simulation/vehicle/instances/vehicleInstances.tsx @@ -5,12 +5,9 @@ function VehicleInstances({ vehicles }: any) { return ( <> - {vehicles.map((val: any) => - - - ) - - } + {vehicles.map((val: any, i: any) => + + )} ) diff --git a/app/src/modules/simulation/vehicle/vehicles.tsx b/app/src/modules/simulation/vehicle/vehicles.tsx index b5cf86f..b9bc07b 100644 --- a/app/src/modules/simulation/vehicle/vehicles.tsx +++ b/app/src/modules/simulation/vehicle/vehicles.tsx @@ -163,6 +163,7 @@ function Vehicles() { useEffect(() => { addVehicle('123', vehicleStatusSample[0]); addVehicle('123', vehicleStatusSample[1]); + addVehicle('123', vehicleStatusSample[2]); }, []) useEffect(() => { From 58b0e779fd326ebf319ea43abf97f242c20c961c Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Wed, 23 Apr 2025 12:27:02 +0530 Subject: [PATCH 05/11] Revert "Merge remote-tracking branch 'origin/simulation-agv-v2' into v2" This reverts commit 27c7072cc918b14f64cddd21501887cb11cdd040, reversing changes made to cd737ed74cfa87c3bb7b28570aec3f874c243136. --- .../builder/groups/floorItemsGroup.tsx | 4 +- .../instances/animator/vehicleAnimator.tsx | 36 +--------- .../instances/instance/vehicleInstance.tsx | 67 ++----------------- .../vehicle/instances/vehicleInstances.tsx | 6 +- .../modules/simulation/vehicle/vehicles.tsx | 64 ++---------------- 5 files changed, 20 insertions(+), 157 deletions(-) diff --git a/app/src/modules/builder/groups/floorItemsGroup.tsx b/app/src/modules/builder/groups/floorItemsGroup.tsx index 04376ce..23fa80d 100644 --- a/app/src/modules/builder/groups/floorItemsGroup.tsx +++ b/app/src/modules/builder/groups/floorItemsGroup.tsx @@ -16,11 +16,11 @@ import addAssetModel from "../geomentries/assets/addAssetModel"; import { getFloorAssets } from "../../../services/factoryBuilder/assest/floorAsset/getFloorItemsApi"; import useModuleStore from "../../../store/useModuleStore"; // import { retrieveGLTF } from "../../../utils/indexDB/idbUtils"; - -import { useEventsStore } from "../../../store/simulation/useEventsStore"; const assetManagerWorker = new Worker(new URL("../../../services/factoryBuilder/webWorkers/assetManagerWorker.js", import.meta.url)); const gltfLoaderWorker = new Worker(new URL("../../../services/factoryBuilder/webWorkers/gltfLoaderWorker.js", import.meta.url)); +import { useEventsStore } from "../../../store/simulation/useEventsStore"; + const FloorItemsGroup = ({ itemsGroup, hoveredDeletableFloorItem, AttachedObject, floorGroup, tempLoader, isTempLoader, plane, }: any) => { const state: Types.ThreeState = useThree(); const { raycaster, controls }: any = state; diff --git a/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx b/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx index db6bedb..14cb6fa 100644 --- a/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx +++ b/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx @@ -1,38 +1,6 @@ -import { useFrame, useThree } from '@react-three/fiber'; -import React, { useEffect, useState } from 'react' +import React from 'react' -interface VehicleAnimatorProps { - path: [number, number, number][]; - handleCallBack: () => void; - currentPhase: string; - agvUuid: number -} - - -function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid }: VehicleAnimatorProps) { - - const [currentPath, setCurrentPath] = useState<[number, number, number][]>([]); - const { scene } = useThree(); - - useEffect(() => { - - if (currentPhase === 'stationed-pickup' && path.length > 0) { - - - setCurrentPath(path); - - } - - }, [currentPhase, path]) - - useFrame(() => { - if (currentPath.length === 0) return; - const object = scene.getObjectByProperty("uuid", agvUuid); - if (!object) return; - - - - }) +function VehicleAnimator() { return ( <> diff --git a/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx b/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx index e381311..0996b3c 100644 --- a/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx +++ b/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx @@ -1,67 +1,14 @@ -import React, { useCallback, useEffect, useState } from 'react' +import React from 'react' import VehicleAnimator from '../animator/vehicleAnimator' -import * as THREE from "three"; -import { NavMeshQuery } from '@recast-navigation/core'; -import { useNavMesh } from '../../../../../store/store'; -import { usePlayButtonStore } from '../../../../../store/usePlayButtonStore'; -import { useVehicleStore } from '../../../../../store/simulation/useVehicleStore'; -function VehicleInstance({ agvDetails }: any) { - const { navMesh } = useNavMesh(); - const { isPlaying } = usePlayButtonStore(); - const { setVehicleActive, setVehicleState } = useVehicleStore(); - const [currentPhase, setCurrentPhase] = useState<(string)>("stationed"); - const [path, setPath] = useState<[number, number, number][]>([]); +function VehicleInstance() { + return ( + <> - const computePath = useCallback((start: any, end: any) => { + - - try { - const navMeshQuery = new NavMeshQuery(navMesh); - const { path: segmentPath } = navMeshQuery.computePath(start, end); - return ( - segmentPath?.map( - ({ x, y, z }) => [x, y + 0.1, z] as [number, number, number] - ) || [] - ); - } catch { - return []; - } - }, [navMesh]); - - useEffect(() => { - // const pickupToDropPath = computePath(pickup, drop); - // const dropToPickupPath = computePath(drop, pickup); - - if (isPlaying) { - if (!agvDetails.isActive && agvDetails.state == "idle" && currentPhase == "stationed") { - const toPickupPath = computePath(new THREE.Vector3(agvDetails.position[0], agvDetails.position[1], agvDetails.position[2]), agvDetails.point.action.pickUpPoint); - setPath(toPickupPath) - setVehicleActive(agvDetails.modelUuid, true) - setVehicleState(agvDetails.modelUuid, "running") - setCurrentPhase("stationed-pickup") - // - } - } - }, [agvDetails, currentPhase, path, isPlaying]) - - function handleCallBack() { - if (currentPhase === "stationed-pickup") { - setVehicleActive(agvDetails.modelUuid, false) - setVehicleState(agvDetails.modelUuid, "idle") - setCurrentPhase("picking") - setPath([]) - } - } - - - return ( - <> - - - - - ) + + ) } export default VehicleInstance \ No newline at end of file diff --git a/app/src/modules/simulation/vehicle/instances/vehicleInstances.tsx b/app/src/modules/simulation/vehicle/instances/vehicleInstances.tsx index f3f1435..13e15b7 100644 --- a/app/src/modules/simulation/vehicle/instances/vehicleInstances.tsx +++ b/app/src/modules/simulation/vehicle/instances/vehicleInstances.tsx @@ -1,13 +1,11 @@ import React from 'react' import VehicleInstance from './instance/vehicleInstance' -function VehicleInstances({ vehicles }: any) { +function VehicleInstances() { return ( <> - {vehicles.map((val: any, i: any) => - - )} + ) diff --git a/app/src/modules/simulation/vehicle/vehicles.tsx b/app/src/modules/simulation/vehicle/vehicles.tsx index 9fb8b90..5d6681b 100644 --- a/app/src/modules/simulation/vehicle/vehicles.tsx +++ b/app/src/modules/simulation/vehicle/vehicles.tsx @@ -9,8 +9,8 @@ function Vehicles() { const vehicleStatusSample: VehicleStatus[] = [ { - modelUuid: "2c01ed76-359a-485b-83d4-052cfcdb9d89", - modelName: "AGV", + modelUuid: "veh-123", + modelName: "Autonomous Truck A1", position: [10, 0, 5], rotation: [0, 0, 0], state: "idle", @@ -18,7 +18,7 @@ function Vehicles() { speed: 2.5, point: { uuid: "point-789", - position: [93.42159216649789, 0, 23.790878603572857], + position: [0, 1, 0], rotation: [0, 0, 0], action: { actionUuid: "action-456", @@ -59,58 +59,9 @@ function Vehicles() { distanceTraveled: 0 }, { - modelUuid: "311130b9-4f2e-425a-b3b5-5039cb348806", - modelName: "AGV", - position: [95.69567023145055, 0, 33.18042399595448], - rotation: [0, 0, 0], - state: "idle", - type: "vehicle", - speed: 2.5, - point: { - uuid: "point-789", - position: [0, 1, 0], - rotation: [0, 0, 0], - action: { - actionUuid: "action-456", - actionName: "Deliver to Zone A", - actionType: "travel", - material: "crate", - unLoadDuration: 15, - loadCapacity: 5, - pickUpPoint: { x: 5, y: 0, z: 3 }, - unLoadPoint: { x: 20, y: 0, z: 10 }, - triggers: [ - { - triggerUuid: "trig-001", - triggerName: "Start Travel", - triggerType: "onStart", - delay: 0, - triggeredAsset: { - triggeredModel: { modelName: "ArmBot-X", modelUuid: "arm-001" }, - triggeredPoint: { pointName: "Pickup Arm Point", pointUuid: "arm-point-01" }, - triggeredAction: { actionName: "Grab Widget", actionUuid: "grab-001" } - } - }, - { - triggerUuid: "trig-002", - triggerName: "Complete Travel", - triggerType: "onComplete", - delay: 2, - triggeredAsset: null - } - ] - } - }, - productId: "prod-890", - isActive: false, - idleTime: 0, - activeTime: 0, - currentLoad: 0, - distanceTraveled: 0 - }, { - modelUuid: "fa54132c-8333-4832-becb-5281f5e11549", - modelName: "AGV", - position: [102.71483985219794, 0, 23.66321267938962], + modelUuid: "veh-123", + modelName: "Autonomous Truck A1", + position: [10, 0, 5], rotation: [0, 0, 0], state: "idle", type: "vehicle", @@ -163,7 +114,6 @@ function Vehicles() { useEffect(() => { addVehicle('123', vehicleStatusSample[0]); addVehicle('123', vehicleStatusSample[1]); - addVehicle('123', vehicleStatusSample[2]); }, []) useEffect(() => { @@ -174,7 +124,7 @@ function Vehicles() { return ( <> - + ) From a965a403eeede962d4b0914169c12b5232c273e2 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Wed, 23 Apr 2025 12:29:16 +0530 Subject: [PATCH 06/11] feat: Add robotic arm components and integrate IKInstance; refactor vehicle status sample type --- .../instances/animator/roboticArmAnimator.tsx | 9 +++++++++ .../armInstance/roboticArmInstance.tsx | 17 +++++++++++++++++ .../instances/ikInstance/ikInstance.tsx | 9 +++++++++ .../roboticArm/instances/ikInstances.tsx | 14 ++++++++++++++ .../instances/roboticArmInstances.tsx | 14 ++++++++++++++ .../simulation/roboticArm/roboticArm.tsx | 15 +++++++++++++++ .../modules/simulation/vehicle/vehicles.tsx | 18 +++--------------- 7 files changed, 81 insertions(+), 15 deletions(-) create mode 100644 app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx create mode 100644 app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx create mode 100644 app/src/modules/simulation/roboticArm/instances/ikInstance/ikInstance.tsx create mode 100644 app/src/modules/simulation/roboticArm/instances/ikInstances.tsx create mode 100644 app/src/modules/simulation/roboticArm/instances/roboticArmInstances.tsx create mode 100644 app/src/modules/simulation/roboticArm/roboticArm.tsx diff --git a/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx b/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx new file mode 100644 index 0000000..0cd4fe2 --- /dev/null +++ b/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx @@ -0,0 +1,9 @@ +import React from 'react' + +function RoboticArmAnimator() { + return ( + <> + ) +} + +export default RoboticArmAnimator; \ No newline at end of file diff --git a/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx new file mode 100644 index 0000000..2817906 --- /dev/null +++ b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx @@ -0,0 +1,17 @@ +import React from 'react' +import IKInstance from '../ikInstance/ikInstance'; +import RoboticArmAnimator from '../animator/roboticArmAnimator'; + +function RoboticArmInstance() { + return ( + <> + + + + + + + ) +} + +export default RoboticArmInstance; \ No newline at end of file diff --git a/app/src/modules/simulation/roboticArm/instances/ikInstance/ikInstance.tsx b/app/src/modules/simulation/roboticArm/instances/ikInstance/ikInstance.tsx new file mode 100644 index 0000000..52a8610 --- /dev/null +++ b/app/src/modules/simulation/roboticArm/instances/ikInstance/ikInstance.tsx @@ -0,0 +1,9 @@ +import React from 'react' + +function IKInstance() { + return ( + <> + ) +} + +export default IKInstance; \ No newline at end of file diff --git a/app/src/modules/simulation/roboticArm/instances/ikInstances.tsx b/app/src/modules/simulation/roboticArm/instances/ikInstances.tsx new file mode 100644 index 0000000..d44ddd2 --- /dev/null +++ b/app/src/modules/simulation/roboticArm/instances/ikInstances.tsx @@ -0,0 +1,14 @@ +import React from 'react' +import IKInstance from './ikInstance/ikInstance'; + +function IkInstances() { + return ( + <> + + + + + ) +} + +export default IkInstances; \ No newline at end of file diff --git a/app/src/modules/simulation/roboticArm/instances/roboticArmInstances.tsx b/app/src/modules/simulation/roboticArm/instances/roboticArmInstances.tsx new file mode 100644 index 0000000..6e8a70a --- /dev/null +++ b/app/src/modules/simulation/roboticArm/instances/roboticArmInstances.tsx @@ -0,0 +1,14 @@ +import React from 'react' +import RoboticArmInstance from './armInstance/roboticArmInstance'; + +function RoboticArmInstances() { + return ( + <> + + + + + ) +} + +export default RoboticArmInstances; \ No newline at end of file diff --git a/app/src/modules/simulation/roboticArm/roboticArm.tsx b/app/src/modules/simulation/roboticArm/roboticArm.tsx new file mode 100644 index 0000000..1270d93 --- /dev/null +++ b/app/src/modules/simulation/roboticArm/roboticArm.tsx @@ -0,0 +1,15 @@ +import React from 'react' +import RoboticArmInstances from './instances/roboticArmInstances'; +import IkInstances from './instances/ikInstances'; + +function RoboticArm() { + return ( + <> + + + + + ) +} + +export default RoboticArm; \ No newline at end of file diff --git a/app/src/modules/simulation/vehicle/vehicles.tsx b/app/src/modules/simulation/vehicle/vehicles.tsx index 5d6681b..3364717 100644 --- a/app/src/modules/simulation/vehicle/vehicles.tsx +++ b/app/src/modules/simulation/vehicle/vehicles.tsx @@ -7,7 +7,7 @@ function Vehicles() { const { vehicles, addVehicle } = useVehicleStore(); - const vehicleStatusSample: VehicleStatus[] = [ + const vehicleStatusSample: VehicleEventSchema[] = [ { modelUuid: "veh-123", modelName: "Autonomous Truck A1", @@ -50,13 +50,7 @@ function Vehicles() { } ] } - }, - productId: "prod-890", - isActive: false, - idleTime: 0, - activeTime: 0, - currentLoad: 0, - distanceTraveled: 0 + } }, { modelUuid: "veh-123", @@ -100,13 +94,7 @@ function Vehicles() { } ] } - }, - productId: "prod-890", - isActive: false, - idleTime: 0, - activeTime: 0, - currentLoad: 0, - distanceTraveled: 0 + } } ]; From 71effecb32e7b74af2c720e7630337f7e5b96181 Mon Sep 17 00:00:00 2001 From: Poovizhi99 Date: Wed, 23 Apr 2025 12:31:37 +0530 Subject: [PATCH 07/11] added useframe --- .../instances/animator/vehicleAnimator.tsx | 35 ++++++++++++++----- .../instances/instance/vehicleInstance.tsx | 2 +- 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx b/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx index db6bedb..137d679 100644 --- a/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx +++ b/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx @@ -10,29 +10,48 @@ interface VehicleAnimatorProps { function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid }: VehicleAnimatorProps) { - + const [progress, setProgress] = useState(0) const [currentPath, setCurrentPath] = useState<[number, number, number][]>([]); const { scene } = useThree(); useEffect(() => { if (currentPhase === 'stationed-pickup' && path.length > 0) { - - setCurrentPath(path); - } }, [currentPhase, path]) + useFrame((_, delta) => { + if (!path || path.length < 2) return; - useFrame(() => { - if (currentPath.length === 0) return; - const object = scene.getObjectByProperty("uuid", agvUuid); + const object = scene.getObjectByProperty("uuid", agvUuid) if (!object) return; + setProgress(prev => { + const next = prev + delta * 0.1; // speed + return next >= 1 ? 1 : next; + }); + + const totalSegments = path.length - 1; + const segmentIndex = Math.floor(progress * totalSegments); + const t = progress * totalSegments - segmentIndex; + + const start = path[segmentIndex]; + const end = path[segmentIndex + 1] || start; + + // Directly set position without creating a new Vector3 + object.position.x = start[0] + (end[0] - start[0]) * t; + object.position.y = start[1] + (end[1] - start[1]) * t; + object.position.z = start[2] + (end[2] - start[2]) * t; + }); + // useFrame(() => { + // if (currentPath.length === 0) return; + // const object = scene.getObjectByProperty("uuid", agvUuid); + // if (!object) return; - }) + + // }) return ( <> diff --git a/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx b/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx index e381311..646dabd 100644 --- a/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx +++ b/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx @@ -58,7 +58,7 @@ function VehicleInstance({ agvDetails }: any) { return ( <> - + ) From f8a6021b4eaba9de78cc704126889e7d9e0d3dde Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Wed, 23 Apr 2025 12:35:34 +0530 Subject: [PATCH 08/11] feat: Refactor VehicleInstance component to include path computation and state management --- .../instances/instance/vehicleInstance.tsx | 98 ++++++++++--------- 1 file changed, 54 insertions(+), 44 deletions(-) diff --git a/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx b/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx index 6b6bd78..bf767ec 100644 --- a/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx +++ b/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx @@ -1,56 +1,66 @@ -import React, { useEffect } from 'react' +import React, { useCallback, useEffect, useState } from 'react' import VehicleAnimator from '../animator/vehicleAnimator' +import * as THREE from "three"; import { NavMeshQuery } from '@recast-navigation/core'; +import { useNavMesh } from '../../../../../store/store'; +import { usePlayButtonStore } from '../../../../../store/usePlayButtonStore'; +import { useVehicleStore } from '../../../../../store/simulation/useVehicleStore'; -function VehicleInstance() { +function VehicleInstance({ agvDetails }: any) { + const { navMesh } = useNavMesh(); + const { isPlaying } = usePlayButtonStore(); + const { setVehicleActive, setVehicleState } = useVehicleStore(); + const [currentPhase, setCurrentPhase] = useState<(string)>("stationed"); + const [path, setPath] = useState<[number, number, number][]>([]); - useEffect(() => { - try { - const navMeshQuery = new NavMeshQuery(navMesh); - const { path: segmentPath } = navMeshQuery.computePath(start, end); - return ( - segmentPath?.map( - ({ x, y, z }) => [x, y + 0.1, z] as [number, number, number] - ) || [] - ); - } catch { - return []; + const computePath = useCallback((start: any, end: any) => { + + + try { + const navMeshQuery = new NavMeshQuery(navMesh); + const { path: segmentPath } = navMeshQuery.computePath(start, end); + return ( + segmentPath?.map( + ({ x, y, z }) => [x, y + 0.1, z] as [number, number, number] + ) || [] + ); + } catch { + return []; + } + }, [navMesh]); + + useEffect(() => { + + + if (isPlaying) { + if (!agvDetails.isActive && agvDetails.state == "idle" && currentPhase == "stationed") { + const toPickupPath = computePath(new THREE.Vector3(agvDetails.position[0], agvDetails.position[1], agvDetails.position[2]), agvDetails.point.action.pickUpPoint); + setPath(toPickupPath) + setVehicleActive(agvDetails.modelUuid, true) + setVehicleState(agvDetails.modelUuid, "running") + setCurrentPhase("stationed-pickup") + // + } + } + }, [agvDetails, currentPhase, path, isPlaying]) + + function handleCallBack() { + if (currentPhase === "stationed-pickup") { + setVehicleActive(agvDetails.modelUuid, false) + setVehicleState(agvDetails.modelUuid, "idle") + setCurrentPhase("picking") + setPath([]) + } } - }, [navMesh]); - - useEffect(() => { - // const pickupToDropPath = computePath(pickup, drop); - // const dropToPickupPath = computePath(drop, pickup); - - if (isPlaying) { - if (!agvDetails.isActive && agvDetails.state == "idle" && currentPhase == "stationed") { - const toPickupPath = computePath(new THREE.Vector3(agvDetails.position[0], agvDetails.position[1], agvDetails.position[2]), agvDetails.point.action.pickUpPoint); - setPath(toPickupPath) - setVehicleActive(agvDetails.modelUuid, true) - setVehicleState(agvDetails.modelUuid, "running") - setCurrentPhase("stationed-pickup") - // - } - } - }, [agvDetails, currentPhase, path, isPlaying]) - - function handleCallBack() { - if (currentPhase === "stationed-pickup") { - setVehicleActive(agvDetails.modelUuid, false) - setVehicleState(agvDetails.modelUuid, "idle") - setCurrentPhase("picking") - setPath([]) - } - } - return ( - <> + return ( + <> - + - - ) + + ) } export default VehicleInstance \ No newline at end of file From faed625c2ae1656dda15794c40615d21f97cf8e5 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Wed, 23 Apr 2025 13:03:27 +0530 Subject: [PATCH 09/11] feat: Update VehicleAnimator and VehicleInstances components to enhance path handling and integrate vehicle data --- .../vehicle/instances/animator/vehicleAnimator.tsx | 1 + .../simulation/vehicle/instances/vehicleInstances.tsx | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx b/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx index f3a4ed5..cf5fd81 100644 --- a/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx +++ b/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx @@ -21,6 +21,7 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid }: Vehicl } }, [currentPhase, path]) + useFrame((_, delta) => { if (!path || path.length < 2) return; diff --git a/app/src/modules/simulation/vehicle/instances/vehicleInstances.tsx b/app/src/modules/simulation/vehicle/instances/vehicleInstances.tsx index 13e15b7..0848883 100644 --- a/app/src/modules/simulation/vehicle/instances/vehicleInstances.tsx +++ b/app/src/modules/simulation/vehicle/instances/vehicleInstances.tsx @@ -1,11 +1,16 @@ import React from 'react' import VehicleInstance from './instance/vehicleInstance' +import { useVehicleStore } from '../../../../store/simulation/useVehicleStore'; function VehicleInstances() { + const { vehicles } = useVehicleStore(); + return ( <> - + {vehicles.map((val: any, i: any) => + + )} ) From 04f91585e65618ec95fc1a23a776124da1c291bf Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Wed, 23 Apr 2025 14:53:27 +0530 Subject: [PATCH 10/11] feat: Update simulation stores and types to enhance robotic arm and vehicle handling --- .../geomentries/assets/addAssetModel.ts | 4 +- .../builder/groups/floorItemsGroup.tsx | 4 +- app/src/store/simulation/useArmBotStore.ts | 39 +++++++++---------- app/src/store/simulation/useConveyorStore.ts | 7 ---- app/src/store/simulation/useMachineStore.ts | 7 ---- .../store/simulation/useStorageUnitStore.ts | 8 ---- app/src/store/simulation/useVehicleStore.ts | 16 ++++++-- app/src/types/simulationTypes.d.ts | 36 ++++++++++++++++- 8 files changed, 71 insertions(+), 50 deletions(-) diff --git a/app/src/modules/builder/geomentries/assets/addAssetModel.ts b/app/src/modules/builder/geomentries/assets/addAssetModel.ts index 5bdb558..193dd41 100644 --- a/app/src/modules/builder/geomentries/assets/addAssetModel.ts +++ b/app/src/modules/builder/geomentries/assets/addAssetModel.ts @@ -257,8 +257,8 @@ async function handleModelLoad( actionName: "Pick and Place", actionType: "pickAndPlace", process: { - startPoint: "start-point-uuid", - endPoint: "end-point-uuid" + startPoint: [0, 0, 0], + endPoint: [0, 0, 0] }, triggers: [] } diff --git a/app/src/modules/builder/groups/floorItemsGroup.tsx b/app/src/modules/builder/groups/floorItemsGroup.tsx index 23fa80d..2a3c2cc 100644 --- a/app/src/modules/builder/groups/floorItemsGroup.tsx +++ b/app/src/modules/builder/groups/floorItemsGroup.tsx @@ -16,11 +16,11 @@ import addAssetModel from "../geomentries/assets/addAssetModel"; import { getFloorAssets } from "../../../services/factoryBuilder/assest/floorAsset/getFloorItemsApi"; import useModuleStore from "../../../store/useModuleStore"; // import { retrieveGLTF } from "../../../utils/indexDB/idbUtils"; +import { useEventsStore } from "../../../store/simulation/useEventsStore"; + const assetManagerWorker = new Worker(new URL("../../../services/factoryBuilder/webWorkers/assetManagerWorker.js", import.meta.url)); const gltfLoaderWorker = new Worker(new URL("../../../services/factoryBuilder/webWorkers/gltfLoaderWorker.js", import.meta.url)); -import { useEventsStore } from "../../../store/simulation/useEventsStore"; - const FloorItemsGroup = ({ itemsGroup, hoveredDeletableFloorItem, AttachedObject, floorGroup, tempLoader, isTempLoader, plane, }: any) => { const state: Types.ThreeState = useThree(); const { raycaster, controls }: any = state; diff --git a/app/src/store/simulation/useArmBotStore.ts b/app/src/store/simulation/useArmBotStore.ts index 7dd4716..493a068 100644 --- a/app/src/store/simulation/useArmBotStore.ts +++ b/app/src/store/simulation/useArmBotStore.ts @@ -1,17 +1,6 @@ import { create } from 'zustand'; import { immer } from 'zustand/middleware/immer'; -interface ArmBotStatus extends RoboticArmEventSchema { - productId: string; - isActive: boolean; - idleTime: number; - activeTime: number; - currentAction?: { - actionUuid: string; - actionName: string; - }; -} - interface ArmBotStore { armBots: ArmBotStatus[]; @@ -22,9 +11,11 @@ interface ArmBotStore { updates: Partial> ) => void; - startAction: (modelUuid: string, actionUuid: string) => void; - completeAction: (modelUuid: string) => void; - cancelAction: (modelUuid: string) => void; + addCurrentAction: (modelUuid: string, actionUuid: string) => void; + removeCurrentAction: (modelUuid: string) => void; + + addAction: (modelUuid: string, action: RoboticArmPointSchema['actions'][number]) => void; + removeAction: (modelUuid: string, actionUuid: string) => void; setArmBotActive: (modelUuid: string, isActive: boolean) => void; @@ -71,7 +62,7 @@ export const useArmBotStore = create()( }); }, - startAction: (modelUuid, actionUuid) => { + addCurrentAction: (modelUuid, actionUuid) => { set((state) => { const armBot = state.armBots.find(a => a.modelUuid === modelUuid); if (armBot) { @@ -87,22 +78,30 @@ export const useArmBotStore = create()( }); }, - completeAction: (modelUuid) => { + removeCurrentAction: (modelUuid) => { set((state) => { const armBot = state.armBots.find(a => a.modelUuid === modelUuid); - if (armBot && armBot.currentAction) { + if (armBot) { armBot.currentAction = undefined; armBot.isActive = false; } }); }, - cancelAction: (modelUuid) => { + addAction: (modelUuid, action) => { set((state) => { const armBot = state.armBots.find(a => a.modelUuid === modelUuid); if (armBot) { - armBot.currentAction = undefined; - armBot.isActive = false; + armBot.point.actions.push(action); + } + }); + }, + + removeAction: (modelUuid, actionUuid) => { + set((state) => { + const armBot = state.armBots.find(a => a.modelUuid === modelUuid); + if (armBot) { + armBot.point.actions = armBot.point.actions.filter(a => a.actionUuid !== actionUuid); } }); }, diff --git a/app/src/store/simulation/useConveyorStore.ts b/app/src/store/simulation/useConveyorStore.ts index 059e76b..15dbf34 100644 --- a/app/src/store/simulation/useConveyorStore.ts +++ b/app/src/store/simulation/useConveyorStore.ts @@ -1,13 +1,6 @@ import { create } from 'zustand'; import { immer } from 'zustand/middleware/immer'; -interface ConveyorStatus extends ConveyorEventSchema { - productId: string; - isActive: boolean; - idleTime: number; - activeTime: number; -} - interface ConveyorStore { conveyors: ConveyorStatus[]; diff --git a/app/src/store/simulation/useMachineStore.ts b/app/src/store/simulation/useMachineStore.ts index 15997b9..cc927f7 100644 --- a/app/src/store/simulation/useMachineStore.ts +++ b/app/src/store/simulation/useMachineStore.ts @@ -1,13 +1,6 @@ import { create } from 'zustand'; import { immer } from 'zustand/middleware/immer'; -interface MachineStatus extends MachineEventSchema { - productId: string; - isActive: boolean; - idleTime: number; - activeTime: number; -} - interface MachineStore { machines: MachineStatus[]; diff --git a/app/src/store/simulation/useStorageUnitStore.ts b/app/src/store/simulation/useStorageUnitStore.ts index 04b4db0..d729708 100644 --- a/app/src/store/simulation/useStorageUnitStore.ts +++ b/app/src/store/simulation/useStorageUnitStore.ts @@ -1,14 +1,6 @@ import { create } from 'zustand'; import { immer } from 'zustand/middleware/immer'; -interface StorageUnitStatus extends StorageEventSchema { - productId: string; - isActive: boolean; - idleTime: number; - activeTime: number; - currentLoad: number; -} - interface StorageUnitStore { storageUnits: StorageUnitStatus[]; diff --git a/app/src/store/simulation/useVehicleStore.ts b/app/src/store/simulation/useVehicleStore.ts index 9f7ac50..ce28916 100644 --- a/app/src/store/simulation/useVehicleStore.ts +++ b/app/src/store/simulation/useVehicleStore.ts @@ -21,7 +21,8 @@ interface VehiclesStore { ) => void; setVehicleActive: (modelUuid: string, isActive: boolean) => void; - updateVehicleLoad: (modelUuid: string, load: number) => void; + incrementVehicleLoad: (modelUuid: string, incrementBy: number) => void; + decrementVehicleLoad: (modelUuid: string, decrementBy: number) => void; setVehicleState: (modelUuid: string, newState: VehicleStatus['state']) => void; incrementActiveTime: (modelUuid: string, incrementBy: number) => void; incrementIdleTime: (modelUuid: string, incrementBy: number) => void; @@ -74,11 +75,20 @@ export const useVehicleStore = create()( }); }, - updateVehicleLoad: (modelUuid, load) => { + incrementVehicleLoad: (modelUuid, incrementBy) => { set((state) => { const vehicle = state.vehicles.find(v => v.modelUuid === modelUuid); if (vehicle) { - vehicle.currentLoad = load; + vehicle.currentLoad += incrementBy; + } + }); + }, + + decrementVehicleLoad: (modelUuid, decrementBy) => { + set((state) => { + const vehicle = state.vehicles.find(v => v.modelUuid === modelUuid); + if (vehicle) { + vehicle.currentLoad = decrementBy; } }); }, diff --git a/app/src/types/simulationTypes.d.ts b/app/src/types/simulationTypes.d.ts index 2b3fc1e..7c2bd2c 100644 --- a/app/src/types/simulationTypes.d.ts +++ b/app/src/types/simulationTypes.d.ts @@ -59,7 +59,7 @@ interface RoboticArmPointSchema { actionUuid: string; actionName: string; actionType: "pickAndPlace"; - process: { startPoint: string; endPoint: string }; + process: { startPoint: [number, number, number]; endPoint: [number, number, number] }; triggers: TriggerSchema[]; }[]; } @@ -127,6 +127,32 @@ type productsSchema = { eventsData: EventsSchema[]; }[] + +interface ConveyorStatus extends ConveyorEventSchema { + productId: string; + isActive: boolean; + idleTime: number; + activeTime: number; +} + +interface MachineStatus extends MachineEventSchema { + productId: string; + isActive: boolean; + idleTime: number; + activeTime: number; +} + +interface ArmBotStatus extends RoboticArmEventSchema { + productId: string; + isActive: boolean; + idleTime: number; + activeTime: number; + currentAction?: { + actionUuid: string; + actionName: string; + }; +} + interface VehicleStatus extends VehicleEventSchema { productId: string; isActive: boolean; @@ -134,4 +160,12 @@ interface VehicleStatus extends VehicleEventSchema { activeTime: number; currentLoad: number; distanceTraveled: number; +} + +interface StorageUnitStatus extends StorageEventSchema { + productId: string; + isActive: boolean; + idleTime: number; + activeTime: number; + currentLoad: number; } \ No newline at end of file From 6f93fc36c27b0a576e4b222c09728e686d874dac Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Wed, 23 Apr 2025 15:29:51 +0530 Subject: [PATCH 11/11] feat: Add Conveyor and RoboticArm components to simulation and integrate MaterialInstances --- .../modules/simulation/conveyor/conveyor.tsx | 14 ++++++++++++++ .../conveyorInstance/conveyorInstance.tsx | 10 ++++++++++ .../conveyor/instances/conveyorInstances.tsx | 14 ++++++++++++++ .../instances/animator/materialAnimator.tsx | 9 +++++++++ .../instances/instance/materialInstance.tsx | 9 +++++++++ .../materials/instances/materialInstances.tsx | 17 +++++++++++++++++ .../modules/simulation/materials/materials.tsx | 14 ++++++++++++++ app/src/modules/simulation/simulation.tsx | 8 +++++++- 8 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 app/src/modules/simulation/conveyor/conveyor.tsx create mode 100644 app/src/modules/simulation/conveyor/instances/conveyorInstance/conveyorInstance.tsx create mode 100644 app/src/modules/simulation/conveyor/instances/conveyorInstances.tsx create mode 100644 app/src/modules/simulation/materials/instances/animator/materialAnimator.tsx create mode 100644 app/src/modules/simulation/materials/instances/instance/materialInstance.tsx create mode 100644 app/src/modules/simulation/materials/instances/materialInstances.tsx create mode 100644 app/src/modules/simulation/materials/materials.tsx diff --git a/app/src/modules/simulation/conveyor/conveyor.tsx b/app/src/modules/simulation/conveyor/conveyor.tsx new file mode 100644 index 0000000..bd21523 --- /dev/null +++ b/app/src/modules/simulation/conveyor/conveyor.tsx @@ -0,0 +1,14 @@ +import React from 'react' +import ConveyorInstances from './instances/conveyorInstances' + +function Conveyor() { + return ( + <> + + + + + ) +} + +export default Conveyor \ No newline at end of file diff --git a/app/src/modules/simulation/conveyor/instances/conveyorInstance/conveyorInstance.tsx b/app/src/modules/simulation/conveyor/instances/conveyorInstance/conveyorInstance.tsx new file mode 100644 index 0000000..9c9d612 --- /dev/null +++ b/app/src/modules/simulation/conveyor/instances/conveyorInstance/conveyorInstance.tsx @@ -0,0 +1,10 @@ +import React from 'react' + +function ConveyorInstance() { + return ( + <> + + ) +} + +export default ConveyorInstance \ No newline at end of file diff --git a/app/src/modules/simulation/conveyor/instances/conveyorInstances.tsx b/app/src/modules/simulation/conveyor/instances/conveyorInstances.tsx new file mode 100644 index 0000000..3f53784 --- /dev/null +++ b/app/src/modules/simulation/conveyor/instances/conveyorInstances.tsx @@ -0,0 +1,14 @@ +import React from 'react' +import ConveyorInstance from './conveyorInstance/conveyorInstance' + +function ConveyorInstances() { + return ( + <> + + + + + ) +} + +export default ConveyorInstances \ No newline at end of file diff --git a/app/src/modules/simulation/materials/instances/animator/materialAnimator.tsx b/app/src/modules/simulation/materials/instances/animator/materialAnimator.tsx new file mode 100644 index 0000000..1445e70 --- /dev/null +++ b/app/src/modules/simulation/materials/instances/animator/materialAnimator.tsx @@ -0,0 +1,9 @@ +import React from 'react' + +function MaterialAnimator() { + return ( + <> + ) +} + +export default MaterialAnimator \ No newline at end of file diff --git a/app/src/modules/simulation/materials/instances/instance/materialInstance.tsx b/app/src/modules/simulation/materials/instances/instance/materialInstance.tsx new file mode 100644 index 0000000..466e235 --- /dev/null +++ b/app/src/modules/simulation/materials/instances/instance/materialInstance.tsx @@ -0,0 +1,9 @@ +import React from 'react' + +function MaterialInstance() { + return ( + <> + ) +} + +export default MaterialInstance \ No newline at end of file diff --git a/app/src/modules/simulation/materials/instances/materialInstances.tsx b/app/src/modules/simulation/materials/instances/materialInstances.tsx new file mode 100644 index 0000000..519cba9 --- /dev/null +++ b/app/src/modules/simulation/materials/instances/materialInstances.tsx @@ -0,0 +1,17 @@ +import React from 'react' +import MaterialInstance from './instance/materialInstance' +import MaterialAnimator from './animator/materialAnimator' + +function MaterialInstances() { + return ( + <> + + + + + + + ) +} + +export default MaterialInstances \ No newline at end of file diff --git a/app/src/modules/simulation/materials/materials.tsx b/app/src/modules/simulation/materials/materials.tsx new file mode 100644 index 0000000..432d815 --- /dev/null +++ b/app/src/modules/simulation/materials/materials.tsx @@ -0,0 +1,14 @@ +import React from 'react' +import MaterialInstances from './instances/materialInstances' + +function Materials() { + return ( + <> + + + + + ) +} + +export default Materials \ No newline at end of file diff --git a/app/src/modules/simulation/simulation.tsx b/app/src/modules/simulation/simulation.tsx index 1be292e..b7bf36d 100644 --- a/app/src/modules/simulation/simulation.tsx +++ b/app/src/modules/simulation/simulation.tsx @@ -3,13 +3,15 @@ import { useEventsStore } from '../../store/simulation/useEventsStore'; import { useProductStore } from '../../store/simulation/useProductStore'; import Vehicles from './vehicle/vehicles'; import Points from './events/points/points'; +import Conveyor from './conveyor/conveyor'; +import RoboticArm from './roboticArm/roboticArm'; function Simulation() { const { events } = useEventsStore(); const { products } = useProductStore(); useEffect(() => { - console.log('events: ', events); + // console.log('events: ', events); }, [events]) useEffect(() => { @@ -23,6 +25,10 @@ function Simulation() { + + + + ) }