Merge remote-tracking branch 'origin/v2' into v2-ui

This commit is contained in:
Vishnu 2025-04-23 17:16:14 +05:30
commit f340b052c1
32 changed files with 969 additions and 356 deletions

View File

@ -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

View File

@ -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: [0, 0, 0],
endPoint: [0, 0, 0]
},
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);
}
}

View File

@ -18,11 +18,9 @@ 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));
const FloorItemsGroup = ({ itemsGroup, hoveredDeletableFloorItem, AttachedObject, floorGroup, tempLoader, isTempLoader, plane, }: any) => {
const state: Types.ThreeState = useThree();
const { raycaster, controls }: any = state;

View File

@ -26,12 +26,9 @@ const MeasurementTool = () => {
);
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;
@ -125,21 +122,9 @@ const MeasurementTool = () => {
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
);
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 });
@ -180,7 +165,7 @@ const MeasurementTool = () => {
useEffect(() => {
if (points.length === 2) {
console.log(points[0].distanceTo(points[1]));
// console.log(points[0].distanceTo(points[1]));
}
}, [points]);

View File

@ -0,0 +1,14 @@
import React from 'react'
import ConveyorInstances from './instances/conveyorInstances'
function Conveyor() {
return (
<>
<ConveyorInstances />
</>
)
}
export default Conveyor

View File

@ -0,0 +1,10 @@
import React from 'react'
function ConveyorInstance() {
return (
<>
</>
)
}
export default ConveyorInstance

View File

@ -0,0 +1,14 @@
import React from 'react'
import ConveyorInstance from './conveyorInstance/conveyorInstance'
function ConveyorInstances() {
return (
<>
<ConveyorInstance />
</>
)
}
export default ConveyorInstances

View File

@ -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<any>(null);
const [transformMode, setTransformMode] = useState<"translate" | "rotate" | null>(null);
const [selectedPoint, setSelectedPoint] = useState<THREE.Mesh | null>(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' &&
<>
<group name='EventPointsGroup' >
{events.map((event, i) => {
if (event.type === 'transfer') {
return (
<group key={i} position={new THREE.Vector3(...event.position)}>
{event.points.map((point, j) => (
<mesh
uuid={point.uuid}
ref={(el) => (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 }}
>
<sphereGeometry args={[0.1, 16, 16]} />
<meshStandardMaterial color="orange" />
</mesh>
))}
</group>
);
} else if (event.type === 'vehicle') {
return (
<group key={i} position={new THREE.Vector3(...event.position)}>
<mesh
uuid={event.point.uuid}
ref={(el) => (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 }}
>
<sphereGeometry args={[0.1, 16, 16]} />
<meshStandardMaterial color="blue" />
</mesh>
</group>
);
} else if (event.type === 'roboticArm') {
return (
<group key={i} position={new THREE.Vector3(...event.position)}>
<mesh
uuid={event.point.uuid}
ref={(el) => (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 }}
>
<sphereGeometry args={[0.1, 16, 16]} />
<meshStandardMaterial color="green" />
</mesh>
</group>
);
} else if (event.type === 'machine') {
return (
<group key={i} position={new THREE.Vector3(...event.position)}>
<mesh
uuid={event.point.uuid}
ref={(el) => (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 }}
>
<sphereGeometry args={[0.1, 16, 16]} />
<meshStandardMaterial color="purple" />
</mesh>
</group>
);
} else {
return null;
}
})}
</group>
{(selectedPoint && transformMode) &&
<TransformControls ref={transformRef} object={selectedPoint} mode={transformMode} onMouseUp={(e) => { updatePointToState(selectedPoint) }} />
}
</>
}
</>
);
}
export default PointsCreator;

View File

@ -0,0 +1,12 @@
import React from 'react'
import PointsCreator from './creator/pointsCreator'
function Points() {
return (
<>
<PointsCreator />
</>
)
}
export default Points

View File

@ -0,0 +1,9 @@
import React from 'react'
function MaterialAnimator() {
return (
<></>
)
}
export default MaterialAnimator

View File

@ -0,0 +1,9 @@
import React from 'react'
function MaterialInstance() {
return (
<></>
)
}
export default MaterialInstance

View File

@ -0,0 +1,17 @@
import React from 'react'
import MaterialInstance from './instance/materialInstance'
import MaterialAnimator from './animator/materialAnimator'
function MaterialInstances() {
return (
<>
<MaterialInstance />
<MaterialAnimator />
</>
)
}
export default MaterialInstances

View File

@ -0,0 +1,14 @@
import React from 'react'
import MaterialInstances from './instances/materialInstances'
function Materials() {
return (
<>
<MaterialInstances />
</>
)
}
export default Materials

View File

@ -0,0 +1,9 @@
import React from 'react'
function RoboticArmAnimator() {
return (
<></>
)
}
export default RoboticArmAnimator;

View File

@ -0,0 +1,17 @@
import React from 'react'
import IKInstance from '../ikInstance/ikInstance';
import RoboticArmAnimator from '../animator/roboticArmAnimator';
function RoboticArmInstance() {
return (
<>
<IKInstance />
<RoboticArmAnimator />
</>
)
}
export default RoboticArmInstance;

View File

