v2 #80
|
@ -28,16 +28,6 @@ function RoboticArmMechanics() {
|
||||||
selectedEventData.data.modelUuid,
|
selectedEventData.data.modelUuid,
|
||||||
selectedEventData.selectedPoint
|
selectedEventData.selectedPoint
|
||||||
) as RoboticArmPointSchema | undefined;
|
) as RoboticArmPointSchema | undefined;
|
||||||
const action = getActionByUuid(selectedProduct.productId, selectedAction.actionId) as RoboticArmPointSchema["actions"][0] | undefined;
|
|
||||||
if (action) {
|
|
||||||
if (point?.actions) {
|
|
||||||
setSelectedPointData(point);
|
|
||||||
if (point.actions.length > 0 && action) {
|
|
||||||
setActiveOption(action.actionType as "default" | "pickAndPlace");
|
|
||||||
setSelectedAction(selectedAction.actionId, selectedAction.actionName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (point?.actions) {
|
if (point?.actions) {
|
||||||
setSelectedPointData(point);
|
setSelectedPointData(point);
|
||||||
if (point.actions.length > 0) {
|
if (point.actions.length > 0) {
|
||||||
|
@ -45,7 +35,6 @@ function RoboticArmMechanics() {
|
||||||
setSelectedAction(point.actions[0].actionUuid, point.actions[0].actionName);
|
setSelectedAction(point.actions[0].actionUuid, point.actions[0].actionName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
clearSelectedAction();
|
clearSelectedAction();
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,6 +38,14 @@ const SimulationPlayer: React.FC = () => {
|
||||||
const { isReset, setReset } = useResetButtonStore();
|
const { isReset, setReset } = useResetButtonStore();
|
||||||
const { subModule } = useSubModuleStore();
|
const { subModule } = useSubModuleStore();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isReset) {
|
||||||
|
setTimeout(()=>{
|
||||||
|
setReset(false);
|
||||||
|
},0)
|
||||||
|
}
|
||||||
|
}, [isReset])
|
||||||
|
|
||||||
// Button functions
|
// Button functions
|
||||||
const handleReset = () => {
|
const handleReset = () => {
|
||||||
setReset(true);
|
setReset(true);
|
||||||
|
|
|
@ -0,0 +1,105 @@
|
||||||
|
import { useCallback, useEffect, useRef } from "react";
|
||||||
|
import { useFrame } from "@react-three/fiber";
|
||||||
|
import { usePlayButtonStore, usePauseButtonStore, useResetButtonStore } from "../../../../../store/usePlayButtonStore";
|
||||||
|
import { useMaterialStore } from "../../../../../store/simulation/useMaterialStore";
|
||||||
|
|
||||||
|
interface DelayInstance {
|
||||||
|
delayEndTime: number;
|
||||||
|
materialId?: string;
|
||||||
|
action: ConveyorAction;
|
||||||
|
isPaused: boolean;
|
||||||
|
remainingTime: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useDelayHandler() {
|
||||||
|
const { isPlaying } = usePlayButtonStore();
|
||||||
|
const { isPaused } = usePauseButtonStore();
|
||||||
|
const { isReset } = useResetButtonStore();
|
||||||
|
const { setIsPaused } = useMaterialStore();
|
||||||
|
const activeDelays = useRef<Map<string, DelayInstance>>(new Map());
|
||||||
|
|
||||||
|
const cleanupDelay = useCallback(() => {
|
||||||
|
activeDelays.current.clear();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isReset) {
|
||||||
|
cleanupDelay();
|
||||||
|
}
|
||||||
|
}, [isReset, cleanupDelay]);
|
||||||
|
|
||||||
|
const delayLogStatus = (materialUuid: string, status: string) => {
|
||||||
|
// console.log(`${materialUuid}, ${status}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const currentTime = performance.now();
|
||||||
|
|
||||||
|
activeDelays.current.forEach((delay) => {
|
||||||
|
if (isPaused && !delay.isPaused) {
|
||||||
|
delay.remainingTime = Math.max(0, delay.delayEndTime - currentTime);
|
||||||
|
delay.isPaused = true;
|
||||||
|
} else if (!isPaused && delay.isPaused) {
|
||||||
|
delay.delayEndTime = currentTime + delay.remainingTime;
|
||||||
|
delay.isPaused = false;
|
||||||
|
delay.remainingTime = 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, [isPaused]);
|
||||||
|
|
||||||
|
useFrame(() => {
|
||||||
|
if (!isPlaying || isPaused) return;
|
||||||
|
|
||||||
|
const currentTime = performance.now();
|
||||||
|
const completedDelays: string[] = [];
|
||||||
|
|
||||||
|
activeDelays.current.forEach((delay, key) => {
|
||||||
|
if (!delay.isPaused && currentTime >= delay.delayEndTime && delay.materialId) {
|
||||||
|
delayLogStatus(delay.materialId, `Delay completed}`);
|
||||||
|
setIsPaused(delay.materialId, false);
|
||||||
|
completedDelays.push(key);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
completedDelays.forEach(key => {
|
||||||
|
activeDelays.current.delete(key);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleDelay = useCallback((action: ConveyorAction, materialId?: string) => {
|
||||||
|
if (!action || action.actionType !== 'delay' || !isPlaying || !materialId) return;
|
||||||
|
|
||||||
|
const delayMs = (action.delay || 0) * 1000;
|
||||||
|
if (delayMs <= 0) return;
|
||||||
|
|
||||||
|
const key = materialId ? `${materialId}-${action.actionUuid}` : action.actionUuid;
|
||||||
|
|
||||||
|
// If this material already has a delay, cancel it
|
||||||
|
if (activeDelays.current.has(key)) {
|
||||||
|
activeDelays.current.delete(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
activeDelays.current.set(key, {
|
||||||
|
delayEndTime: performance.now() + delayMs,
|
||||||
|
materialId,
|
||||||
|
action,
|
||||||
|
isPaused: false,
|
||||||
|
remainingTime: 0
|
||||||
|
});
|
||||||
|
|
||||||
|
delayLogStatus(materialId, `Started ${delayMs * 1000}s delay`);
|
||||||
|
setIsPaused(materialId, true);
|
||||||
|
|
||||||
|
}, [isPlaying]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
return () => {
|
||||||
|
cleanupDelay();
|
||||||
|
};
|
||||||
|
}, [cleanupDelay]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
handleDelay,
|
||||||
|
cleanupDelay
|
||||||
|
};
|
||||||
|
}
|
|
@ -5,6 +5,7 @@ import { useMaterialStore } from "../../../../../store/simulation/useMaterialSto
|
||||||
import { useProductStore } from "../../../../../store/simulation/useProductStore";
|
import { useProductStore } from "../../../../../store/simulation/useProductStore";
|
||||||
import { useSelectedProduct } from "../../../../../store/simulation/useSimulationStore";
|
import { useSelectedProduct } from "../../../../../store/simulation/useSimulationStore";
|
||||||
import { usePlayButtonStore, useAnimationPlaySpeed, usePauseButtonStore, useResetButtonStore } from "../../../../../store/usePlayButtonStore";
|
import { usePlayButtonStore, useAnimationPlaySpeed, usePauseButtonStore, useResetButtonStore } from "../../../../../store/usePlayButtonStore";
|
||||||
|
import { useConveyorStore } from "../../../../../store/simulation/useConveyorStore";
|
||||||
|
|
||||||
interface SpawnInstance {
|
interface SpawnInstance {
|
||||||
lastSpawnTime: number | null;
|
lastSpawnTime: number | null;
|
||||||
|
@ -23,6 +24,7 @@ interface SpawnInstance {
|
||||||
|
|
||||||
export function useSpawnHandler() {
|
export function useSpawnHandler() {
|
||||||
const { addMaterial } = useMaterialStore();
|
const { addMaterial } = useMaterialStore();
|
||||||
|
const { getConveyorById } = useConveyorStore();
|
||||||
const { getModelUuidByActionUuid, getPointUuidByActionUuid } = useProductStore();
|
const { getModelUuidByActionUuid, getPointUuidByActionUuid } = useProductStore();
|
||||||
const { isPlaying } = usePlayButtonStore();
|
const { isPlaying } = usePlayButtonStore();
|
||||||
const { isPaused } = usePauseButtonStore();
|
const { isPaused } = usePauseButtonStore();
|
||||||
|
@ -57,11 +59,12 @@ export function useSpawnHandler() {
|
||||||
materialType: materialType,
|
materialType: materialType,
|
||||||
isActive: false,
|
isActive: false,
|
||||||
isVisible: true,
|
isVisible: true,
|
||||||
|
isPaused: false,
|
||||||
isRendered: true,
|
isRendered: true,
|
||||||
current: {
|
current: {
|
||||||
modelUuid: modelUuid,
|
modelUuid: modelUuid,
|
||||||
pointUuid: pointUuid,
|
pointUuid: pointUuid,
|
||||||
actionUuid: action?.actionUuid || ''
|
actionUuid: action.actionUuid
|
||||||
},
|
},
|
||||||
weight: 1,
|
weight: 1,
|
||||||
cost: 1
|
cost: 1
|
||||||
|
@ -74,7 +77,6 @@ export function useSpawnHandler() {
|
||||||
newMaterial.next = {
|
newMaterial.next = {
|
||||||
modelUuid: action.triggers[0].triggeredAsset?.triggeredModel.modelUuid,
|
modelUuid: action.triggers[0].triggeredAsset?.triggeredModel.modelUuid,
|
||||||
pointUuid: action.triggers[0].triggeredAsset?.triggeredPoint?.pointUuid,
|
pointUuid: action.triggers[0].triggeredAsset?.triggeredPoint?.pointUuid,
|
||||||
actionUuid: action.triggers[0].triggeredAsset?.triggeredAction?.actionUuid
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,6 +84,15 @@ export function useSpawnHandler() {
|
||||||
return newMaterial;
|
return newMaterial;
|
||||||
}, [addMaterial, getModelUuidByActionUuid, getPointUuidByActionUuid, selectedProduct.productId]);
|
}, [addMaterial, getModelUuidByActionUuid, getPointUuidByActionUuid, selectedProduct.productId]);
|
||||||
|
|
||||||
|
|
||||||
|
const getConveyorPausedState = useCallback((action: ConveyorAction) => {
|
||||||
|
const modelUuid = getModelUuidByActionUuid(selectedProduct.productId, action.actionUuid);
|
||||||
|
if (!modelUuid) return false;
|
||||||
|
|
||||||
|
const conveyor = getConveyorById(modelUuid);
|
||||||
|
return conveyor?.isPaused ?? false;
|
||||||
|
}, [getConveyorById, getModelUuidByActionUuid, selectedProduct.productId]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const currentTime = performance.now();
|
const currentTime = performance.now();
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
import { useCallback } from "react";
|
||||||
|
import { useMaterialStore } from "../../../../../store/simulation/useMaterialStore";
|
||||||
|
import { useProductStore } from "../../../../../store/simulation/useProductStore";
|
||||||
|
import { useSelectedProduct } from "../../../../../store/simulation/useSimulationStore";
|
||||||
|
import { usePlayButtonStore } from "../../../../../store/usePlayButtonStore";
|
||||||
|
|
||||||
|
export function useSwapHandler() {
|
||||||
|
const { addMaterial, getMaterialById, setMaterial } = useMaterialStore();
|
||||||
|
const { getPointUuidByActionUuid } = useProductStore();
|
||||||
|
const { selectedProduct } = useSelectedProduct();
|
||||||
|
const { isPlaying } = usePlayButtonStore();
|
||||||
|
|
||||||
|
const swapLogStatus = (materialUuid: string, status: string) => {
|
||||||
|
// console.log(`${materialUuid}, ${status}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSwap = useCallback((action: ConveyorAction, materialId?: string) => {
|
||||||
|
if (!action || action.actionType !== 'swap' || !isPlaying || !materialId) return;
|
||||||
|
|
||||||
|
const { material: newMaterialType } = action;
|
||||||
|
const material = getMaterialById(materialId);
|
||||||
|
if (!material) return;
|
||||||
|
|
||||||
|
setMaterial(material.materialId, newMaterialType);
|
||||||
|
swapLogStatus(material.materialId, `Swapped to ${newMaterialType}`);
|
||||||
|
|
||||||
|
}, [addMaterial, getMaterialById, getPointUuidByActionUuid, isPlaying, setMaterial, selectedProduct.productId]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
handleSwap,
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,32 +1,33 @@
|
||||||
import { useEffect, useCallback, useRef } from "react";
|
import { useEffect, useCallback } from "react";
|
||||||
import { useSpawnHandler } from "./actionHandler/useSpawnHandler";
|
import { useSpawnHandler } from "./actionHandler/useSpawnHandler";
|
||||||
|
import { useSwapHandler } from "./actionHandler/useSwapHandler";
|
||||||
|
import { useDelayHandler } from "./actionHandler/useDelayHandler";
|
||||||
|
|
||||||
export function useConveyorActions() {
|
export function useConveyorActions() {
|
||||||
const { handleSpawn, clearCurrentSpawn } = useSpawnHandler();
|
const { handleSpawn, clearCurrentSpawn } = useSpawnHandler();
|
||||||
|
const { handleSwap } = useSwapHandler();
|
||||||
|
const { handleDelay, cleanupDelay } = useDelayHandler();
|
||||||
|
|
||||||
const handleDefaultAction = useCallback((action: ConveyorAction) => {
|
const handleDefaultAction = useCallback((action: ConveyorAction) => {
|
||||||
console.log('action: ', action);
|
|
||||||
console.log(`Default conveyor action ${action.actionUuid}`);
|
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const handleSpawnAction = useCallback((action: ConveyorAction) => {
|
const handleSpawnAction = useCallback((action: ConveyorAction) => {
|
||||||
handleSpawn(action);
|
handleSpawn(action);
|
||||||
}, [handleSpawn]);
|
}, [handleSpawn]);
|
||||||
|
|
||||||
const handleSwapAction = useCallback((action: ConveyorAction) => {
|
const handleSwapAction = useCallback((action: ConveyorAction, materialId?: string) => {
|
||||||
console.log(`Swapping to material ${action.material}`);
|
handleSwap(action, materialId);
|
||||||
}, []);
|
}, [handleSwap]);
|
||||||
|
|
||||||
const handleDelayAction = useCallback((action: ConveyorAction) => {
|
const handleDelayAction = useCallback((action: ConveyorAction, materialId?: string) => {
|
||||||
const delayMs = (action.delay || 0) * 1000;
|
handleDelay(action, materialId);
|
||||||
console.log(`Delaying for ${delayMs}ms`);
|
}, [handleDelay]);
|
||||||
}, []);
|
|
||||||
|
|
||||||
const handleDespawnAction = useCallback((action: ConveyorAction) => {
|
const handleDespawnAction = useCallback((action: ConveyorAction) => {
|
||||||
console.log(`Despawning material`);
|
console.log(`Despawning material`);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const handleConveyorAction = useCallback((action: ConveyorAction) => {
|
const handleConveyorAction = useCallback((action: ConveyorAction, materialId?: string) => {
|
||||||
if (!action) return;
|
if (!action) return;
|
||||||
|
|
||||||
switch (action.actionType) {
|
switch (action.actionType) {
|
||||||
|
@ -37,10 +38,10 @@ export function useConveyorActions() {
|
||||||
handleSpawnAction(action);
|
handleSpawnAction(action);
|
||||||
break;
|
break;
|
||||||
case 'swap':
|
case 'swap':
|
||||||
handleSwapAction(action);
|
handleSwapAction(action, materialId);
|
||||||
break;
|
break;
|
||||||
case 'delay':
|
case 'delay':
|
||||||
handleDelayAction(action);
|
handleDelayAction(action, materialId);
|
||||||
break;
|
break;
|
||||||
case 'despawn':
|
case 'despawn':
|
||||||
handleDespawnAction(action);
|
handleDespawnAction(action);
|
||||||
|
@ -52,7 +53,8 @@ export function useConveyorActions() {
|
||||||
|
|
||||||
const cleanup = useCallback(() => {
|
const cleanup = useCallback(() => {
|
||||||
clearCurrentSpawn();
|
clearCurrentSpawn();
|
||||||
}, [clearCurrentSpawn]);
|
cleanupDelay();
|
||||||
|
}, [clearCurrentSpawn, cleanupDelay]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
return () => {
|
return () => {
|
||||||
|
|
|
@ -15,13 +15,13 @@ export function useActionHandler() {
|
||||||
const { handleMachineAction, cleanup: cleanupMachine } = useMachineActions();
|
const { handleMachineAction, cleanup: cleanupMachine } = useMachineActions();
|
||||||
const { handleStorageAction, cleanup: cleanupStorage } = useStorageActions();
|
const { handleStorageAction, cleanup: cleanupStorage } = useStorageActions();
|
||||||
|
|
||||||
const handleAction = useCallback((action: Action) => {
|
const handleAction = useCallback((action: Action, materialId?: string) => {
|
||||||
if (!action) return;
|
if (!action) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
switch (action.actionType) {
|
switch (action.actionType) {
|
||||||
case 'default': case 'spawn': case 'swap': case 'delay': case 'despawn':
|
case 'default': case 'spawn': case 'swap': case 'delay': case 'despawn':
|
||||||
handleConveyorAction(action as ConveyorAction);
|
handleConveyorAction(action as ConveyorAction, materialId as string);
|
||||||
break;
|
break;
|
||||||
case 'travel':
|
case 'travel':
|
||||||
handleVehicleAction(action as VehicleAction);
|
handleVehicleAction(action as VehicleAction);
|
||||||
|
|
|
@ -1,6 +1,33 @@
|
||||||
import React from 'react'
|
import React, { useEffect } from 'react'
|
||||||
|
import { useMaterialStore } from '../../../../../store/simulation/useMaterialStore';
|
||||||
|
import { useConveyorStore } from '../../../../../store/simulation/useConveyorStore';
|
||||||
|
import { useResetButtonStore } from '../../../../../store/usePlayButtonStore';
|
||||||
|
|
||||||
|
function ConveyorInstance({ conveyor }: { conveyor: ConveyorStatus }) {
|
||||||
|
const { materials, getMaterialsByCurrentModelUuid } = useMaterialStore();
|
||||||
|
const { isReset } = useResetButtonStore();
|
||||||
|
|
||||||
|
const { setConveyorPaused } = useConveyorStore();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const conveyorMaterials = getMaterialsByCurrentModelUuid(conveyor.modelUuid);
|
||||||
|
if (conveyorMaterials && conveyorMaterials?.length > 0) {
|
||||||
|
|
||||||
|
const hasPausedMaterials = conveyorMaterials.some(material => material.isPaused);
|
||||||
|
|
||||||
|
if (hasPausedMaterials) {
|
||||||
|
setConveyorPaused(conveyor.modelUuid, true);
|
||||||
|
} else {
|
||||||
|
setConveyorPaused(conveyor.modelUuid, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}, [materials, conveyor.modelUuid, getMaterialsByCurrentModelUuid, setConveyorPaused, isReset]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// console.log('conveyor: ', conveyor);
|
||||||
|
}, [conveyor])
|
||||||
|
|
||||||
function ConveyorInstance() {
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -1,11 +1,17 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import ConveyorInstance from './conveyorInstance/conveyorInstance'
|
import ConveyorInstance from './conveyorInstance/conveyorInstance'
|
||||||
|
import { useConveyorStore } from '../../../../store/simulation/useConveyorStore'
|
||||||
|
|
||||||
function ConveyorInstances() {
|
function ConveyorInstances() {
|
||||||
|
|
||||||
|
const { conveyors } = useConveyorStore();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
||||||
<ConveyorInstance />
|
{conveyors.map((conveyor: ConveyorStatus) =>
|
||||||
|
<ConveyorInstance conveyor={conveyor} key={conveyor.modelUuid} />
|
||||||
|
)}
|
||||||
|
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|
|
@ -2,6 +2,7 @@ import React, { useEffect, useState, useRef } from 'react';
|
||||||
import * as THREE from 'three';
|
import * as THREE from 'three';
|
||||||
import { useFrame, useThree } from '@react-three/fiber';
|
import { useFrame, useThree } from '@react-three/fiber';
|
||||||
import { usePauseButtonStore, usePlayButtonStore } from '../../../../../store/usePlayButtonStore';
|
import { usePauseButtonStore, usePlayButtonStore } from '../../../../../store/usePlayButtonStore';
|
||||||
|
import { useConveyorStore } from '../../../../../store/simulation/useConveyorStore';
|
||||||
|
|
||||||
interface MaterialAnimatorProps {
|
interface MaterialAnimatorProps {
|
||||||
matRef: React.RefObject<THREE.Mesh>;
|
matRef: React.RefObject<THREE.Mesh>;
|
||||||
|
@ -19,6 +20,7 @@ function MaterialAnimator({
|
||||||
const { scene } = useThree();
|
const { scene } = useThree();
|
||||||
const [targetPosition, setTargetPosition] = useState<THREE.Vector3 | null>(null);
|
const [targetPosition, setTargetPosition] = useState<THREE.Vector3 | null>(null);
|
||||||
const [isAnimating, setIsAnimating] = useState(false);
|
const [isAnimating, setIsAnimating] = useState(false);
|
||||||
|
const { getConveyorById } = useConveyorStore();
|
||||||
const animationState = useRef({
|
const animationState = useRef({
|
||||||
startTime: 0,
|
startTime: 0,
|
||||||
startPosition: new THREE.Vector3(),
|
startPosition: new THREE.Vector3(),
|
||||||
|
@ -29,7 +31,10 @@ function MaterialAnimator({
|
||||||
});
|
});
|
||||||
|
|
||||||
const { isPlaying } = usePlayButtonStore();
|
const { isPlaying } = usePlayButtonStore();
|
||||||
const { isPaused } = usePauseButtonStore();
|
const { isPaused: isGlobalPaused } = usePauseButtonStore();
|
||||||
|
|
||||||
|
const conveyor = getConveyorById(material.current.modelUuid);
|
||||||
|
const shouldPause = isGlobalPaused || material.isPaused || conveyor?.isPaused;
|
||||||
|
|
||||||
const getWorldPosition = (uuid: string): THREE.Vector3 | null => {
|
const getWorldPosition = (uuid: string): THREE.Vector3 | null => {
|
||||||
const obj = scene.getObjectByProperty('uuid', uuid);
|
const obj = scene.getObjectByProperty('uuid', uuid);
|
||||||
|
@ -39,7 +44,6 @@ function MaterialAnimator({
|
||||||
return position;
|
return position;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Handle target position changes and play state
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isPlaying || !material.next?.pointUuid) {
|
if (!isPlaying || !material.next?.pointUuid) {
|
||||||
setIsAnimating(false);
|
setIsAnimating(false);
|
||||||
|
@ -58,22 +62,21 @@ function MaterialAnimator({
|
||||||
}
|
}
|
||||||
}, [material.next?.pointUuid, isPlaying]);
|
}, [material.next?.pointUuid, isPlaying]);
|
||||||
|
|
||||||
// Handle pause/unpause
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isPaused) {
|
if (shouldPause) {
|
||||||
|
// Pause the animation
|
||||||
animationState.current.isPaused = true;
|
animationState.current.isPaused = true;
|
||||||
setIsAnimating(false);
|
setIsAnimating(false);
|
||||||
// Record the time when paused
|
|
||||||
animationState.current.pausedTime = performance.now() - animationState.current.startTime;
|
animationState.current.pausedTime = performance.now() - animationState.current.startTime;
|
||||||
} else {
|
} else {
|
||||||
|
// Resume the animation
|
||||||
animationState.current.isPaused = false;
|
animationState.current.isPaused = false;
|
||||||
if (isPlaying && targetPosition && !isAnimating) {
|
if (isPlaying && targetPosition && !isAnimating) {
|
||||||
// Resume from where we left off
|
|
||||||
animationState.current.startTime = performance.now() - animationState.current.pausedTime;
|
animationState.current.startTime = performance.now() - animationState.current.pausedTime;
|
||||||
setIsAnimating(true);
|
setIsAnimating(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [isPaused]);
|
}, [shouldPause, isPlaying]);
|
||||||
|
|
||||||
useFrame(() => {
|
useFrame(() => {
|
||||||
if (!matRef.current || !targetPosition || !isAnimating || animationState.current.isPaused || !isPlaying) {
|
if (!matRef.current || !targetPosition || !isAnimating || animationState.current.isPaused || !isPlaying) {
|
||||||
|
@ -81,7 +84,6 @@ function MaterialAnimator({
|
||||||
}
|
}
|
||||||
|
|
||||||
const currentTime = performance.now();
|
const currentTime = performance.now();
|
||||||
// Calculate elapsed time since animation start, minus any paused time
|
|
||||||
const elapsed = (currentTime - animationState.current.startTime) / 1000;
|
const elapsed = (currentTime - animationState.current.startTime) / 1000;
|
||||||
const progress = Math.min(1, (currentSpeed * elapsed) / animationState.current.totalDistance);
|
const progress = Math.min(1, (currentSpeed * elapsed) / animationState.current.totalDistance);
|
||||||
|
|
||||||
|
@ -95,6 +97,14 @@ function MaterialAnimator({
|
||||||
matRef.current.position.copy(targetPosition);
|
matRef.current.position.copy(targetPosition);
|
||||||
setIsAnimating(false);
|
setIsAnimating(false);
|
||||||
onAnimationComplete?.();
|
onAnimationComplete?.();
|
||||||
|
animationState.current = {
|
||||||
|
startTime: 0,
|
||||||
|
startPosition: new THREE.Vector3(),
|
||||||
|
totalDistance: 0,
|
||||||
|
pausedTime: 0,
|
||||||
|
isPaused: false,
|
||||||
|
lastFrameTime: 0
|
||||||
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ import { useTriggerHandler } from '../../../triggers/triggerHandler/useTriggerHa
|
||||||
function MaterialInstance({ material }: { material: MaterialSchema }) {
|
function MaterialInstance({ material }: { material: MaterialSchema }) {
|
||||||
const matRef: any = useRef();
|
const matRef: any = useRef();
|
||||||
const { scene } = useThree();
|
const { scene } = useThree();
|
||||||
const { getModelUuidByPointUuid, getPointByUuid, getEventByModelUuid, getActionByUuid } = useProductStore();
|
const { getModelUuidByPointUuid, getPointByUuid, getEventByModelUuid, getActionByUuid, getTriggerByUuid, getActionByPointUuid } = useProductStore();
|
||||||
const { selectedProduct } = useSelectedProduct();
|
const { selectedProduct } = useSelectedProduct();
|
||||||
const { speed } = useAnimationPlaySpeed();
|
const { speed } = useAnimationPlaySpeed();
|
||||||
const { triggerPointActions } = useTriggerHandler();
|
const { triggerPointActions } = useTriggerHandler();
|
||||||
|
@ -39,12 +39,12 @@ function MaterialInstance({ material }: { material: MaterialSchema }) {
|
||||||
|
|
||||||
const point = getPointByUuid(selectedProduct.productId, modelUuid, material.current.pointUuid);
|
const point = getPointByUuid(selectedProduct.productId, modelUuid, material.current.pointUuid);
|
||||||
if (!point) {
|
if (!point) {
|
||||||
return { position: new THREE.Vector3(0, 0, 0), rotation: new THREE.Vector3(0, 0, 0), currentSpeed: 1 };
|
return { position: new THREE.Vector3(0, 0, 0), rotation: new THREE.Vector3(0, 0, 0), currentSpeed: currentSpeed || 1 };
|
||||||
}
|
}
|
||||||
|
|
||||||
const position = getWorldPositionFromScene(point.uuid);
|
const position = getWorldPositionFromScene(point.uuid);
|
||||||
if (position) {
|
if (position) {
|
||||||
return { position: position, rotation: new THREE.Vector3(0, 0, 0), currentSpeed: 1 };
|
return { position: position, rotation: new THREE.Vector3(0, 0, 0), currentSpeed: currentSpeed || 1 };
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -54,6 +54,7 @@ function MaterialInstance({ material }: { material: MaterialSchema }) {
|
||||||
};
|
};
|
||||||
}, [material, getPointByUuid]);
|
}, [material, getPointByUuid]);
|
||||||
|
|
||||||
|
|
||||||
function getCurrentSpeed(productId: string, modelUuid: string) {
|
function getCurrentSpeed(productId: string, modelUuid: string) {
|
||||||
const event = getEventByModelUuid(productId, modelUuid)
|
const event = getEventByModelUuid(productId, modelUuid)
|
||||||
if (event) {
|
if (event) {
|
||||||
|
@ -84,13 +85,45 @@ function MaterialInstance({ material }: { material: MaterialSchema }) {
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// console.log('material: ', material);
|
// console.log('material: ', material);
|
||||||
|
if (material.current && material.next) {
|
||||||
|
// console.log('current: ', material.current.pointUuid);
|
||||||
|
// console.log('next: ', material.next.pointUuid);
|
||||||
|
}
|
||||||
}, [material])
|
}, [material])
|
||||||
|
|
||||||
const callTrigger = () => {
|
const callTrigger = () => {
|
||||||
const action = getActionByUuid(selectedProduct.productId, material.current.actionUuid)
|
if (!material.next) return;
|
||||||
|
const fromModel = getEventByModelUuid(selectedProduct.productId, material.next.modelUuid);
|
||||||
|
if (!fromModel) return;
|
||||||
|
const fromPoint = getPointByUuid(selectedProduct.productId, fromModel.modelUuid, material.next.pointUuid);
|
||||||
|
if (!fromPoint) return;
|
||||||
|
|
||||||
|
if (fromModel.type === 'transfer') {
|
||||||
|
const toModel = getEventByModelUuid(selectedProduct.productId, material.next.modelUuid);
|
||||||
|
if (!toModel) return;
|
||||||
|
if (toModel.type === 'transfer') {
|
||||||
|
const action = getActionByPointUuid(selectedProduct.productId, material.next.pointUuid);
|
||||||
if (action) {
|
if (action) {
|
||||||
triggerPointActions(action);
|
triggerPointActions(action, material.materialId);
|
||||||
}
|
}
|
||||||
|
} else if (toModel?.type === 'vehicle') {
|
||||||
|
// Transfer to Vehicle
|
||||||
|
|
||||||
|
} else if (toModel?.type === 'machine') {
|
||||||
|
// Transfer to Machine
|
||||||
|
|
||||||
|
} else if (toModel?.type === 'roboticArm') {
|
||||||
|
// Transfer to Robotic Arm
|
||||||
|
|
||||||
|
} else if (toModel?.type === 'storageUnit') {
|
||||||
|
// Transfer to Storage Unit
|
||||||
|
}
|
||||||
|
} else if (fromModel.type === 'vehicle') {
|
||||||
|
} else if (fromModel.type === 'machine') {
|
||||||
|
} else if (fromModel.type === 'roboticArm') {
|
||||||
|
} else if (fromModel.type === 'storageUnit') {
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -32,7 +32,7 @@ export function MaterialModel({ materialType, matRef, ...props }: ModelProps) {
|
||||||
<group ref={matRef} {...props} dispose={null}>
|
<group ref={matRef} {...props} dispose={null}>
|
||||||
<primitive
|
<primitive
|
||||||
object={cloned}
|
object={cloned}
|
||||||
scale={[0.25, 0.25, 0.25]}
|
scale={[0.4, 0.4, 0.4]}
|
||||||
/>
|
/>
|
||||||
</group>
|
</group>
|
||||||
);
|
);
|
||||||
|
|
|
@ -6,7 +6,7 @@ function MaterialInstances() {
|
||||||
const { materials } = useMaterialStore();
|
const { materials } = useMaterialStore();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log('materials: ', materials);
|
// console.log('materials: ', materials);
|
||||||
}, [materials])
|
}, [materials])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -7,12 +7,14 @@ import { upsertProductOrEventApi } from '../../../services/simulation/UpsertProd
|
||||||
import { getAllProductsApi } from '../../../services/simulation/getallProductsApi';
|
import { getAllProductsApi } from '../../../services/simulation/getallProductsApi';
|
||||||
import { useVehicleStore } from '../../../store/simulation/useVehicleStore';
|
import { useVehicleStore } from '../../../store/simulation/useVehicleStore';
|
||||||
import { useArmBotStore } from '../../../store/simulation/useArmBotStore';
|
import { useArmBotStore } from '../../../store/simulation/useArmBotStore';
|
||||||
|
import { useConveyorStore } from '../../../store/simulation/useConveyorStore';
|
||||||
|
|
||||||
function Products() {
|
function Products() {
|
||||||
const { products, getProductById, addProduct, setProducts } = useProductStore();
|
const { products, getProductById, addProduct, setProducts } = useProductStore();
|
||||||
const { selectedProduct, setSelectedProduct } = useSelectedProduct();
|
const { selectedProduct, setSelectedProduct } = useSelectedProduct();
|
||||||
const { addVehicle, clearvehicles } = useVehicleStore();
|
const { addVehicle, clearvehicles } = useVehicleStore();
|
||||||
const { addArmBot, clearArmBots } = useArmBotStore();
|
const { addArmBot, clearArmBots } = useArmBotStore();
|
||||||
|
const { addConveyor, clearConveyors } = useConveyorStore();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const email = localStorage.getItem('email')
|
const email = localStorage.getItem('email')
|
||||||
|
@ -59,6 +61,20 @@ function Products() {
|
||||||
}
|
}
|
||||||
}, [selectedProduct, products]);
|
}, [selectedProduct, products]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (selectedProduct.productId) {
|
||||||
|
const product = getProductById(selectedProduct.productId);
|
||||||
|
if (product) {
|
||||||
|
clearConveyors();
|
||||||
|
product.eventDatas.forEach(events => {
|
||||||
|
if (events.type === 'transfer') {
|
||||||
|
addConveyor(selectedProduct.productId, events);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [selectedProduct, products]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,16 @@
|
||||||
import { useFrame } from '@react-three/fiber';
|
import { useFrame } from '@react-three/fiber';
|
||||||
import React, { useEffect, useRef, useState } from 'react';
|
import React, { useEffect, useRef, useState } from 'react';
|
||||||
import * as THREE from 'three';
|
import * as THREE from 'three';
|
||||||
import { useLogger } from '../../../../../components/ui/log/LoggerContext';
|
import { MaterialModel } from '../../../materials/instances/material/materialModel';
|
||||||
|
|
||||||
type MaterialAnimatorProps = {
|
type MaterialAnimatorProps = {
|
||||||
ikSolver: any;
|
ikSolver: any;
|
||||||
armBot: any;
|
armBot: ArmBotStatus;
|
||||||
currentPhase: string;
|
currentPhase: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function MaterialAnimator({ ikSolver, armBot, currentPhase }: MaterialAnimatorProps) {
|
export default function MaterialAnimator({ ikSolver, armBot, currentPhase }: MaterialAnimatorProps) {
|
||||||
const sphereRef = useRef<THREE.Mesh>(null);
|
const sphereRef = useRef<any>(null);
|
||||||
const boneWorldPosition = new THREE.Vector3();
|
|
||||||
const [isRendered, setIsRendered] = useState<boolean>(false);
|
const [isRendered, setIsRendered] = useState<boolean>(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -41,7 +40,8 @@ export default function MaterialAnimator({ ikSolver, armBot, currentPhase }: Mat
|
||||||
const direction = new THREE.Vector3();
|
const direction = new THREE.Vector3();
|
||||||
direction.subVectors(boneWorldPos, boneTargetWorldPos).normalize();
|
direction.subVectors(boneWorldPos, boneTargetWorldPos).normalize();
|
||||||
const downwardDirection = direction.clone().negate();
|
const downwardDirection = direction.clone().negate();
|
||||||
const adjustedPosition = boneWorldPos.clone().addScaledVector(downwardDirection, -0.25);
|
|
||||||
|
const adjustedPosition = boneWorldPos.clone().addScaledVector(downwardDirection, -0.01);
|
||||||
|
|
||||||
//set position
|
//set position
|
||||||
sphereRef.current.position.copy(adjustedPosition);
|
sphereRef.current.position.copy(adjustedPosition);
|
||||||
|
@ -56,10 +56,10 @@ export default function MaterialAnimator({ ikSolver, armBot, currentPhase }: Mat
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{isRendered && (
|
{isRendered && (
|
||||||
<mesh ref={sphereRef}>
|
<MaterialModel
|
||||||
<boxGeometry args={[0.5, 0.5, 0.5]} />
|
matRef={sphereRef}
|
||||||
<meshStandardMaterial color="yellow" />
|
materialType={armBot.currentAction?.materialType || 'Default material'}
|
||||||
</mesh>
|
/>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,39 +1,34 @@
|
||||||
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import { useFrame } from '@react-three/fiber';
|
import { useFrame } from '@react-three/fiber';
|
||||||
import * as THREE from 'three';
|
import * as THREE from 'three';
|
||||||
import { Line } from '@react-three/drei';
|
import { Line, Text } from '@react-three/drei';
|
||||||
import {
|
import { useAnimationPlaySpeed, usePauseButtonStore, usePlayButtonStore, useResetButtonStore } from '../../../../../store/usePlayButtonStore';
|
||||||
useAnimationPlaySpeed,
|
|
||||||
usePauseButtonStore,
|
type PointWithDegree = {
|
||||||
usePlayButtonStore,
|
position: [number, number, number];
|
||||||
useResetButtonStore
|
degree: number;
|
||||||
} from '../../../../../store/usePlayButtonStore';
|
};
|
||||||
|
|
||||||
|
function RoboticArmAnimator({ HandleCallback, restPosition, ikSolver, targetBone, armBot, path }: any) {
|
||||||
|
|
||||||
function RoboticArmAnimator({
|
|
||||||
HandleCallback,
|
|
||||||
restPosition,
|
|
||||||
ikSolver,
|
|
||||||
targetBone,
|
|
||||||
armBot,
|
|
||||||
path
|
|
||||||
}: any) {
|
|
||||||
const progressRef = useRef(0);
|
const progressRef = useRef(0);
|
||||||
const curveRef = useRef<THREE.Vector3[] | null>(null);
|
const curveRef = useRef<THREE.Vector3[] | null>(null);
|
||||||
const [currentPath, setCurrentPath] = useState<[number, number, number][]>([]);
|
|
||||||
const [circlePoints, setCirclePoints] = useState<[number, number, number][]>([]);
|
|
||||||
const [customCurvePoints, setCustomCurvePoints] = useState<THREE.Vector3[] | null>(null);
|
|
||||||
let curveHeight = 1.75
|
|
||||||
const totalDistanceRef = useRef(0);
|
const totalDistanceRef = useRef(0);
|
||||||
const startTimeRef = useRef<number | null>(null);
|
const startTimeRef = useRef<number | null>(null);
|
||||||
const segmentDistancesRef = useRef<number[]>([]);
|
const segmentDistancesRef = useRef<number[]>([]);
|
||||||
|
const [currentPath, setCurrentPath] = useState<[number, number, number][]>([]);
|
||||||
|
const [circlePoints, setCirclePoints] = useState<[number, number, number][]>([]);
|
||||||
|
const [circlePointsWithDegrees, setCirclePointsWithDegrees] = useState<PointWithDegree[]>([]);
|
||||||
|
const [customCurvePoints, setCustomCurvePoints] = useState<THREE.Vector3[] | null>(null);
|
||||||
|
let curveHeight = 1.75
|
||||||
|
const CIRCLE_RADIUS = 1.6
|
||||||
|
|
||||||
// Zustand stores
|
// Zustand stores
|
||||||
const { isPlaying } = usePlayButtonStore();
|
const { isPlaying } = usePlayButtonStore();
|
||||||
const { isPaused } = usePauseButtonStore();
|
const { isPaused } = usePauseButtonStore();
|
||||||
const { isReset } = useResetButtonStore();
|
const { isReset } = useResetButtonStore();
|
||||||
const { speed } = useAnimationPlaySpeed();
|
const { speed } = useAnimationPlaySpeed();
|
||||||
|
|
||||||
const CIRCLE_RADIUS = 1.6
|
|
||||||
|
|
||||||
// Update path state whenever `path` prop changes
|
// Update path state whenever `path` prop changes
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setCurrentPath(path);
|
setCurrentPath(path);
|
||||||
|
@ -47,7 +42,7 @@ function RoboticArmAnimator({
|
||||||
|
|
||||||
//Handle Reset Animation
|
//Handle Reset Animation
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isReset) {
|
if (isReset || !isPlaying) {
|
||||||
progressRef.current = 0;
|
progressRef.current = 0;
|
||||||
curveRef.current = null;
|
curveRef.current = null;
|
||||||
setCurrentPath([]);
|
setCurrentPath([]);
|
||||||
|
@ -76,6 +71,29 @@ function RoboticArmAnimator({
|
||||||
}
|
}
|
||||||
return points;
|
return points;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Generate CirclePoints with Angle
|
||||||
|
function generateRingPointsWithDegrees(radius: number, segments: number, initialRotation: [number, number, number]) {
|
||||||
|
const points: { position: [number, number, number]; degree: number }[] = [];
|
||||||
|
for (let i = 0; i < segments; i++) {
|
||||||
|
const angleRadians = (i / segments) * Math.PI * 2;
|
||||||
|
const x = Math.cos(angleRadians) * radius;
|
||||||
|
const z = Math.sin(angleRadians) * radius;
|
||||||
|
const degree = (angleRadians * 180) / Math.PI; // Convert radians to degrees
|
||||||
|
points.push({
|
||||||
|
position: [x, 1.5, z],
|
||||||
|
degree,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return points;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle circle points based on armBot position
|
||||||
|
useEffect(() => {
|
||||||
|
const points = generateRingPointsWithDegrees(CIRCLE_RADIUS, 64, armBot.rotation);
|
||||||
|
setCirclePointsWithDegrees(points)
|
||||||
|
}, [armBot.rotation]);
|
||||||
|
|
||||||
// Function for find nearest Circlepoints Index
|
// Function for find nearest Circlepoints Index
|
||||||
const findNearestIndex = (nearestPoint: [number, number, number], points: [number, number, number][], epsilon = 1e-6) => {
|
const findNearestIndex = (nearestPoint: [number, number, number], points: [number, number, number][], epsilon = 1e-6) => {
|
||||||
for (let i = 0; i < points.length; i++) {
|
for (let i = 0; i < points.length; i++) {
|
||||||
|
@ -100,6 +118,30 @@ function RoboticArmAnimator({
|
||||||
}, circlePoints[0]);
|
}, circlePoints[0]);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Helper function to collect points and check forbidden degrees
|
||||||
|
const collectArcPoints = (startIdx: number, endIdx: number, clockwise: boolean) => {
|
||||||
|
const totalSegments = 64;
|
||||||
|
const arcPoints: [number, number, number][] = [];
|
||||||
|
let i = startIdx;
|
||||||
|
|
||||||
|
while (i !== (endIdx + (clockwise ? 1 : -1) + totalSegments) % totalSegments) {
|
||||||
|
const { degree, position } = circlePointsWithDegrees[i];
|
||||||
|
// Skip over
|
||||||
|
arcPoints.push(position);
|
||||||
|
i = (i + (clockwise ? 1 : -1) + totalSegments) % totalSegments;
|
||||||
|
}
|
||||||
|
return arcPoints;
|
||||||
|
};
|
||||||
|
|
||||||
|
//Range to restrict angle
|
||||||
|
const hasForbiddenDegrees = (arc: [number, number, number][]) => {
|
||||||
|
return arc.some(p => {
|
||||||
|
const idx = findNearestIndex(p, circlePoints);
|
||||||
|
const degree = circlePointsWithDegrees[idx]?.degree || 0;
|
||||||
|
return degree >= 271 && degree <= 300; // Forbidden range: 271° to 300°
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
// Handle nearest points and final path (including arc points)
|
// Handle nearest points and final path (including arc points)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (circlePoints.length > 0 && currentPath.length > 0) {
|
if (circlePoints.length > 0 && currentPath.length > 0) {
|
||||||
|
@ -116,31 +158,23 @@ function RoboticArmAnimator({
|
||||||
const indexOfNearestStart = findNearestIndex(nearestToStart, circlePoints);
|
const indexOfNearestStart = findNearestIndex(nearestToStart, circlePoints);
|
||||||
const indexOfNearestEnd = findNearestIndex(nearestToEnd, circlePoints);
|
const indexOfNearestEnd = findNearestIndex(nearestToEnd, circlePoints);
|
||||||
|
|
||||||
const clockwiseDistance = (indexOfNearestEnd - indexOfNearestStart + 64) % 64;
|
const totalSegments = 64;
|
||||||
const counterClockwiseDistance = (indexOfNearestStart - indexOfNearestEnd + 64) % 64;
|
const clockwiseDistance = (indexOfNearestEnd - indexOfNearestStart + totalSegments) % totalSegments;
|
||||||
const clockwiseIsShorter = clockwiseDistance <= counterClockwiseDistance;
|
const counterClockwiseDistance = (indexOfNearestStart - indexOfNearestEnd + totalSegments) % totalSegments;
|
||||||
|
|
||||||
|
// Try both directions
|
||||||
|
const arcClockwise = collectArcPoints(indexOfNearestStart, indexOfNearestEnd, true);
|
||||||
|
const arcCounterClockwise = collectArcPoints(indexOfNearestStart, indexOfNearestEnd, false);
|
||||||
|
|
||||||
|
const clockwiseForbidden = hasForbiddenDegrees(arcClockwise);
|
||||||
|
const counterClockwiseForbidden = hasForbiddenDegrees(arcCounterClockwise);
|
||||||
|
|
||||||
let arcPoints: [number, number, number][] = [];
|
let arcPoints: [number, number, number][] = [];
|
||||||
|
|
||||||
if (clockwiseIsShorter) {
|
if (!clockwiseForbidden && (clockwiseDistance <= counterClockwiseDistance || counterClockwiseForbidden)) {
|
||||||
if (indexOfNearestStart <= indexOfNearestEnd) {
|
arcPoints = arcClockwise;
|
||||||
arcPoints = circlePoints.slice(indexOfNearestStart, indexOfNearestEnd + 1);
|
|
||||||
} else {
|
} else {
|
||||||
arcPoints = [
|
arcPoints = arcCounterClockwise;
|
||||||
...circlePoints.slice(indexOfNearestStart, 64),
|
|
||||||
...circlePoints.slice(0, indexOfNearestEnd + 1)
|
|
||||||
];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (indexOfNearestStart >= indexOfNearestEnd) {
|
|
||||||
for (let i = indexOfNearestStart; i !== (indexOfNearestEnd - 1 + 64) % 64; i = (i - 1 + 64) % 64) {
|
|
||||||
arcPoints.push(circlePoints[i]);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (let i = indexOfNearestStart; i !== (indexOfNearestEnd - 1 + 64) % 64; i = (i - 1 + 64) % 64) {
|
|
||||||
arcPoints.push(circlePoints[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const pathVectors = [
|
const pathVectors = [
|
||||||
|
@ -153,9 +187,7 @@ function RoboticArmAnimator({
|
||||||
new THREE.Vector3(end[0], end[1], end[2])
|
new THREE.Vector3(end[0], end[1], end[2])
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
const pathSegments: [THREE.Vector3, THREE.Vector3][] = [];
|
const pathSegments: [THREE.Vector3, THREE.Vector3][] = [];
|
||||||
|
|
||||||
for (let i = 0; i < pathVectors.length - 1; i++) {
|
for (let i = 0; i < pathVectors.length - 1; i++) {
|
||||||
pathSegments.push([pathVectors[i], pathVectors[i + 1]]);
|
pathSegments.push([pathVectors[i], pathVectors[i + 1]]);
|
||||||
}
|
}
|
||||||
|
@ -165,13 +197,7 @@ function RoboticArmAnimator({
|
||||||
const totalDistance = segmentDistances.reduce((sum, d) => sum + d, 0);
|
const totalDistance = segmentDistances.reduce((sum, d) => sum + d, 0);
|
||||||
totalDistanceRef.current = totalDistance;
|
totalDistanceRef.current = totalDistance;
|
||||||
|
|
||||||
const movementSpeed = speed * armBot.speed;
|
|
||||||
const totalMoveTime = totalDistance / movementSpeed;
|
|
||||||
|
|
||||||
const segmentTimes = segmentDistances.map(distance => (distance / totalDistance) * totalMoveTime);
|
|
||||||
|
|
||||||
setCustomCurvePoints(pathVectors);
|
setCustomCurvePoints(pathVectors);
|
||||||
|
|
||||||
}
|
}
|
||||||
}, [circlePoints, currentPath]);
|
}, [circlePoints, currentPath]);
|
||||||
|
|
||||||
|
@ -182,7 +208,6 @@ function RoboticArmAnimator({
|
||||||
const bone = ikSolver.mesh.skeleton.bones.find((b: any) => b.name === targetBone);
|
const bone = ikSolver.mesh.skeleton.bones.find((b: any) => b.name === targetBone);
|
||||||
|
|
||||||
if (!bone) return;
|
if (!bone) return;
|
||||||
|
|
||||||
if (isPlaying) {
|
if (isPlaying) {
|
||||||
if (isReset) {
|
if (isReset) {
|
||||||
bone.position.copy(restPosition);
|
bone.position.copy(restPosition);
|
||||||
|
@ -227,12 +252,17 @@ function RoboticArmAnimator({
|
||||||
ikSolver.update();
|
ikSolver.update();
|
||||||
}
|
}
|
||||||
} else if (!isPlaying && currentPath.length === 0) {
|
} else if (!isPlaying && currentPath.length === 0) {
|
||||||
|
progressRef.current = 0;
|
||||||
|
startTimeRef.current = null;
|
||||||
|
setCurrentPath([]);
|
||||||
|
setCustomCurvePoints([]);
|
||||||
bone.position.copy(restPosition);
|
bone.position.copy(restPosition);
|
||||||
|
|
||||||
}
|
}
|
||||||
ikSolver.update();
|
ikSolver.update();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
//Helper to Visible the Circle and Curve
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{customCurvePoints && customCurvePoints?.length >= 2 && currentPath && isPlaying && (
|
{customCurvePoints && customCurvePoints?.length >= 2 && currentPath && isPlaying && (
|
||||||
|
@ -245,10 +275,18 @@ function RoboticArmAnimator({
|
||||||
/>
|
/>
|
||||||
</mesh>
|
</mesh>
|
||||||
)}
|
)}
|
||||||
<mesh position={[armBot.position[0], armBot.position[1] + 1.5, armBot.position[2]]} rotation={[-Math.PI / 2, 0, 0]}>
|
<group
|
||||||
|
position={[armBot.position[0], armBot.position[1] + 1.5, armBot.position[2]]}
|
||||||
|
rotation={[armBot.rotation[0], armBot.rotation[1], armBot.rotation[2]]}
|
||||||
|
>
|
||||||
|
{/* Green ring */}
|
||||||
|
<mesh rotation={[-Math.PI / 2, 0, 0]}>
|
||||||
<ringGeometry args={[CIRCLE_RADIUS, CIRCLE_RADIUS + 0.02, 64]} />
|
<ringGeometry args={[CIRCLE_RADIUS, CIRCLE_RADIUS + 0.02, 64]} />
|
||||||
<meshBasicMaterial color="green" side={THREE.DoubleSide} />
|
<meshBasicMaterial color="green" side={THREE.DoubleSide} />
|
||||||
</mesh>
|
</mesh>
|
||||||
|
|
||||||
|
</group>
|
||||||
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,6 @@ import { usePauseButtonStore, usePlayButtonStore, useResetButtonStore } from '..
|
||||||
import { useArmBotStore } from '../../../../../store/simulation/useArmBotStore';
|
import { useArmBotStore } from '../../../../../store/simulation/useArmBotStore';
|
||||||
import armModel from "../../../../../assets/gltf-glb/rigged/ik_arm_1.glb";
|
import armModel from "../../../../../assets/gltf-glb/rigged/ik_arm_1.glb";
|
||||||
import { useThree } from "@react-three/fiber";
|
import { useThree } from "@react-three/fiber";
|
||||||
import useModuleStore from '../../../../../store/useModuleStore';
|
|
||||||
import * as THREE from "three";
|
import * as THREE from "three";
|
||||||
import MaterialAnimator from '../animator/materialAnimator';
|
import MaterialAnimator from '../animator/materialAnimator';
|
||||||
|
|
||||||
|
@ -24,16 +23,15 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
|
||||||
let startTime: number;
|
let startTime: number;
|
||||||
//zustand
|
//zustand
|
||||||
const { addCurrentAction, setArmBotActive, setArmBotState, removeCurrentAction } = useArmBotStore();
|
const { addCurrentAction, setArmBotActive, setArmBotState, removeCurrentAction } = useArmBotStore();
|
||||||
const { activeModule } = useModuleStore();
|
|
||||||
const { isPlaying } = usePlayButtonStore();
|
const { isPlaying } = usePlayButtonStore();
|
||||||
const { isReset, setReset } = useResetButtonStore();
|
const { isReset } = useResetButtonStore();
|
||||||
const { isPaused } = usePauseButtonStore();
|
const { isPaused } = usePauseButtonStore();
|
||||||
|
|
||||||
|
|
||||||
function firstFrame() {
|
function firstFrame() {
|
||||||
startTime = performance.now();
|
startTime = performance.now();
|
||||||
step();
|
step();
|
||||||
}
|
}
|
||||||
|
|
||||||
function step() {
|
function step() {
|
||||||
if (isPausedRef.current) {
|
if (isPausedRef.current) {
|
||||||
if (!pauseTimeRef.current) {
|
if (!pauseTimeRef.current) {
|
||||||
|
@ -87,6 +85,7 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
|
||||||
logStatus(armBot.modelUuid, "Moving armBot from end point to rest position.")
|
logStatus(armBot.modelUuid, "Moving armBot from end point to rest position.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
isPausedRef.current = isPaused;
|
isPausedRef.current = isPaused;
|
||||||
}, [isPaused]);
|
}, [isPaused]);
|
||||||
|
@ -98,6 +97,7 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
|
||||||
setArmBotState(armBot.modelUuid, "idle")
|
setArmBotState(armBot.modelUuid, "idle")
|
||||||
setCurrentPhase("init");
|
setCurrentPhase("init");
|
||||||
setPath([])
|
setPath([])
|
||||||
|
setIkSolver(null);
|
||||||
removeCurrentAction(armBot.modelUuid)
|
removeCurrentAction(armBot.modelUuid)
|
||||||
isPausedRef.current = false
|
isPausedRef.current = false
|
||||||
pauseTimeRef.current = null
|
pauseTimeRef.current = null
|
||||||
|
@ -117,17 +117,17 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const targetMesh = scene?.getObjectByProperty("uuid", armBot.modelUuid);
|
const targetMesh = scene?.getObjectByProperty("uuid", armBot.modelUuid);
|
||||||
if (targetMesh) {
|
if (targetMesh) {
|
||||||
targetMesh.visible = activeModule !== "simulation"
|
targetMesh.visible = (!isPlaying)
|
||||||
}
|
}
|
||||||
const targetBones = ikSolver?.mesh.skeleton.bones.find((b: any) => b.name === targetBone);
|
const targetBones = ikSolver?.mesh.skeleton.bones.find((b: any) => b.name === targetBone);
|
||||||
if (isPlaying) {
|
if (!isReset && isPlaying) {
|
||||||
//Moving armBot from initial point to rest position.
|
//Moving armBot from initial point to rest position.
|
||||||
if (!armBot?.isActive && armBot?.state == "idle" && currentPhase == "init") {
|
if (!armBot?.isActive && armBot?.state == "idle" && currentPhase == "init") {
|
||||||
|
if (targetBones) {
|
||||||
setArmBotActive(armBot.modelUuid, true)
|
setArmBotActive(armBot.modelUuid, true)
|
||||||
setArmBotState(armBot.modelUuid, "running")
|
setArmBotState(armBot.modelUuid, "running")
|
||||||
setCurrentPhase("init-to-rest");
|
setCurrentPhase("init-to-rest");
|
||||||
if (targetBones) {
|
let curve = createCurveBetweenTwoPoints(targetBones.position, restPosition)
|
||||||
let curve = createCurveBetweenTwoPoints(targetBones.position, targetBones.position)
|
|
||||||
if (curve) {
|
if (curve) {
|
||||||
setPath(curve.points.map(point => [point.x, point.y, point.z]));
|
setPath(curve.points.map(point => [point.x, point.y, point.z]));
|
||||||
}
|
}
|
||||||
|
@ -138,13 +138,13 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
|
||||||
else if (armBot && !armBot.isActive && armBot.state === "idle" && currentPhase === "rest" && !armBot.currentAction) {
|
else if (armBot && !armBot.isActive && armBot.state === "idle" && currentPhase === "rest" && !armBot.currentAction) {
|
||||||
logStatus(armBot.modelUuid, "Waiting to trigger CurrentAction")
|
logStatus(armBot.modelUuid, "Waiting to trigger CurrentAction")
|
||||||
const timeoutId = setTimeout(() => {
|
const timeoutId = setTimeout(() => {
|
||||||
addCurrentAction(armBot.modelUuid, armBot.point.actions[0].actionUuid);
|
addCurrentAction(armBot.modelUuid, armBot.point.actions[0].actionUuid, 'Material 2');
|
||||||
}, 3000);
|
}, 3000);
|
||||||
return () => clearTimeout(timeoutId);
|
return () => clearTimeout(timeoutId);
|
||||||
}
|
}
|
||||||
|
//Moving to pickup point
|
||||||
else if (armBot && !armBot.isActive && armBot.state === "idle" && currentPhase === "rest" && armBot.currentAction) {
|
else if (armBot && !armBot.isActive && armBot.state === "idle" && currentPhase === "rest" && armBot.currentAction) {
|
||||||
if (armBot.currentAction) {
|
if (armBot.currentAction) {
|
||||||
|
|
||||||
setArmBotActive(armBot.modelUuid, true);
|
setArmBotActive(armBot.modelUuid, true);
|
||||||
setArmBotState(armBot.modelUuid, "running");
|
setArmBotState(armBot.modelUuid, "running");
|
||||||
setCurrentPhase("rest-to-start");
|
setCurrentPhase("rest-to-start");
|
||||||
|
@ -158,15 +158,29 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
|
||||||
}
|
}
|
||||||
logStatus(armBot.modelUuid, "Moving armBot from rest point to start position.")
|
logStatus(armBot.modelUuid, "Moving armBot from rest point to start position.")
|
||||||
}
|
}
|
||||||
|
// Moving to Pick to Drop position
|
||||||
else if (armBot && !armBot.isActive && armBot.state === "idle" && currentPhase === "picking" && armBot.currentAction) {
|
else if (armBot && !armBot.isActive && armBot.state === "idle" && currentPhase === "picking" && armBot.currentAction) {
|
||||||
requestAnimationFrame(firstFrame);
|
requestAnimationFrame(firstFrame);
|
||||||
}
|
}
|
||||||
|
//Moving to drop point to restPosition
|
||||||
else if (armBot && !armBot.isActive && armBot.state === "idle" && currentPhase === "dropping" && armBot.currentAction) {
|
else if (armBot && !armBot.isActive && armBot.state === "idle" && currentPhase === "dropping" && armBot.currentAction) {
|
||||||
requestAnimationFrame(firstFrame);
|
requestAnimationFrame(firstFrame);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
logStatus(armBot.modelUuid, "Simulation Play Exited")
|
||||||
|
setArmBotActive(armBot.modelUuid, false)
|
||||||
|
setArmBotState(armBot.modelUuid, "idle")
|
||||||
|
setCurrentPhase("init");
|
||||||
|
setIkSolver(null);
|
||||||
|
setPath([])
|
||||||
|
isPausedRef.current = false
|
||||||
|
pauseTimeRef.current = null
|
||||||
|
isPausedRef.current = false
|
||||||
|
startTime = 0
|
||||||
|
removeCurrentAction(armBot.modelUuid)
|
||||||
}
|
}
|
||||||
|
|
||||||
}, [currentPhase, armBot, isPlaying, ikSolver])
|
}, [currentPhase, armBot, isPlaying, isReset, ikSolver])
|
||||||
|
|
||||||
|
|
||||||
function createCurveBetweenTwoPoints(p1: any, p2: any) {
|
function createCurveBetweenTwoPoints(p1: any, p2: any) {
|
||||||
|
@ -212,10 +226,14 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
{!isReset && isPlaying && (
|
||||||
<>
|
<>
|
||||||
<IKInstance modelUrl={armModel} setIkSolver={setIkSolver} ikSolver={ikSolver} armBot={armBot} groupRef={groupRef} />
|
<IKInstance modelUrl={armModel} setIkSolver={setIkSolver} ikSolver={ikSolver} armBot={armBot} groupRef={groupRef} />
|
||||||
<RoboticArmAnimator HandleCallback={HandleCallback} restPosition={restPosition} ikSolver={ikSolver} targetBone={targetBone} armBot={armBot}
|
<RoboticArmAnimator HandleCallback={HandleCallback} restPosition={restPosition} ikSolver={ikSolver} targetBone={targetBone} armBot={armBot}
|
||||||
logStatus={logStatus} path={path} currentPhase={currentPhase} />
|
logStatus={logStatus} path={path} currentPhase={currentPhase} />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
<MaterialAnimator ikSolver={ikSolver} armBot={armBot} currentPhase={currentPhase} />
|
<MaterialAnimator ikSolver={ikSolver} armBot={armBot} currentPhase={currentPhase} />
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|
|
@ -11,7 +11,7 @@ type IKInstanceProps = {
|
||||||
modelUrl: string;
|
modelUrl: string;
|
||||||
ikSolver: any;
|
ikSolver: any;
|
||||||
setIkSolver: any
|
setIkSolver: any
|
||||||
armBot: any;
|
armBot: ArmBotStatus;
|
||||||
groupRef: any;
|
groupRef: any;
|
||||||
};
|
};
|
||||||
function IKInstance({ modelUrl, setIkSolver, ikSolver, armBot, groupRef }: IKInstanceProps) {
|
function IKInstance({ modelUrl, setIkSolver, ikSolver, armBot, groupRef }: IKInstanceProps) {
|
||||||
|
@ -57,12 +57,6 @@ function IKInstance({ modelUrl, setIkSolver, ikSolver, armBot, groupRef }: IKIns
|
||||||
rotationMin: new THREE.Vector3(0, 0, 0),
|
rotationMin: new THREE.Vector3(0, 0, 0),
|
||||||
rotationMax: new THREE.Vector3(2, 0, 0),
|
rotationMax: new THREE.Vector3(2, 0, 0),
|
||||||
},
|
},
|
||||||
// {
|
|
||||||
// index: 1,
|
|
||||||
// enabled: true,
|
|
||||||
// rotationMin: new THREE.Vector3(0, -Math.PI, 0),
|
|
||||||
// rotationMax: new THREE.Vector3(0, Math.PI, 0),
|
|
||||||
// },
|
|
||||||
{ index: 1, enabled: true, limitation: new THREE.Vector3(0, 1, 0) },
|
{ index: 1, enabled: true, limitation: new THREE.Vector3(0, 1, 0) },
|
||||||
{ index: 0, enabled: false, limitation: new THREE.Vector3(0, 0, 0) },
|
{ index: 0, enabled: false, limitation: new THREE.Vector3(0, 0, 0) },
|
||||||
],
|
],
|
||||||
|
@ -76,7 +70,7 @@ function IKInstance({ modelUrl, setIkSolver, ikSolver, armBot, groupRef }: IKIns
|
||||||
|
|
||||||
setSelectedArm(OOI.Target_Bone);
|
setSelectedArm(OOI.Target_Bone);
|
||||||
|
|
||||||
scene.add(helper);
|
// scene.add(helper);
|
||||||
|
|
||||||
}, [cloned, gltf, setIkSolver]);
|
}, [cloned, gltf, setIkSolver]);
|
||||||
|
|
||||||
|
@ -86,10 +80,10 @@ function IKInstance({ modelUrl, setIkSolver, ikSolver, armBot, groupRef }: IKIns
|
||||||
setSelectedArm(groupRef.current?.getObjectByName(targetBoneName))
|
setSelectedArm(groupRef.current?.getObjectByName(targetBoneName))
|
||||||
}}>
|
}}>
|
||||||
<primitive
|
<primitive
|
||||||
uuid={"ArmBot-X200"}
|
uuid={armBot.modelUuid}
|
||||||
object={cloned}
|
object={cloned}
|
||||||
scale={[1, 1, 1]}
|
scale={[1, 1, 1]}
|
||||||
name={`arm-bot11`}
|
name={armBot.modelName}
|
||||||
/>
|
/>
|
||||||
</group>
|
</group>
|
||||||
{/* {selectedArm && <TransformControls object={selectedArm} />} */}
|
{/* {selectedArm && <TransformControls object={selectedArm} />} */}
|
||||||
|
|
|
@ -1,24 +1,37 @@
|
||||||
import { useEffect } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import RoboticArmInstances from "./instances/roboticArmInstances";
|
|
||||||
import { useArmBotStore } from "../../../store/simulation/useArmBotStore";
|
import { useArmBotStore } from "../../../store/simulation/useArmBotStore";
|
||||||
import { useSelectedEventData, useSelectedEventSphere } from "../../../store/simulation/useSimulationStore";
|
import { useSelectedEventSphere } from "../../../store/simulation/useSimulationStore";
|
||||||
|
import { usePlayButtonStore } from "../../../store/usePlayButtonStore";
|
||||||
import ArmBotUI from "../ui/arm/armBotUI";
|
import ArmBotUI from "../ui/arm/armBotUI";
|
||||||
|
import RoboticArmInstances from "./instances/roboticArmInstances";
|
||||||
|
|
||||||
function RoboticArm() {
|
function RoboticArm() {
|
||||||
const { armBots } = useArmBotStore();
|
const { armBots, getArmBotById } = useArmBotStore();
|
||||||
const { selectedEventSphere } = useSelectedEventSphere();
|
const { selectedEventSphere } = useSelectedEventSphere();
|
||||||
const { selectedEventData } = useSelectedEventData();
|
const { isPlaying } = usePlayButtonStore();
|
||||||
|
const [isArmBotSelected, setIsArmBotSelected] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// console.log('armBots: ', armBots);
|
// console.log('armBots: ', armBots);
|
||||||
}, [armBots])
|
}, [armBots])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (selectedEventSphere) {
|
||||||
|
const selectedArmBot = getArmBotById(selectedEventSphere.userData.modelUuid);
|
||||||
|
if (selectedArmBot) {
|
||||||
|
setIsArmBotSelected(true);
|
||||||
|
} else {
|
||||||
|
setIsArmBotSelected(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [selectedEventSphere])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
||||||
<RoboticArmInstances />
|
<RoboticArmInstances />
|
||||||
|
|
||||||
{selectedEventSphere && selectedEventData?.data.type === "roboticArm" &&
|
{isArmBotSelected && !isPlaying &&
|
||||||
< ArmBotUI />
|
< ArmBotUI />
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,131 +1,128 @@
|
||||||
import { useCallback, useEffect, useRef } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { useActionHandler } from '../../actions/useActionHandler';
|
import { useActionHandler } from '../../actions/useActionHandler';
|
||||||
import { useProductStore } from '../../../../store/simulation/useProductStore';
|
import { useProductStore } from '../../../../store/simulation/useProductStore';
|
||||||
import { useSelectedProduct } from '../../../../store/simulation/useSimulationStore';
|
import { useSelectedProduct } from '../../../../store/simulation/useSimulationStore';
|
||||||
import { useMaterialStore } from '../../../../store/simulation/useMaterialStore';
|
import { useMaterialStore } from '../../../../store/simulation/useMaterialStore';
|
||||||
|
|
||||||
export function useTriggerHandler() {
|
export function useTriggerHandler() {
|
||||||
const { getActionByUuid, getEventByTriggerUuid, getEventByModelUuid } = useProductStore();
|
const { getEventByTriggerUuid, getEventByModelUuid } = useProductStore();
|
||||||
const { handleAction } = useActionHandler();
|
const { handleAction } = useActionHandler();
|
||||||
const { getMaterialByCurrentModelUuid, setCurrentLocation, setNextLocation } = useMaterialStore();
|
const { setCurrentLocation, setNextLocation, getMaterialById } = useMaterialStore();
|
||||||
const { selectedProduct } = useSelectedProduct();
|
const { selectedProduct } = useSelectedProduct();
|
||||||
|
|
||||||
const handleTrigger = (trigger: TriggerSchema, actionUuid: string) => {
|
const handleTrigger = (trigger: TriggerSchema, action: Action, materialId: string) => {
|
||||||
|
|
||||||
// const fromEvent = getEventByTriggerUuid(selectedProduct.productId, trigger.triggerUuid);
|
const fromEvent = getEventByTriggerUuid(selectedProduct.productId, trigger.triggerUuid);
|
||||||
// console.log('fromEvent: ', fromEvent);
|
|
||||||
|
|
||||||
// const toEvent = getEventByModelUuid(selectedProduct.productId, trigger.triggeredAsset?.triggeredModel.modelUuid || '');
|
const toEvent = getEventByModelUuid(selectedProduct.productId, trigger.triggeredAsset?.triggeredModel.modelUuid || '');
|
||||||
// console.log('toEvent: ', toEvent);
|
|
||||||
|
|
||||||
// if (fromEvent?.type === 'transfer') {
|
if (fromEvent?.type === 'transfer') {
|
||||||
// if (toEvent?.type === 'transfer') {
|
if (toEvent?.type === 'transfer') {
|
||||||
// // console.log('toEvent: ', toEvent.type);
|
// Transfer to Transfer
|
||||||
// // Transfer to Transfer
|
if (trigger.triggeredAsset && trigger.triggeredAsset.triggeredPoint && trigger.triggeredAsset.triggeredAction) {
|
||||||
// const action = getActionByUuid(selectedProduct.productId, trigger.triggeredAsset?.triggeredAction?.actionUuid || '');
|
const material = getMaterialById(materialId);
|
||||||
// if (action && trigger.triggeredAsset && trigger.triggeredAsset.triggeredPoint && trigger.triggeredAsset.triggeredAction) {
|
if (material) {
|
||||||
// const material = getMaterialByCurrentModelUuid(fromEvent.modelUuid);
|
if (material.next) {
|
||||||
// if (material) {
|
|
||||||
// if (material.next &&
|
|
||||||
// action.triggers[0].triggeredAsset?.triggeredAction?.actionUuid &&
|
|
||||||
// action.triggers[0].triggeredAsset?.triggeredPoint?.pointUuid) {
|
|
||||||
|
|
||||||
// setCurrentLocation(material.materialId, material.next);
|
setCurrentLocation(material.materialId, {
|
||||||
|
modelUuid: material.next.modelUuid,
|
||||||
|
pointUuid: material.next.pointUuid,
|
||||||
|
actionUuid: trigger.triggeredAsset?.triggeredAction?.actionUuid,
|
||||||
|
});
|
||||||
|
|
||||||
// setNextLocation(material.materialId, {
|
setNextLocation(material.materialId, {
|
||||||
// modelUuid: toEvent.modelUuid,
|
modelUuid: trigger.triggeredAsset.triggeredModel.modelUuid,
|
||||||
// pointUuid: action.triggers[0].triggeredAsset?.triggeredPoint?.pointUuid,
|
pointUuid: trigger.triggeredAsset.triggeredPoint.pointUuid,
|
||||||
// actionUuid: action.triggers[0].triggeredAsset?.triggeredAction?.actionUuid
|
});
|
||||||
// });
|
}
|
||||||
// }
|
handleAction(action, materialId);
|
||||||
// handleAction(action);
|
}
|
||||||
// }
|
}
|
||||||
// }
|
} else if (toEvent?.type === 'vehicle') {
|
||||||
// } else if (toEvent?.type === 'vehicle') {
|
// Transfer to Vehicle
|
||||||
// // Transfer to Vehicle
|
|
||||||
|
|
||||||
// } else if (toEvent?.type === 'machine') {
|
} else if (toEvent?.type === 'machine') {
|
||||||
// // Transfer to Machine
|
// Transfer to Machine
|
||||||
|
|
||||||
// } else if (toEvent?.type === 'roboticArm') {
|
} else if (toEvent?.type === 'roboticArm') {
|
||||||
// // Transfer to Robotic Arm
|
// Transfer to Robotic Arm
|
||||||
|
|
||||||
// } else if (toEvent?.type === 'storageUnit') {
|
} else if (toEvent?.type === 'storageUnit') {
|
||||||
// // Transfer to Storage Unit
|
// Transfer to Storage Unit
|
||||||
|
|
||||||
// }
|
}
|
||||||
// } else if (fromEvent?.type === 'vehicle') {
|
} else if (fromEvent?.type === 'vehicle') {
|
||||||
// if (toEvent?.type === 'transfer') {
|
if (toEvent?.type === 'transfer') {
|
||||||
// // Vehicle to Transfer
|
// Vehicle to Transfer
|
||||||
|
|
||||||
// } else if (toEvent?.type === 'vehicle') {
|
} else if (toEvent?.type === 'vehicle') {
|
||||||
// // Vehicle to Vehicle
|
// Vehicle to Vehicle
|
||||||
|
|
||||||
// } else if (toEvent?.type === 'machine') {
|
} else if (toEvent?.type === 'machine') {
|
||||||
// // Vehicle to Machine
|
// Vehicle to Machine
|
||||||
|
|
||||||
// } else if (toEvent?.type === 'roboticArm') {
|
} else if (toEvent?.type === 'roboticArm') {
|
||||||
// // Vehicle to Robotic Arm
|
// Vehicle to Robotic Arm
|
||||||
|
|
||||||
// } else if (toEvent?.type === 'storageUnit') {
|
} else if (toEvent?.type === 'storageUnit') {
|
||||||
// // Vehicle to Storage Unit
|
// Vehicle to Storage Unit
|
||||||
|
|
||||||
// }
|
}
|
||||||
// } else if (fromEvent?.type === 'machine') {
|
} else if (fromEvent?.type === 'machine') {
|
||||||
// if (toEvent?.type === 'transfer') {
|
if (toEvent?.type === 'transfer') {
|
||||||
// // Machine to Transfer
|
// Machine to Transfer
|
||||||
|
|
||||||
// } else if (toEvent?.type === 'vehicle') {
|
} else if (toEvent?.type === 'vehicle') {
|
||||||
// // Machine to Vehicle
|
// Machine to Vehicle
|
||||||
|
|
||||||
// } else if (toEvent?.type === 'machine') {
|
} else if (toEvent?.type === 'machine') {
|
||||||
// // Machine to Machine
|
// Machine to Machine
|
||||||
|
|
||||||
// } else if (toEvent?.type === 'roboticArm') {
|
} else if (toEvent?.type === 'roboticArm') {
|
||||||
// // Machine to Robotic Arm
|
// Machine to Robotic Arm
|
||||||
|
|
||||||
// } else if (toEvent?.type === 'storageUnit') {
|
} else if (toEvent?.type === 'storageUnit') {
|
||||||
// // Machine to Storage Unit
|
// Machine to Storage Unit
|
||||||
|
|
||||||
// }
|
}
|
||||||
// } else if (fromEvent?.type === 'roboticArm') {
|
} else if (fromEvent?.type === 'roboticArm') {
|
||||||
// if (toEvent?.type === 'transfer') {
|
if (toEvent?.type === 'transfer') {
|
||||||
// // Robotic Arm to Transfer
|
// Robotic Arm to Transfer
|
||||||
|
|
||||||
// } else if (toEvent?.type === 'vehicle') {
|
} else if (toEvent?.type === 'vehicle') {
|
||||||
// // Robotic Arm to Vehicle
|
// Robotic Arm to Vehicle
|
||||||
|
|
||||||
// } else if (toEvent?.type === 'machine') {
|
} else if (toEvent?.type === 'machine') {
|
||||||
// // Robotic Arm to Machine
|
// Robotic Arm to Machine
|
||||||
|
|
||||||
// } else if (toEvent?.type === 'roboticArm') {
|
} else if (toEvent?.type === 'roboticArm') {
|
||||||
// // Robotic Arm to Robotic Arm
|
// Robotic Arm to Robotic Arm
|
||||||
|
|
||||||
// } else if (toEvent?.type === 'storageUnit') {
|
} else if (toEvent?.type === 'storageUnit') {
|
||||||
// // Robotic Arm to Storage Unit
|
// Robotic Arm to Storage Unit
|
||||||
|
|
||||||
// }
|
}
|
||||||
// } else if (fromEvent?.type === 'storageUnit') {
|
} else if (fromEvent?.type === 'storageUnit') {
|
||||||
// if (toEvent?.type === 'transfer') {
|
if (toEvent?.type === 'transfer') {
|
||||||
// // Storage Unit to Transfer
|
// Storage Unit to Transfer
|
||||||
|
|
||||||
// } else if (toEvent?.type === 'vehicle') {
|
} else if (toEvent?.type === 'vehicle') {
|
||||||
// // Storage Unit to Vehicle
|
// Storage Unit to Vehicle
|
||||||
|
|
||||||
// } else if (toEvent?.type === 'machine') {
|
} else if (toEvent?.type === 'machine') {
|
||||||
// // Storage Unit to Machine
|
// Storage Unit to Machine
|
||||||
|
|
||||||
// } else if (toEvent?.type === 'roboticArm') {
|
} else if (toEvent?.type === 'roboticArm') {
|
||||||
// // Storage Unit to Robotic Arm
|
// Storage Unit to Robotic Arm
|
||||||
|
|
||||||
// } else if (toEvent?.type === 'storageUnit') {
|
} else if (toEvent?.type === 'storageUnit') {
|
||||||
// // Storage Unit to Storage Unit
|
// Storage Unit to Storage Unit
|
||||||
|
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const triggerPointActions = useCallback((action: Action) => {
|
const triggerPointActions = useCallback((action: Action, materialId: string) => {
|
||||||
if (!action) return;
|
if (!action) return;
|
||||||
|
|
||||||
action.triggers.forEach(trigger => {
|
action.triggers.forEach(trigger => {
|
||||||
|
@ -133,7 +130,7 @@ export function useTriggerHandler() {
|
||||||
case 'onStart':
|
case 'onStart':
|
||||||
break;
|
break;
|
||||||
case 'onComplete':
|
case 'onComplete':
|
||||||
handleTrigger(trigger, action.actionUuid);
|
handleTrigger(trigger, action, materialId);
|
||||||
break;
|
break;
|
||||||
case 'onStop':
|
case 'onStop':
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -121,31 +121,65 @@ export default function useDraggableGLTF(onUpdate: OnUpdateCallback) {
|
||||||
// CONSTRAIN MOVEMENT HERE:
|
// CONSTRAIN MOVEMENT HERE:
|
||||||
const centerX = selectedArmBot.position[0];
|
const centerX = selectedArmBot.position[0];
|
||||||
const centerZ = selectedArmBot.position[2];
|
const centerZ = selectedArmBot.position[2];
|
||||||
const minDistance = 1.2; // 1.4 radius
|
const minDistance = 1.2;
|
||||||
const maxDistance = 2; // 2 radius
|
const maxDistance = 2;
|
||||||
|
|
||||||
const deltaX = targetPosition.x - centerX;
|
const delta = new THREE.Vector3(targetPosition.x - centerX, 0, targetPosition.z - centerZ);
|
||||||
const deltaZ = targetPosition.z - centerZ;
|
|
||||||
const distance = Math.sqrt(deltaX * deltaX + deltaZ * deltaZ);
|
|
||||||
|
|
||||||
if (distance < minDistance || distance > maxDistance) {
|
// Create quaternion from rotation
|
||||||
const angle = Math.atan2(deltaZ, deltaX);
|
const robotEuler = new THREE.Euler(selectedArmBot.rotation[0], selectedArmBot.rotation[1], selectedArmBot.rotation[2]);
|
||||||
const clampedDistance = Math.min(
|
const robotQuaternion = new THREE.Quaternion().setFromEuler(robotEuler);
|
||||||
Math.max(distance, minDistance),
|
|
||||||
maxDistance
|
// Inverse rotate
|
||||||
|
const inverseQuaternion = robotQuaternion.clone().invert();
|
||||||
|
delta.applyQuaternion(inverseQuaternion);
|
||||||
|
|
||||||
|
// Angle in robot local space
|
||||||
|
let relativeAngle = Math.atan2(delta.z, delta.x);
|
||||||
|
let angleDeg = (relativeAngle * 180) / Math.PI;
|
||||||
|
if (angleDeg < 0) {
|
||||||
|
angleDeg += 360;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clamp angle
|
||||||
|
if (angleDeg < 0 || angleDeg > 270) {
|
||||||
|
const distanceTo90 = Math.abs(angleDeg - 0);
|
||||||
|
const distanceTo270 = Math.abs(angleDeg - 270);
|
||||||
|
if (distanceTo90 < distanceTo270) {
|
||||||
|
angleDeg = 0;
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
relativeAngle = (angleDeg * Math.PI) / 180;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Distance clamp
|
||||||
|
const distance = delta.length();
|
||||||
|
const clampedDistance = Math.min(Math.max(distance, minDistance), maxDistance);
|
||||||
|
|
||||||
|
// Calculate local target
|
||||||
|
const finalLocal = new THREE.Vector3(
|
||||||
|
Math.cos(relativeAngle) * clampedDistance,
|
||||||
|
0,
|
||||||
|
Math.sin(relativeAngle) * clampedDistance
|
||||||
);
|
);
|
||||||
|
|
||||||
targetPosition.x = centerX + Math.cos(angle) * clampedDistance;
|
// Rotate back to world space
|
||||||
targetPosition.z = centerZ + Math.sin(angle) * clampedDistance;
|
finalLocal.applyQuaternion(robotQuaternion);
|
||||||
}
|
|
||||||
|
targetPosition.x = centerX + finalLocal.x;
|
||||||
|
targetPosition.z = centerZ + finalLocal.z;
|
||||||
|
|
||||||
|
|
||||||
|
// Clamp Y axis if needed
|
||||||
targetPosition.y = Math.min(Math.max(targetPosition.y, 0.6), 1.9);
|
targetPosition.y = Math.min(Math.max(targetPosition.y, 0.6), 1.9);
|
||||||
// Convert world position to local if object is nested inside a parent
|
|
||||||
|
// Convert to local if parent exists
|
||||||
if (parent) {
|
if (parent) {
|
||||||
parent.worldToLocal(targetPosition);
|
parent.worldToLocal(targetPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update object position
|
// Update the object position
|
||||||
|
|
||||||
activeObjRef.current.position.copy(targetPosition);
|
activeObjRef.current.position.copy(targetPosition);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,7 +10,7 @@ interface VehicleAnimatorProps {
|
||||||
handleCallBack: () => void;
|
handleCallBack: () => void;
|
||||||
reset: () => void;
|
reset: () => void;
|
||||||
currentPhase: string;
|
currentPhase: string;
|
||||||
agvUuid: number;
|
agvUuid: string;
|
||||||
agvDetail: VehicleStatus;
|
agvDetail: VehicleStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ import { usePlayButtonStore } from '../../../../../store/usePlayButtonStore';
|
||||||
import { useVehicleStore } from '../../../../../store/simulation/useVehicleStore';
|
import { useVehicleStore } from '../../../../../store/simulation/useVehicleStore';
|
||||||
import MaterialAnimator from '../animator/materialAnimator';
|
import MaterialAnimator from '../animator/materialAnimator';
|
||||||
|
|
||||||
function VehicleInstance({ agvDetail }: any) {
|
function VehicleInstance({ agvDetail }: { agvDetail: VehicleStatus }) {
|
||||||
const { navMesh } = useNavMesh();
|
const { navMesh } = useNavMesh();
|
||||||
const vehicleRef: any = useRef();
|
const vehicleRef: any = useRef();
|
||||||
const { isPlaying } = usePlayButtonStore();
|
const { isPlaying } = usePlayButtonStore();
|
||||||
|
@ -74,6 +74,7 @@ function VehicleInstance({ agvDetail }: any) {
|
||||||
|
|
||||||
|
|
||||||
if (agvDetail.currentLoad === agvDetail.point.action.loadCapacity && agvDetail.materialType) {
|
if (agvDetail.currentLoad === agvDetail.point.action.loadCapacity && agvDetail.materialType) {
|
||||||
|
if (agvDetail.point.action.pickUpPoint && agvDetail.point.action.unLoadPoint) {
|
||||||
const toDrop = computePath(
|
const toDrop = computePath(
|
||||||
agvDetail.point.action.pickUpPoint.position,
|
agvDetail.point.action.pickUpPoint.position,
|
||||||
agvDetail.point.action.unLoadPoint.position
|
agvDetail.point.action.unLoadPoint.position
|
||||||
|
@ -84,7 +85,9 @@ function VehicleInstance({ agvDetail }: any) {
|
||||||
setVehicleActive(agvDetail.modelUuid, true);
|
setVehicleActive(agvDetail.modelUuid, true);
|
||||||
vehicleStatus(agvDetail.modelUuid, 'Started from pickup point, heading to drop point');
|
vehicleStatus(agvDetail.modelUuid, 'Started from pickup point, heading to drop point');
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else if (!agvDetail.isActive && agvDetail.state === 'idle' && currentPhase === 'dropping' && agvDetail.currentLoad === 0) {
|
} else if (!agvDetail.isActive && agvDetail.state === 'idle' && currentPhase === 'dropping' && agvDetail.currentLoad === 0) {
|
||||||
|
if (agvDetail.point.action.pickUpPoint && agvDetail.point.action.unLoadPoint) {
|
||||||
const dropToPickup = computePath(
|
const dropToPickup = computePath(
|
||||||
agvDetail.point.action.unLoadPoint.position,
|
agvDetail.point.action.unLoadPoint.position,
|
||||||
agvDetail.point.action.pickUpPoint.position
|
agvDetail.point.action.pickUpPoint.position
|
||||||
|
@ -97,6 +100,7 @@ function VehicleInstance({ agvDetail }: any) {
|
||||||
|
|
||||||
isIncrememtable.current = true;
|
isIncrememtable.current = true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
reset()
|
reset()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,26 +1,37 @@
|
||||||
import { useEffect } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import VehicleInstances from "./instances/vehicleInstances";
|
|
||||||
import { useVehicleStore } from "../../../store/simulation/useVehicleStore";
|
import { useVehicleStore } from "../../../store/simulation/useVehicleStore";
|
||||||
import { useSelectedEventData, useSelectedEventSphere } from "../../../store/simulation/useSimulationStore";
|
import { useSelectedEventSphere } from "../../../store/simulation/useSimulationStore";
|
||||||
import VehicleUI from "../ui/vehicle/vehicleUI";
|
|
||||||
import { usePlayButtonStore } from "../../../store/usePlayButtonStore";
|
import { usePlayButtonStore } from "../../../store/usePlayButtonStore";
|
||||||
|
import VehicleUI from "../ui/vehicle/vehicleUI";
|
||||||
|
import VehicleInstances from "./instances/vehicleInstances";
|
||||||
|
|
||||||
function Vehicles() {
|
function Vehicles() {
|
||||||
const { vehicles } = useVehicleStore();
|
const { vehicles, getVehicleById } = useVehicleStore();
|
||||||
const { selectedEventSphere } = useSelectedEventSphere();
|
const { selectedEventSphere } = useSelectedEventSphere();
|
||||||
const { selectedEventData } = useSelectedEventData();
|
|
||||||
const { isPlaying } = usePlayButtonStore();
|
const { isPlaying } = usePlayButtonStore();
|
||||||
|
const [isVehicleSelected, setIsVehicleSelected] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// console.log('vehicles: ', vehicles);
|
// console.log('vehicles: ', vehicles);
|
||||||
}, [vehicles])
|
}, [vehicles])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (selectedEventSphere) {
|
||||||
|
const selectedVehicle = getVehicleById(selectedEventSphere.userData.modelUuid);
|
||||||
|
if (selectedVehicle) {
|
||||||
|
setIsVehicleSelected(true);
|
||||||
|
} else {
|
||||||
|
setIsVehicleSelected(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [selectedEventSphere])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
||||||
<VehicleInstances />
|
<VehicleInstances />
|
||||||
|
|
||||||
{selectedEventSphere && selectedEventData?.data.type === "vehicle" && !isPlaying &&
|
{isVehicleSelected && !isPlaying &&
|
||||||
< VehicleUI />
|
< VehicleUI />
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ interface ArmBotStore {
|
||||||
) => void;
|
) => void;
|
||||||
clearArmBots: () => void;
|
clearArmBots: () => void;
|
||||||
|
|
||||||
addCurrentAction: (modelUuid: string, actionUuid: string) => void;
|
addCurrentAction: (modelUuid: string, actionUuid: string, materialType: string) => void;
|
||||||
removeCurrentAction: (modelUuid: string) => void;
|
removeCurrentAction: (modelUuid: string) => void;
|
||||||
|
|
||||||
addAction: (modelUuid: string, action: RoboticArmPointSchema['actions'][number]) => void;
|
addAction: (modelUuid: string, action: RoboticArmPointSchema['actions'][number]) => void;
|
||||||
|
@ -75,7 +75,7 @@ export const useArmBotStore = create<ArmBotStore>()(
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
addCurrentAction: (modelUuid, actionUuid) => {
|
addCurrentAction: (modelUuid, actionUuid, materialType) => {
|
||||||
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) {
|
||||||
|
@ -84,7 +84,7 @@ export const useArmBotStore = create<ArmBotStore>()(
|
||||||
armBot.currentAction = {
|
armBot.currentAction = {
|
||||||
actionUuid: action.actionUuid,
|
actionUuid: action.actionUuid,
|
||||||
actionName: action.actionName,
|
actionName: action.actionName,
|
||||||
materialType: null
|
materialType: materialType
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ interface ConveyorStore {
|
||||||
|
|
||||||
setConveyorActive: (modelUuid: string, isActive: boolean) => void;
|
setConveyorActive: (modelUuid: string, isActive: boolean) => void;
|
||||||
setConveyorState: (modelUuid: string, newState: ConveyorStatus['state']) => void;
|
setConveyorState: (modelUuid: string, newState: ConveyorStatus['state']) => void;
|
||||||
|
setConveyorPaused: (modelUuid: string, isPaused: boolean) => 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;
|
||||||
|
@ -37,6 +38,7 @@ export const useConveyorStore = create<ConveyorStore>()(
|
||||||
...event,
|
...event,
|
||||||
productId,
|
productId,
|
||||||
isActive: false,
|
isActive: false,
|
||||||
|
isPaused: false,
|
||||||
idleTime: 0,
|
idleTime: 0,
|
||||||
activeTime: 0,
|
activeTime: 0,
|
||||||
state: 'idle',
|
state: 'idle',
|
||||||
|
@ -84,6 +86,15 @@ export const useConveyorStore = create<ConveyorStore>()(
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
setConveyorPaused: (modelUuid, isPaused) => {
|
||||||
|
set((state) => {
|
||||||
|
const conveyor = state.conveyors.find(c => c.modelUuid === modelUuid);
|
||||||
|
if (conveyor) {
|
||||||
|
conveyor.isPaused = isPaused;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
incrementActiveTime: (modelUuid, incrementBy) => {
|
incrementActiveTime: (modelUuid, incrementBy) => {
|
||||||
set((state) => {
|
set((state) => {
|
||||||
const conveyor = state.conveyors.find(c => c.modelUuid === modelUuid);
|
const conveyor = state.conveyors.find(c => c.modelUuid === modelUuid);
|
||||||
|
|
|
@ -23,20 +23,22 @@ type MaterialsStore = {
|
||||||
location?: {
|
location?: {
|
||||||
modelUuid: string;
|
modelUuid: string;
|
||||||
pointUuid: string;
|
pointUuid: string;
|
||||||
actionUuid: string;
|
|
||||||
} | null
|
} | null
|
||||||
) => MaterialSchema | undefined;
|
) => MaterialSchema | undefined;
|
||||||
|
|
||||||
|
setMaterial: (materialId: string, materialType: string) => MaterialSchema | undefined;
|
||||||
setStartTime: (materialId: string, startTime: string) => MaterialSchema | undefined;
|
setStartTime: (materialId: string, startTime: string) => MaterialSchema | undefined;
|
||||||
setEndTime: (materialId: string, endTime: string) => MaterialSchema | undefined;
|
setEndTime: (materialId: string, endTime: string) => MaterialSchema | undefined;
|
||||||
setCost: (materialId: string, cost: number) => MaterialSchema | undefined;
|
setCost: (materialId: string, cost: number) => MaterialSchema | undefined;
|
||||||
setWeight: (materialId: string, weight: number) => MaterialSchema | undefined;
|
setWeight: (materialId: string, weight: number) => MaterialSchema | undefined;
|
||||||
setIsActive: (materialId: string, isActive: boolean) => MaterialSchema | undefined;
|
setIsActive: (materialId: string, isActive: boolean) => MaterialSchema | undefined;
|
||||||
setIsVisible: (materialId: string, isVisible: boolean) => MaterialSchema | undefined;
|
setIsVisible: (materialId: string, isVisible: boolean) => MaterialSchema | undefined;
|
||||||
|
setIsPaused: (materialId: string, isPlaying: boolean) => MaterialSchema | undefined;
|
||||||
setIsRendered: (materialId: string, isRendered: boolean) => MaterialSchema | undefined;
|
setIsRendered: (materialId: string, isRendered: boolean) => MaterialSchema | undefined;
|
||||||
|
|
||||||
getMaterialById: (materialId: string) => MaterialSchema | undefined;
|
getMaterialById: (materialId: string) => MaterialSchema | undefined;
|
||||||
getMaterialByCurrentModelUuid: (currentModelUuid: string) => MaterialSchema | undefined;
|
getMaterialsByCurrentModelUuid: (currentModelUuid: string) => MaterialSchema[] | undefined;
|
||||||
|
getMaterialByCurrentPointUuid: (currentPointUuid: string) => MaterialSchema | undefined;
|
||||||
getMaterialsByPoint: (pointUuid: string) => MaterialSchema[];
|
getMaterialsByPoint: (pointUuid: string) => MaterialSchema[];
|
||||||
getMaterialsByModel: (modelUuid: string) => MaterialSchema[];
|
getMaterialsByModel: (modelUuid: string) => MaterialSchema[];
|
||||||
};
|
};
|
||||||
|
@ -107,6 +109,18 @@ export const useMaterialStore = create<MaterialsStore>()(
|
||||||
return updatedMaterial;
|
return updatedMaterial;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
setMaterial: (materialId, materialType) => {
|
||||||
|
let updatedMaterial: MaterialSchema | undefined;
|
||||||
|
set((state) => {
|
||||||
|
const material = state.materials.find(m => m.materialId === materialId);
|
||||||
|
if (material) {
|
||||||
|
material.materialType = materialType;
|
||||||
|
updatedMaterial = JSON.parse(JSON.stringify(material));
|
||||||
|
};
|
||||||
|
});
|
||||||
|
return updatedMaterial;
|
||||||
|
},
|
||||||
|
|
||||||
setStartTime: (materialId, startTime) => {
|
setStartTime: (materialId, startTime) => {
|
||||||
let updatedMaterial: MaterialSchema | undefined;
|
let updatedMaterial: MaterialSchema | undefined;
|
||||||
set((state) => {
|
set((state) => {
|
||||||
|
@ -179,6 +193,18 @@ export const useMaterialStore = create<MaterialsStore>()(
|
||||||
return updatedMaterial;
|
return updatedMaterial;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
setIsPaused: (materialId, isPaused) => {
|
||||||
|
let updatedMaterial: MaterialSchema | undefined;
|
||||||
|
set((state) => {
|
||||||
|
const material = state.materials.find(m => m.materialId === materialId);
|
||||||
|
if (material) {
|
||||||
|
material.isPaused = isPaused;
|
||||||
|
updatedMaterial = JSON.parse(JSON.stringify(material));
|
||||||
|
};
|
||||||
|
});
|
||||||
|
return updatedMaterial;
|
||||||
|
},
|
||||||
|
|
||||||
setIsRendered: (materialId, isRendered) => {
|
setIsRendered: (materialId, isRendered) => {
|
||||||
let updatedMaterial: MaterialSchema | undefined;
|
let updatedMaterial: MaterialSchema | undefined;
|
||||||
set((state) => {
|
set((state) => {
|
||||||
|
@ -195,8 +221,12 @@ export const useMaterialStore = create<MaterialsStore>()(
|
||||||
return get().materials.find(m => m.materialId === materialId);
|
return get().materials.find(m => m.materialId === materialId);
|
||||||
},
|
},
|
||||||
|
|
||||||
getMaterialByCurrentModelUuid: (currentModelUuid) => {
|
getMaterialsByCurrentModelUuid: (currentModelUuid) => {
|
||||||
return get().materials.find(m => m.current?.modelUuid === currentModelUuid);
|
return get().materials.filter(m => m.current?.modelUuid === currentModelUuid);
|
||||||
|
},
|
||||||
|
|
||||||
|
getMaterialByCurrentPointUuid: (currentPointlUuid) => {
|
||||||
|
return get().materials.find(m => m.current?.pointUuid === currentPointlUuid);
|
||||||
},
|
},
|
||||||
|
|
||||||
getMaterialsByPoint: (pointUuid) => {
|
getMaterialsByPoint: (pointUuid) => {
|
||||||
|
|
|
@ -65,6 +65,7 @@ type ProductsStore = {
|
||||||
getEventByPointUuid: (productId: string, pointUuid: string) => EventsSchema | undefined;
|
getEventByPointUuid: (productId: string, pointUuid: string) => EventsSchema | undefined;
|
||||||
getPointByUuid: (productId: string, modelUuid: string, pointUuid: string) => ConveyorPointSchema | VehiclePointSchema | RoboticArmPointSchema | MachinePointSchema | StoragePointSchema | undefined;
|
getPointByUuid: (productId: string, modelUuid: string, pointUuid: string) => ConveyorPointSchema | VehiclePointSchema | RoboticArmPointSchema | MachinePointSchema | StoragePointSchema | undefined;
|
||||||
getActionByUuid: (productId: string, actionUuid: string) => (ConveyorPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action']) | undefined;
|
getActionByUuid: (productId: string, actionUuid: string) => (ConveyorPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action']) | undefined;
|
||||||
|
getActionByPointUuid: (productId: string, pointUuid: string) => (ConveyorPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action']) | undefined;
|
||||||
getModelUuidByPointUuid: (productId: string, actionUuid: string) => (string) | undefined;
|
getModelUuidByPointUuid: (productId: string, actionUuid: string) => (string) | undefined;
|
||||||
getModelUuidByActionUuid: (productId: string, actionUuid: string) => (string) | undefined;
|
getModelUuidByActionUuid: (productId: string, actionUuid: string) => (string) | undefined;
|
||||||
getPointUuidByActionUuid: (productId: string, actionUuid: string) => (string) | undefined;
|
getPointUuidByActionUuid: (productId: string, actionUuid: string) => (string) | undefined;
|
||||||
|
@ -625,6 +626,27 @@ export const useProductStore = create<ProductsStore>()(
|
||||||
return undefined;
|
return undefined;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getActionByPointUuid: (productId, pointUuid) => {
|
||||||
|
const product = get().products.find(p => p.productId === productId);
|
||||||
|
if (!product) return undefined;
|
||||||
|
|
||||||
|
for (const event of product.eventDatas) {
|
||||||
|
if ('points' in event) {
|
||||||
|
for (const point of (event as ConveyorEventSchema).points) {
|
||||||
|
if (point.uuid === pointUuid) {
|
||||||
|
return point.action;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if ('point' in event) {
|
||||||
|
const point = (event as any).point;
|
||||||
|
if (point.uuid === pointUuid) {
|
||||||
|
return point.action;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
},
|
||||||
|
|
||||||
getModelUuidByPointUuid: (productId, pointUuid) => {
|
getModelUuidByPointUuid: (productId, pointUuid) => {
|
||||||
const product = get().products.find(p => p.productId === productId);
|
const product = get().products.find(p => p.productId === productId);
|
||||||
if (!product) return undefined;
|
if (!product) return undefined;
|
||||||
|
|
|
@ -125,7 +125,6 @@ interface StorageAction {
|
||||||
actionUuid: string;
|
actionUuid: string;
|
||||||
actionName: string;
|
actionName: string;
|
||||||
actionType: "store";
|
actionType: "store";
|
||||||
materials: { materialName: string; materialId: string; }[];
|
|
||||||
storageCapacity: number;
|
storageCapacity: number;
|
||||||
triggers: TriggerSchema[];
|
triggers: TriggerSchema[];
|
||||||
}
|
}
|
||||||
|
@ -146,6 +145,7 @@ type productsSchema = {
|
||||||
interface ConveyorStatus extends ConveyorEventSchema {
|
interface ConveyorStatus extends ConveyorEventSchema {
|
||||||
productId: string;
|
productId: string;
|
||||||
isActive: boolean;
|
isActive: boolean;
|
||||||
|
isPaused: boolean;
|
||||||
idleTime: number;
|
idleTime: number;
|
||||||
activeTime: number;
|
activeTime: number;
|
||||||
}
|
}
|
||||||
|
@ -190,6 +190,7 @@ interface StorageUnitStatus extends StorageEventSchema {
|
||||||
idleTime: number;
|
idleTime: number;
|
||||||
activeTime: number;
|
activeTime: number;
|
||||||
currentLoad: number;
|
currentLoad: number;
|
||||||
|
materials?: { materialName: string; materialId: string; }[];
|
||||||
}
|
}
|
||||||
|
|
||||||
interface MaterialSchema {
|
interface MaterialSchema {
|
||||||
|
@ -198,6 +199,7 @@ interface MaterialSchema {
|
||||||
materialType: string;
|
materialType: string;
|
||||||
isActive: boolean;
|
isActive: boolean;
|
||||||
isVisible: boolean;
|
isVisible: boolean;
|
||||||
|
isPaused: boolean;
|
||||||
isRendered: boolean;
|
isRendered: boolean;
|
||||||
startTime?: string;
|
startTime?: string;
|
||||||
endTime?: string;
|
endTime?: string;
|
||||||
|
@ -213,7 +215,6 @@ interface MaterialSchema {
|
||||||
next?: {
|
next?: {
|
||||||
modelUuid: string;
|
modelUuid: string;
|
||||||
pointUuid: string;
|
pointUuid: string;
|
||||||
actionUuid: string;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue