Merge remote-tracking branch 'origin/v2' into v2-ui
This commit is contained in:
commit
f340b052c1
|
@ -25,19 +25,8 @@ const avatarColors: string[] = [
|
||||||
export function getAvatarColor(index: number, name?: string): string {
|
export function getAvatarColor(index: number, name?: string): string {
|
||||||
// Check if the color is already stored in localStorage
|
// Check if the color is already stored in localStorage
|
||||||
const localStorageKey = "userAvatarColors";
|
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
|
// Check if local storage is available
|
||||||
if (isLocalStorageAvailable() && name) {
|
if (name) {
|
||||||
let userColors = JSON.parse(localStorage.getItem(localStorageKey) || "{}");
|
let userColors = JSON.parse(localStorage.getItem(localStorageKey) || "{}");
|
||||||
|
|
||||||
// Check if the user already has an assigned color
|
// Check if the user already has an assigned color
|
||||||
|
|
|
@ -184,24 +184,9 @@ async function handleModelLoad(
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!data || !data.points) return;
|
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") {
|
if (selectedItem.type === "Conveyor") {
|
||||||
const event: ConveyorEventSchema = {
|
const ConveyorEvent: ConveyorEventSchema = {
|
||||||
modelUuid: newFloorItem.modeluuid,
|
modelUuid: newFloorItem.modeluuid,
|
||||||
modelName: newFloorItem.modelname,
|
modelName: newFloorItem.modelname,
|
||||||
position: newFloorItem.position,
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,11 +18,9 @@ import useModuleStore from "../../../store/useModuleStore";
|
||||||
// import { retrieveGLTF } from "../../../utils/indexDB/idbUtils";
|
// import { retrieveGLTF } from "../../../utils/indexDB/idbUtils";
|
||||||
import { useEventsStore } from "../../../store/simulation/useEventsStore";
|
import { useEventsStore } from "../../../store/simulation/useEventsStore";
|
||||||
|
|
||||||
|
|
||||||
const assetManagerWorker = new Worker(new URL("../../../services/factoryBuilder/webWorkers/assetManagerWorker.js", import.meta.url));
|
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 gltfLoaderWorker = new Worker(new URL("../../../services/factoryBuilder/webWorkers/gltfLoaderWorker.js", import.meta.url));
|
||||||
|
|
||||||
|
|
||||||
const FloorItemsGroup = ({ itemsGroup, hoveredDeletableFloorItem, AttachedObject, floorGroup, tempLoader, isTempLoader, plane, }: any) => {
|
const FloorItemsGroup = ({ itemsGroup, hoveredDeletableFloorItem, AttachedObject, floorGroup, tempLoader, isTempLoader, plane, }: any) => {
|
||||||
const state: Types.ThreeState = useThree();
|
const state: Types.ThreeState = useThree();
|
||||||
const { raycaster, controls }: any = state;
|
const { raycaster, controls }: any = state;
|
||||||
|
|
|
@ -26,12 +26,9 @@ const MeasurementTool = () => {
|
||||||
);
|
);
|
||||||
const [coneSize, setConeSize] = useState({ radius: 0.2, height: 0.5 });
|
const [coneSize, setConeSize] = useState({ radius: 0.2, height: 0.5 });
|
||||||
|
|
||||||
const MIN_RADIUS = 0.001,
|
const MIN_RADIUS = 0.001, MAX_RADIUS = 0.1;
|
||||||
MAX_RADIUS = 0.1;
|
const MIN_CONE_RADIUS = 0.01, MAX_CONE_RADIUS = 0.4;
|
||||||
const MIN_CONE_RADIUS = 0.01,
|
const MIN_CONE_HEIGHT = 0.035, MAX_CONE_HEIGHT = 2.0;
|
||||||
MAX_CONE_RADIUS = 0.4;
|
|
||||||
const MIN_CONE_HEIGHT = 0.035,
|
|
||||||
MAX_CONE_HEIGHT = 2.0;
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const canvasElement = gl.domElement;
|
const canvasElement = gl.domElement;
|
||||||
|
@ -125,21 +122,9 @@ const MeasurementTool = () => {
|
||||||
const updateMeasurement = (start: THREE.Vector3, end: THREE.Vector3) => {
|
const updateMeasurement = (start: THREE.Vector3, end: THREE.Vector3) => {
|
||||||
const distance = start.distanceTo(end);
|
const distance = start.distanceTo(end);
|
||||||
|
|
||||||
const radius = THREE.MathUtils.clamp(
|
const radius = THREE.MathUtils.clamp(distance * 0.02, MIN_RADIUS, MAX_RADIUS);
|
||||||
distance * 0.02,
|
const coneRadius = THREE.MathUtils.clamp(distance * 0.05, MIN_CONE_RADIUS, MAX_CONE_RADIUS);
|
||||||
MIN_RADIUS,
|
const coneHeight = THREE.MathUtils.clamp(distance * 0.2, MIN_CONE_HEIGHT, MAX_CONE_HEIGHT);
|
||||||
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 });
|
setConeSize({ radius: coneRadius, height: coneHeight });
|
||||||
|
|
||||||
|
@ -180,7 +165,7 @@ const MeasurementTool = () => {
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (points.length === 2) {
|
if (points.length === 2) {
|
||||||
console.log(points[0].distanceTo(points[1]));
|
// console.log(points[0].distanceTo(points[1]));
|
||||||
}
|
}
|
||||||
}, [points]);
|
}, [points]);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
import React from 'react'
|
||||||
|
import ConveyorInstances from './instances/conveyorInstances'
|
||||||
|
|
||||||
|
function Conveyor() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
|
||||||
|
<ConveyorInstances />
|
||||||
|
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Conveyor
|
|
@ -0,0 +1,10 @@
|
||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
function ConveyorInstance() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ConveyorInstance
|
|
@ -0,0 +1,14 @@
|
||||||
|
import React from 'react'
|
||||||
|
import ConveyorInstance from './conveyorInstance/conveyorInstance'
|
||||||
|
|
||||||
|
function ConveyorInstances() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
|
||||||
|
<ConveyorInstance />
|
||||||
|
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ConveyorInstances
|
|
@ -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;
|
|
@ -0,0 +1,12 @@
|
||||||
|
import React from 'react'
|
||||||
|
import PointsCreator from './creator/pointsCreator'
|
||||||
|
|
||||||
|
function Points() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<PointsCreator />
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Points
|
|
@ -0,0 +1,9 @@
|
||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
function MaterialAnimator() {
|
||||||
|
return (
|
||||||
|
<></>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MaterialAnimator
|
|
@ -0,0 +1,9 @@
|
||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
function MaterialInstance() {
|
||||||
|
return (
|
||||||
|
<></>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MaterialInstance
|
|
@ -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
|
|
@ -0,0 +1,14 @@
|
||||||
|
import React from 'react'
|
||||||
|
import MaterialInstances from './instances/materialInstances'
|
||||||
|
|
||||||
|
function Materials() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
|
||||||
|
<MaterialInstances />
|
||||||
|
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Materials
|
|
@ -0,0 +1,9 @@
|
||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
function RoboticArmAnimator() {
|
||||||
|
return (
|
||||||
|
<></>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default RoboticArmAnimator;
|
|
@ -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;
|
|
@ -0,0 +1,9 @@
|
||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
function IKInstance() {
|
||||||
|
return (
|
||||||
|
<></>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default IKInstance;
|
|
@ -0,0 +1,14 @@
|
||||||
|
import React from 'react'
|
||||||
|
import IKInstance from './ikInstance/ikInstance';
|
||||||
|
|
||||||
|
function IkInstances() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
|
||||||
|
<IKInstance />
|
||||||
|
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default IkInstances;
|
|
@ -0,0 +1,14 @@
|
||||||
|
import React from 'react'
|
||||||
|
import RoboticArmInstance from './armInstance/roboticArmInstance';
|
||||||
|
|
||||||
|
function RoboticArmInstances() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
|
||||||
|
<RoboticArmInstance />
|
||||||
|
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default RoboticArmInstances;
|
|
@ -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;
|
|
@ -1,21 +1,34 @@
|
||||||
import React, { useEffect } from 'react';
|
import React, { useEffect } from 'react';
|
||||||
import { useEventsStore } from '../../store/simulation/useEventsStore';
|
import { useEventsStore } from '../../store/simulation/useEventsStore';
|
||||||
import { useProductStore } from '../../store/simulation/useProductStore';
|
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() {
|
function Simulation() {
|
||||||
const { events } = useEventsStore();
|
const { events } = useEventsStore();
|
||||||
const { products } = useProductStore();
|
const { products } = useProductStore();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log('events: ', events);
|
// console.log('events: ', events);
|
||||||
}, [events])
|
}, [events])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log('products: ', products);
|
// console.log('products: ', products);
|
||||||
}, [products])
|
}, [products])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
||||||
|
<Points />
|
||||||
|
|
||||||
|
<Vehicles />
|
||||||
|
|
||||||
|
<RoboticArm />
|
||||||
|
|
||||||
|
<Conveyor />
|
||||||
|
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 (
|
return (
|
||||||
<div>VehicleAnimator</div>
|
<>
|
||||||
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,63 @@
|
||||||
import React from 'react'
|
import React, { useCallback, useEffect, useState } from 'react'
|
||||||
import VehicleAnimator from '../animator/vehicleAnimator'
|
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 (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
||||||
<VehicleAnimator />
|
<VehicleAnimator path={path} handleCallBack={handleCallBack} currentPhase={currentPhase} agvUuid={agvDetails?.modelUuid} />
|
||||||
|
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,11 +1,16 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import VehicleInstance from './instance/vehicleInstance'
|
import VehicleInstance from './instance/vehicleInstance'
|
||||||
|
import { useVehicleStore } from '../../../../store/simulation/useVehicleStore';
|
||||||
|
|
||||||
function VehicleInstances() {
|
function VehicleInstances() {
|
||||||
|
const { vehicles } = useVehicleStore();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
||||||
<VehicleInstance />
|
{vehicles.map((val: any, i: any) =>
|
||||||
|
<VehicleInstance agvDetails={val} key={i} />
|
||||||
|
)}
|
||||||
|
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,14 +0,0 @@
|
||||||
import React from 'react'
|
|
||||||
import VehicleInstances from './instances/vehicleInstances';
|
|
||||||
|
|
||||||
function Vehicle() {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
|
|
||||||
<VehicleInstances />
|
|
||||||
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Vehicle
|
|
|
@ -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;
|
|
@ -44,7 +44,7 @@ export default function Dropped3dWidgets() {
|
||||||
const rotationStartRef = useRef<[number, number, number]>([0, 0, 0]);
|
const rotationStartRef = useRef<[number, number, number]>([0, 0, 0]);
|
||||||
const mouseStartRef = useRef<{ x: number; y: number }>({ x: 0, y: 0 });
|
const mouseStartRef = useRef<{ x: number; y: number }>({ x: 0, y: 0 });
|
||||||
const { setSelectedChartId } = useWidgetStore();
|
const { setSelectedChartId } = useWidgetStore();
|
||||||
const { measurements, duration} = useChartStore();
|
const { measurements, duration } = useChartStore();
|
||||||
let [floorPlanesVertical, setFloorPlanesVertical] = useState(
|
let [floorPlanesVertical, setFloorPlanesVertical] = useState(
|
||||||
new THREE.Plane(new THREE.Vector3(0, 1, 0))
|
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("Roof") &&
|
||||||
!intersect.object.name.includes("agv-collider") &&
|
!intersect.object.name.includes("agv-collider") &&
|
||||||
!intersect.object.name.includes("MeasurementReference") &&
|
!intersect.object.name.includes("MeasurementReference") &&
|
||||||
!intersect.object.userData.isPathObject &&
|
|
||||||
!(intersect.object.type === "GridHelper")
|
!(intersect.object.type === "GridHelper")
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -154,7 +153,6 @@ export default function Dropped3dWidgets() {
|
||||||
!intersect.object.name.includes("Roof") &&
|
!intersect.object.name.includes("Roof") &&
|
||||||
!intersect.object.name.includes("agv-collider") &&
|
!intersect.object.name.includes("agv-collider") &&
|
||||||
!intersect.object.name.includes("MeasurementReference") &&
|
!intersect.object.name.includes("MeasurementReference") &&
|
||||||
!intersect.object.userData.isPathObject &&
|
|
||||||
!(intersect.object.type === "GridHelper")
|
!(intersect.object.type === "GridHelper")
|
||||||
);
|
);
|
||||||
// Update widget's position in memory
|
// Update widget's position in memory
|
||||||
|
@ -258,7 +256,7 @@ export default function Dropped3dWidgets() {
|
||||||
widgetToDuplicate.position[2] + 0.5,
|
widgetToDuplicate.position[2] + 0.5,
|
||||||
],
|
],
|
||||||
rotation: widgetToDuplicate.rotation || [0, 0, 0],
|
rotation: widgetToDuplicate.rotation || [0, 0, 0],
|
||||||
Data:{
|
Data: {
|
||||||
measurements: measurements,
|
measurements: measurements,
|
||||||
duration: duration
|
duration: duration
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,17 +1,6 @@
|
||||||
import { create } from 'zustand';
|
import { create } from 'zustand';
|
||||||
import { immer } from 'zustand/middleware/immer';
|
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 {
|
interface ArmBotStore {
|
||||||
armBots: ArmBotStatus[];
|
armBots: ArmBotStatus[];
|
||||||
|
|
||||||
|
@ -22,9 +11,11 @@ interface ArmBotStore {
|
||||||
updates: Partial<Omit<ArmBotStatus, 'modelUuid' | 'productId'>>
|
updates: Partial<Omit<ArmBotStatus, 'modelUuid' | 'productId'>>
|
||||||
) => void;
|
) => void;
|
||||||
|
|
||||||
startAction: (modelUuid: string, actionUuid: string) => void;
|
addCurrentAction: (modelUuid: string, actionUuid: string) => void;
|
||||||
completeAction: (modelUuid: string) => void;
|
removeCurrentAction: (modelUuid: string) => void;
|
||||||
cancelAction: (modelUuid: string) => void;
|
|
||||||
|
addAction: (modelUuid: string, action: RoboticArmPointSchema['actions'][number]) => void;
|
||||||
|
removeAction: (modelUuid: string, actionUuid: string) => void;
|
||||||
|
|
||||||
setArmBotActive: (modelUuid: string, isActive: boolean) => void;
|
setArmBotActive: (modelUuid: string, isActive: boolean) => void;
|
||||||
|
|
||||||
|
@ -71,7 +62,7 @@ export const useArmBotStore = create<ArmBotStore>()(
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
startAction: (modelUuid, actionUuid) => {
|
addCurrentAction: (modelUuid, actionUuid) => {
|
||||||
set((state) => {
|
set((state) => {
|
||||||
const armBot = state.armBots.find(a => a.modelUuid === modelUuid);
|
const armBot = state.armBots.find(a => a.modelUuid === modelUuid);
|
||||||
if (armBot) {
|
if (armBot) {
|
||||||
|
@ -87,22 +78,30 @@ export const useArmBotStore = create<ArmBotStore>()(
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
completeAction: (modelUuid) => {
|
removeCurrentAction: (modelUuid) => {
|
||||||
set((state) => {
|
set((state) => {
|
||||||
const armBot = state.armBots.find(a => a.modelUuid === modelUuid);
|
const armBot = state.armBots.find(a => a.modelUuid === modelUuid);
|
||||||
if (armBot && armBot.currentAction) {
|
if (armBot) {
|
||||||
armBot.currentAction = undefined;
|
armBot.currentAction = undefined;
|
||||||
armBot.isActive = false;
|
armBot.isActive = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
cancelAction: (modelUuid) => {
|
addAction: (modelUuid, action) => {
|
||||||
set((state) => {
|
set((state) => {
|
||||||
const armBot = state.armBots.find(a => a.modelUuid === modelUuid);
|
const armBot = state.armBots.find(a => a.modelUuid === modelUuid);
|
||||||
if (armBot) {
|
if (armBot) {
|
||||||
armBot.currentAction = undefined;
|
armBot.point.actions.push(action);
|
||||||
armBot.isActive = false;
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,13 +1,6 @@
|
||||||
import { create } from 'zustand';
|
import { create } from 'zustand';
|
||||||
import { immer } from 'zustand/middleware/immer';
|
import { immer } from 'zustand/middleware/immer';
|
||||||
|
|
||||||
interface ConveyorStatus extends ConveyorEventSchema {
|
|
||||||
productId: string;
|
|
||||||
isActive: boolean;
|
|
||||||
idleTime: number;
|
|
||||||
activeTime: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ConveyorStore {
|
interface ConveyorStore {
|
||||||
conveyors: ConveyorStatus[];
|
conveyors: ConveyorStatus[];
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,6 @@
|
||||||
import { create } from 'zustand';
|
import { create } from 'zustand';
|
||||||
import { immer } from 'zustand/middleware/immer';
|
import { immer } from 'zustand/middleware/immer';
|
||||||
|
|
||||||
interface MachineStatus extends MachineEventSchema {
|
|
||||||
productId: string;
|
|
||||||
isActive: boolean;
|
|
||||||
idleTime: number;
|
|
||||||
activeTime: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface MachineStore {
|
interface MachineStore {
|
||||||
machines: MachineStatus[];
|
machines: MachineStatus[];
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,6 @@
|
||||||
import { create } from 'zustand';
|
import { create } from 'zustand';
|
||||||
import { immer } from 'zustand/middleware/immer';
|
import { immer } from 'zustand/middleware/immer';
|
||||||
|
|
||||||
interface StorageUnitStatus extends StorageEventSchema {
|
|
||||||
productId: string;
|
|
||||||
isActive: boolean;
|
|
||||||
idleTime: number;
|
|
||||||
activeTime: number;
|
|
||||||
currentLoad: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface StorageUnitStore {
|
interface StorageUnitStore {
|
||||||
storageUnits: StorageUnitStatus[];
|
storageUnits: StorageUnitStatus[];
|
||||||
|
|
||||||
|
@ -25,7 +17,7 @@ interface StorageUnitStore {
|
||||||
setStorageUnitState: (modelUuid: string, newState: StorageUnitStatus['state']) => void;
|
setStorageUnitState: (modelUuid: string, newState: StorageUnitStatus['state']) => void;
|
||||||
|
|
||||||
// Load updates
|
// Load updates
|
||||||
updateStorageUnitLoad: (modelUuid: string, load: number) => void;
|
updateStorageUnitLoad: (modelUuid: string, incrementBy: number) => void;
|
||||||
|
|
||||||
// Time tracking
|
// Time tracking
|
||||||
incrementActiveTime: (modelUuid: string, incrementBy: number) => void;
|
incrementActiveTime: (modelUuid: string, incrementBy: number) => void;
|
||||||
|
@ -95,11 +87,11 @@ export const useStorageUnitStore = create<StorageUnitStore>()(
|
||||||
},
|
},
|
||||||
|
|
||||||
// Load updates
|
// Load updates
|
||||||
updateStorageUnitLoad: (modelUuid, load) => {
|
updateStorageUnitLoad: (modelUuid, incrementBy) => {
|
||||||
set((state) => {
|
set((state) => {
|
||||||
const unit = state.storageUnits.find(s => s.modelUuid === modelUuid);
|
const unit = state.storageUnits.find(s => s.modelUuid === modelUuid);
|
||||||
if (unit) {
|
if (unit) {
|
||||||
unit.currentLoad = load;
|
unit.currentLoad += incrementBy;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
|
@ -21,7 +21,8 @@ interface VehiclesStore {
|
||||||
) => void;
|
) => void;
|
||||||
|
|
||||||
setVehicleActive: (modelUuid: string, isActive: boolean) => 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;
|
setVehicleState: (modelUuid: string, newState: VehicleStatus['state']) => void;
|
||||||
incrementActiveTime: (modelUuid: string, incrementBy: number) => void;
|
incrementActiveTime: (modelUuid: string, incrementBy: number) => void;
|
||||||
incrementIdleTime: (modelUuid: string, incrementBy: number) => void;
|
incrementIdleTime: (modelUuid: string, incrementBy: number) => void;
|
||||||
|
@ -30,7 +31,6 @@ interface VehiclesStore {
|
||||||
getVehiclesByProduct: (productId: string) => VehicleStatus[];
|
getVehiclesByProduct: (productId: string) => VehicleStatus[];
|
||||||
getVehiclesByState: (state: string) => VehicleStatus[];
|
getVehiclesByState: (state: string) => VehicleStatus[];
|
||||||
getActiveVehicles: () => VehicleStatus[];
|
getActiveVehicles: () => VehicleStatus[];
|
||||||
getIdleVehicles: () => VehicleStatus[];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useVehicleStore = create<VehiclesStore>()(
|
export const useVehicleStore = create<VehiclesStore>()(
|
||||||
|
@ -75,11 +75,20 @@ export const useVehicleStore = create<VehiclesStore>()(
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
updateVehicleLoad: (modelUuid, load) => {
|
incrementVehicleLoad: (modelUuid, incrementBy) => {
|
||||||
set((state) => {
|
set((state) => {
|
||||||
const vehicle = state.vehicles.find(v => v.modelUuid === modelUuid);
|
const vehicle = state.vehicles.find(v => v.modelUuid === modelUuid);
|
||||||
if (vehicle) {
|
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: () => {
|
getActiveVehicles: () => {
|
||||||
return get().vehicles.filter(v => v.isActive);
|
return get().vehicles.filter(v => v.isActive);
|
||||||
},
|
|
||||||
|
|
||||||
getIdleVehicles: () => {
|
|
||||||
return get().vehicles.filter(v => !v.isActive && v.currentLoad > 0);
|
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
);
|
);
|
||||||
|
|
|
@ -42,7 +42,7 @@ interface VehiclePointSchema {
|
||||||
actionUuid: string;
|
actionUuid: string;
|
||||||
actionName: string;
|
actionName: string;
|
||||||
actionType: "travel";
|
actionType: "travel";
|
||||||
material: string;
|
material: string | null;
|
||||||
unLoadDuration: number;
|
unLoadDuration: number;
|
||||||
loadCapacity: number;
|
loadCapacity: number;
|
||||||
pickUpPoint: { x: number; y: number, z: number } | null;
|
pickUpPoint: { x: number; y: number, z: number } | null;
|
||||||
|
@ -59,7 +59,7 @@ interface RoboticArmPointSchema {
|
||||||
actionUuid: string;
|
actionUuid: string;
|
||||||
actionName: string;
|
actionName: string;
|
||||||
actionType: "pickAndPlace";
|
actionType: "pickAndPlace";
|
||||||
process: { startPoint: string; endPoint: string };
|
process: { startPoint: [number, number, number]; endPoint: [number, number, number] };
|
||||||
triggers: TriggerSchema[];
|
triggers: TriggerSchema[];
|
||||||
}[];
|
}[];
|
||||||
}
|
}
|
||||||
|
@ -119,10 +119,53 @@ interface StorageEventSchema extends AssetEventSchema {
|
||||||
point: StoragePointSchema;
|
point: StoragePointSchema;
|
||||||
}
|
}
|
||||||
|
|
||||||
type EventsSchema = ConveyorEventSchema | VehicleEventSchema | RoboticArmEventSchema | MachineEventSchema | StorageEventSchema | [];
|
type EventsSchema = ConveyorEventSchema | VehicleEventSchema | RoboticArmEventSchema | MachineEventSchema | StorageEventSchema;
|
||||||
|
|
||||||
type productsSchema = {
|
type productsSchema = {
|
||||||
productName: string;
|
productName: string;
|
||||||
productId: string;
|
productId: string;
|
||||||
eventsData: EventsSchema[];
|
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;
|
||||||
|
}
|
Loading…
Reference in New Issue