@ -0,0 +1,9 @@
import React from 'react'
function IKInstance() {
return (
<></>
)
}
export default IKInstance;

View File

@ -0,0 +1,14 @@
import React from 'react'
import IKInstance from './ikInstance/ikInstance';
function IkInstances() {
return (
<>
<IKInstance />
</>
)
}
export default IkInstances;

View File

@ -0,0 +1,14 @@
import React from 'react'
import RoboticArmInstance from './armInstance/roboticArmInstance';
function RoboticArmInstances() {
return (
<>
<RoboticArmInstance />
</>
)
}
export default RoboticArmInstances;

View File

@ -0,0 +1,15 @@
import React from 'react'
import RoboticArmInstances from './instances/roboticArmInstances';
import IkInstances from './instances/ikInstances';
function RoboticArm() {
return (
<>
<RoboticArmInstances />
</>
)
}
export default RoboticArm;

View File

@ -1,21 +1,34 @@
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';
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(() => {
console.log('products: ', products);
// console.log('products: ', products);
}, [products])
return (
<>
<Points />
<Vehicles />
<RoboticArm />
<Conveyor />
</>
)
}

View File

@ -1,8 +1,61 @@
import React from 'react'
import { useEffect, useState } from 'react'
import { useFrame, useThree } from '@react-three/fiber';
function VehicleAnimator() {
interface VehicleAnimatorProps {
path: [number, number, number][];
handleCallBack: () => void;
currentPhase: string;
agvUuid: number
}
function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid }: VehicleAnimatorProps) {
const [progress, setProgress] = useState<number>(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;
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 (
<div>VehicleAnimator</div>
<>
</>
)
}

View File

@ -1,11 +1,63 @@
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) {
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(() => {
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([])
}
}
function VehicleInstance() {
return (
<>
<VehicleAnimator />
<VehicleAnimator path={path} handleCallBack={handleCallBack} currentPhase={currentPhase} agvUuid={agvDetails?.modelUuid} />
</>
)

View File

@ -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 (
<>
<VehicleInstance />
{vehicles.map((val: any, i: any) =>
<VehicleInstance agvDetails={val} key={i} />
)}
</>
)

View File

@ -1,14 +0,0 @@
import React from 'react'
import VehicleInstances from './instances/vehicleInstances';
function Vehicle() {
return (
<>
<VehicleInstances />
</>
)
}
export default Vehicle

View File

@ -0,0 +1,121 @@
import React, { useEffect } from 'react'
import VehicleInstances from './instances/vehicleInstances';
import { useVehicleStore } from '../../../store/simulation/useVehicleStore';
function Vehicles() {
const { vehicles, addVehicle } = useVehicleStore();
const vehicleStatusSample: VehicleEventSchema[] = [
{
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
}
]
}
}
},
{
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
}
]
}
}
}
];
useEffect(() => {
addVehicle('123', vehicleStatusSample[0]);
addVehicle('123', vehicleStatusSample[1]);
}, [])
useEffect(() => {
// console.log('vehicles: ', vehicles);
}, [vehicles])
return (
<>
<VehicleInstances />
</>
)
}
export default Vehicles;

View File

@ -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

View File

@ -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<Omit<ArmBotStatus, 'modelUuid' | 'productId'>>
) => 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<ArmBotStore>()(
});
},
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<ArmBotStore>()(
});
},
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);
}
});
},

View File

@ -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[];

View File

@ -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[];

View File

@ -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[];
@ -25,7 +17,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 +87,11 @@ export const useStorageUnitStore = create<StorageUnitStore>()(
},
// 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;
}
});
},

View File

@ -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;
@ -30,7 +31,6 @@ interface VehiclesStore {
getVehiclesByProduct: (productId: string) => VehicleStatus[];
getVehiclesByState: (state: string) => VehicleStatus[];
getActiveVehicles: () => VehicleStatus[];
getIdleVehicles: () => VehicleStatus[];
}
export const useVehicleStore = create<VehiclesStore>()(
@ -75,11 +75,20 @@ export const useVehicleStore = create<VehiclesStore>()(
});
},
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;
}
});
},
@ -125,10 +134,6 @@ export const useVehicleStore = create<VehiclesStore>()(
getActiveVehicles: () => {
return get().vehicles.filter(v => v.isActive);
},
getIdleVehicles: () => {
return get().vehicles.filter(v => !v.isActive && v.currentLoad > 0);
}
}))
);

View File

@ -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;
@ -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[];
}[];
}
@ -119,10 +119,53 @@ interface StorageEventSchema extends AssetEventSchema {
point: StoragePointSchema;
}
type EventsSchema = ConveyorEventSchema | VehicleEventSchema | RoboticArmEventSchema | MachineEventSchema | StorageEventSchema | [];
type EventsSchema = ConveyorEventSchema | VehicleEventSchema | RoboticArmEventSchema | MachineEventSchema | StorageEventSchema;
type productsSchema = {
productName: string;
productId: string;
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;
idleTime: number;
activeTime: number;
currentLoad: number;
distanceTraveled: number;
}
interface StorageUnitStatus extends StorageEventSchema {
productId: string;
isActive: boolean;
idleTime: number;
activeTime: number;
currentLoad: number;
}