feat: Enhance simulation with StaticMachine integration and ArmBot updates
- Added StaticMachine component to manage static machine states and interactions. - Implemented StaticMachineInstances for handling individual machine behaviors. - Updated ArmBot and related components to support interactions with static machines. - Refactored process handling to include ArmBot actions and trigger management. - Improved type definitions for simulation types to accommodate new features.
This commit is contained in:
parent
5cef9bdb8a
commit
5b42bd9c40
|
@ -225,7 +225,6 @@ async function handleModelLoad(
|
||||||
eventData as SimulationTypes.ConveyorEventsSchema
|
eventData as SimulationTypes.ConveyorEventsSchema
|
||||||
]);
|
]);
|
||||||
|
|
||||||
console.log('data: ', data);
|
|
||||||
socket.emit("v2:model-asset:add", data);
|
socket.emit("v2:model-asset:add", data);
|
||||||
|
|
||||||
} else if (res.type === "Vehicle") {
|
} else if (res.type === "Vehicle") {
|
||||||
|
@ -365,7 +364,7 @@ async function handleModelLoad(
|
||||||
uuid: pointUUID,
|
uuid: pointUUID,
|
||||||
position: res.points.position as [number, number, number],
|
position: res.points.position as [number, number, number],
|
||||||
rotation: res.points.rotation as [number, number, number],
|
rotation: res.points.rotation as [number, number, number],
|
||||||
actions: { uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', speed: 1, processes: [] },
|
actions: { uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', speed: 0.2, processes: [] },
|
||||||
triggers: { uuid: THREE.MathUtils.generateUUID(), name: 'Trigger 1', type: 'OnComplete' },
|
triggers: { uuid: THREE.MathUtils.generateUUID(), name: 'Trigger 1', type: 'OnComplete' },
|
||||||
connections: { source: { modelUUID: model.uuid, pointUUID: pointUUID }, targets: [] },
|
connections: { source: { modelUUID: model.uuid, pointUUID: pointUUID }, targets: [] },
|
||||||
}
|
}
|
||||||
|
|
|
@ -332,8 +332,8 @@ const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pas
|
||||||
} else if (eventData.type === 'StaticMachine' && eventData) {
|
} else if (eventData.type === 'StaticMachine' && eventData) {
|
||||||
const createStaticMachinePoint = () => {
|
const createStaticMachinePoint = () => {
|
||||||
const pointUUID = THREE.MathUtils.generateUUID();
|
const pointUUID = THREE.MathUtils.generateUUID();
|
||||||
const vehiclePoint = (eventData as SimulationTypes.StaticMachineEventsSchema)?.points;
|
const staticMachinePoint = (eventData as SimulationTypes.StaticMachineEventsSchema)?.points;
|
||||||
const hasActions = vehiclePoint?.actions !== undefined;
|
const hasActions = staticMachinePoint?.actions !== undefined;
|
||||||
|
|
||||||
const defaultAction = {
|
const defaultAction = {
|
||||||
uuid: THREE.MathUtils.generateUUID(),
|
uuid: THREE.MathUtils.generateUUID(),
|
||||||
|
@ -344,11 +344,11 @@ const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pas
|
||||||
|
|
||||||
return {
|
return {
|
||||||
uuid: pointUUID,
|
uuid: pointUUID,
|
||||||
position: vehiclePoint?.position,
|
position: staticMachinePoint?.position,
|
||||||
// rotation: vehiclePoint?.rotation,
|
rotation: staticMachinePoint?.rotation,
|
||||||
actions: hasActions
|
actions: hasActions
|
||||||
? {
|
? {
|
||||||
...vehiclePoint.actions,
|
...staticMachinePoint.actions,
|
||||||
uuid: THREE.MathUtils.generateUUID()
|
uuid: THREE.MathUtils.generateUUID()
|
||||||
}
|
}
|
||||||
: defaultAction,
|
: defaultAction,
|
||||||
|
@ -410,8 +410,8 @@ const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pas
|
||||||
} else if (eventData.type === 'ArmBot' && eventData) {
|
} else if (eventData.type === 'ArmBot' && eventData) {
|
||||||
const createArmBotPoint = () => {
|
const createArmBotPoint = () => {
|
||||||
const pointUUID = THREE.MathUtils.generateUUID();
|
const pointUUID = THREE.MathUtils.generateUUID();
|
||||||
const vehiclePoint = (eventData as SimulationTypes.ArmBotEventsSchema)?.points;
|
const armBotPoint = (eventData as SimulationTypes.ArmBotEventsSchema)?.points;
|
||||||
const hasActions = vehiclePoint?.actions !== undefined;
|
const hasActions = armBotPoint?.actions !== undefined;
|
||||||
|
|
||||||
const defaultAction = {
|
const defaultAction = {
|
||||||
uuid: THREE.MathUtils.generateUUID(),
|
uuid: THREE.MathUtils.generateUUID(),
|
||||||
|
@ -422,18 +422,19 @@ const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pas
|
||||||
|
|
||||||
return {
|
return {
|
||||||
uuid: pointUUID,
|
uuid: pointUUID,
|
||||||
position: vehiclePoint?.position,
|
position: armBotPoint?.position,
|
||||||
// rotation: vehiclePoint?.rotation,
|
rotation: armBotPoint?.rotation,
|
||||||
actions: hasActions
|
actions: hasActions
|
||||||
? {
|
? {
|
||||||
...vehiclePoint.actions,
|
...armBotPoint.actions,
|
||||||
uuid: THREE.MathUtils.generateUUID()
|
uuid: THREE.MathUtils.generateUUID(),
|
||||||
|
processes: []
|
||||||
}
|
}
|
||||||
: defaultAction,
|
: defaultAction,
|
||||||
triggers: {
|
triggers: {
|
||||||
uuid: THREE.MathUtils.generateUUID(),
|
uuid: THREE.MathUtils.generateUUID(),
|
||||||
name: vehiclePoint.triggers.name,
|
name: armBotPoint.triggers.name,
|
||||||
type: vehiclePoint.triggers.type,
|
type: armBotPoint.triggers.type,
|
||||||
},
|
},
|
||||||
connections: {
|
connections: {
|
||||||
source: { modelUUID: obj.uuid, pointUUID },
|
source: { modelUUID: obj.uuid, pointUUID },
|
||||||
|
|
|
@ -246,7 +246,7 @@ const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedOb
|
||||||
return {
|
return {
|
||||||
uuid: pointUUID,
|
uuid: pointUUID,
|
||||||
position: vehiclePoint?.position,
|
position: vehiclePoint?.position,
|
||||||
// rotation: vehiclePoint?.rotation,
|
rotation: vehiclePoint?.rotation,
|
||||||
actions: hasActions
|
actions: hasActions
|
||||||
? {
|
? {
|
||||||
...vehiclePoint.actions,
|
...vehiclePoint.actions,
|
||||||
|
@ -311,8 +311,8 @@ const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedOb
|
||||||
} else if (eventData.type === 'StaticMachine' && eventData) {
|
} else if (eventData.type === 'StaticMachine' && eventData) {
|
||||||
const createStaticMachinePoint = () => {
|
const createStaticMachinePoint = () => {
|
||||||
const pointUUID = THREE.MathUtils.generateUUID();
|
const pointUUID = THREE.MathUtils.generateUUID();
|
||||||
const vehiclePoint = (eventData as SimulationTypes.StaticMachineEventsSchema)?.points;
|
const staticMachinePoint = (eventData as SimulationTypes.StaticMachineEventsSchema)?.points;
|
||||||
const hasActions = vehiclePoint?.actions !== undefined;
|
const hasActions = staticMachinePoint?.actions !== undefined;
|
||||||
|
|
||||||
const defaultAction = {
|
const defaultAction = {
|
||||||
uuid: THREE.MathUtils.generateUUID(),
|
uuid: THREE.MathUtils.generateUUID(),
|
||||||
|
@ -323,11 +323,11 @@ const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedOb
|
||||||
|
|
||||||
return {
|
return {
|
||||||
uuid: pointUUID,
|
uuid: pointUUID,
|
||||||
position: vehiclePoint?.position,
|
position: staticMachinePoint?.position,
|
||||||
// rotation: vehiclePoint?.rotation,
|
rotation: staticMachinePoint?.rotation,
|
||||||
actions: hasActions
|
actions: hasActions
|
||||||
? {
|
? {
|
||||||
...vehiclePoint.actions,
|
...staticMachinePoint.actions,
|
||||||
uuid: THREE.MathUtils.generateUUID()
|
uuid: THREE.MathUtils.generateUUID()
|
||||||
}
|
}
|
||||||
: defaultAction,
|
: defaultAction,
|
||||||
|
@ -389,8 +389,8 @@ const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedOb
|
||||||
} else if (eventData.type === 'ArmBot' && eventData) {
|
} else if (eventData.type === 'ArmBot' && eventData) {
|
||||||
const createArmBotPoint = () => {
|
const createArmBotPoint = () => {
|
||||||
const pointUUID = THREE.MathUtils.generateUUID();
|
const pointUUID = THREE.MathUtils.generateUUID();
|
||||||
const vehiclePoint = (eventData as SimulationTypes.ArmBotEventsSchema)?.points;
|
const armBotPoint = (eventData as SimulationTypes.ArmBotEventsSchema)?.points;
|
||||||
const hasActions = vehiclePoint?.actions !== undefined;
|
const hasActions = armBotPoint?.actions !== undefined;
|
||||||
|
|
||||||
const defaultAction = {
|
const defaultAction = {
|
||||||
uuid: THREE.MathUtils.generateUUID(),
|
uuid: THREE.MathUtils.generateUUID(),
|
||||||
|
@ -401,18 +401,19 @@ const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedOb
|
||||||
|
|
||||||
return {
|
return {
|
||||||
uuid: pointUUID,
|
uuid: pointUUID,
|
||||||
position: vehiclePoint?.position,
|
position: armBotPoint?.position,
|
||||||
// rotation: vehiclePoint?.rotation,
|
rotation: armBotPoint?.rotation,
|
||||||
actions: hasActions
|
actions: hasActions
|
||||||
? {
|
? {
|
||||||
...vehiclePoint.actions,
|
...armBotPoint.actions,
|
||||||
uuid: THREE.MathUtils.generateUUID()
|
uuid: THREE.MathUtils.generateUUID(),
|
||||||
|
processes: []
|
||||||
}
|
}
|
||||||
: defaultAction,
|
: defaultAction,
|
||||||
triggers: {
|
triggers: {
|
||||||
uuid: THREE.MathUtils.generateUUID(),
|
uuid: THREE.MathUtils.generateUUID(),
|
||||||
name: vehiclePoint.triggers.name,
|
name: armBotPoint.triggers.name,
|
||||||
type: vehiclePoint.triggers.type,
|
type: armBotPoint.triggers.type,
|
||||||
},
|
},
|
||||||
connections: {
|
connections: {
|
||||||
source: { modelUUID: obj.uuid, pointUUID },
|
source: { modelUUID: obj.uuid, pointUUID },
|
||||||
|
|
|
@ -15,27 +15,38 @@ interface ArmBotState {
|
||||||
actions: { uuid: string; name: string; speed: number; processes: { triggerId: string; startPoint: string; endPoint: string }[]; };
|
actions: { uuid: string; name: string; speed: number; processes: { triggerId: string; startPoint: string; endPoint: string }[]; };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface StaticMachineState {
|
||||||
|
uuid: string;
|
||||||
|
status: string;
|
||||||
|
actions: { uuid: string; name: string; buffer: number; material: string; };
|
||||||
|
machineTriggerId: string;
|
||||||
|
connectedArmBot: string;
|
||||||
|
}
|
||||||
|
|
||||||
interface ArmBotProps {
|
interface ArmBotProps {
|
||||||
armBots: ArmBotState[];
|
armBots: ArmBotState[];
|
||||||
setArmBots: React.Dispatch<React.SetStateAction<ArmBotState[]>>;
|
setArmBots: React.Dispatch<React.SetStateAction<ArmBotState[]>>;
|
||||||
|
setStaticMachines: React.Dispatch<React.SetStateAction<StaticMachineState[]>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ArmBot = ({ armBots, setArmBots }: ArmBotProps) => {
|
const ArmBot = ({ armBots, setArmBots, setStaticMachines }: ArmBotProps) => {
|
||||||
const { activeModule } = useModuleStore();
|
const { activeModule } = useModuleStore();
|
||||||
const { scene } = useThree();
|
const { scene } = useThree();
|
||||||
const { simulationStates } = useSimulationStates();
|
const { simulationStates } = useSimulationStates();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const filtered = simulationStates.filter((s): s is SimulationTypes.ArmBotEventsSchema => s.type === "ArmBot");
|
const filtered = simulationStates.filter((s): s is SimulationTypes.ArmBotEventsSchema => s.type === "ArmBot");
|
||||||
const initialStates: ArmBotState[] = filtered.map(bot => ({
|
const initialStates: ArmBotState[] = filtered
|
||||||
uuid: bot.modeluuid,
|
.filter(bot => bot.points.connections.targets.length > 0)
|
||||||
position: bot.position,
|
.map(bot => ({
|
||||||
rotation: bot.rotation,
|
uuid: bot.modeluuid,
|
||||||
status: "idle",
|
position: bot.position,
|
||||||
material: "default",
|
rotation: bot.rotation,
|
||||||
triggerId: '',
|
status: "idle",
|
||||||
actions: bot.points.actions
|
material: "default",
|
||||||
}));
|
triggerId: '',
|
||||||
|
actions: bot.points.actions
|
||||||
|
}));
|
||||||
setArmBots(initialStates);
|
setArmBots(initialStates);
|
||||||
}, [simulationStates]);
|
}, [simulationStates]);
|
||||||
|
|
||||||
|
@ -57,6 +68,7 @@ const ArmBot = ({ armBots, setArmBots }: ArmBotProps) => {
|
||||||
index={i}
|
index={i}
|
||||||
armBot={bot}
|
armBot={bot}
|
||||||
setArmBots={setArmBots}
|
setArmBots={setArmBots}
|
||||||
|
setStaticMachines={setStaticMachines}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -30,13 +30,22 @@ interface ArmBotState {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface StaticMachineState {
|
||||||
|
uuid: string;
|
||||||
|
status: string;
|
||||||
|
actions: { uuid: string; name: string; buffer: number; material: string; };
|
||||||
|
machineTriggerId: string;
|
||||||
|
connectedArmBot: string;
|
||||||
|
}
|
||||||
|
|
||||||
interface ArmbotInstancesProps {
|
interface ArmbotInstancesProps {
|
||||||
index: number;
|
index: number;
|
||||||
armBot: ArmBotState;
|
armBot: ArmBotState;
|
||||||
setArmBots: React.Dispatch<React.SetStateAction<ArmBotState[]>>;
|
setArmBots: React.Dispatch<React.SetStateAction<ArmBotState[]>>;
|
||||||
|
setStaticMachines: React.Dispatch<React.SetStateAction<StaticMachineState[]>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ArmbotInstances: React.FC<ArmbotInstancesProps> = ({ index, armBot, setArmBots }) => {
|
export const ArmbotInstances: React.FC<ArmbotInstancesProps> = ({ index, armBot, setArmBots, setStaticMachines }) => {
|
||||||
const { scene } = useThree();
|
const { scene } = useThree();
|
||||||
const [processes, setProcesses] = useState<Process[]>([]);
|
const [processes, setProcesses] = useState<Process[]>([]);
|
||||||
|
|
||||||
|
@ -61,7 +70,7 @@ export const ArmbotInstances: React.FC<ArmbotInstancesProps> = ({ index, armBot,
|
||||||
setArmBots((prevArmBots) => {
|
setArmBots((prevArmBots) => {
|
||||||
return prevArmBots.map(bot => {
|
return prevArmBots.map(bot => {
|
||||||
if (bot.uuid === armBot.uuid) {
|
if (bot.uuid === armBot.uuid) {
|
||||||
return { ...bot, status };
|
return { ...bot, status, triggerId: status === 'idle' ? '' : armBot.triggerId };
|
||||||
}
|
}
|
||||||
return bot;
|
return bot;
|
||||||
});
|
});
|
||||||
|
@ -72,10 +81,13 @@ export const ArmbotInstances: React.FC<ArmbotInstancesProps> = ({ index, armBot,
|
||||||
<IkInstances
|
<IkInstances
|
||||||
key={index}
|
key={index}
|
||||||
uuid={armBot.uuid}
|
uuid={armBot.uuid}
|
||||||
|
selectedTrigger={armBot.triggerId}
|
||||||
modelUrl={armModel}
|
modelUrl={armModel}
|
||||||
position={armBot.position}
|
position={armBot.position}
|
||||||
rotation={armBot.rotation}
|
rotation={armBot.rotation}
|
||||||
processes={processes}
|
processes={processes}
|
||||||
|
armBot={armBot}
|
||||||
|
setStaticMachines={setStaticMachines}
|
||||||
updateArmBotStatus={updateArmBotStatus}
|
updateArmBotStatus={updateArmBotStatus}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
|
@ -2,6 +2,35 @@ import { useEffect, useMemo, useState, useRef } 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 { usePlayButtonStore } from "../../../store/usePlayButtonStore";
|
import { usePlayButtonStore } from "../../../store/usePlayButtonStore";
|
||||||
|
import { useSimulationStates } from "../../../store/store";
|
||||||
|
|
||||||
|
|
||||||
|
interface StaticMachineState {
|
||||||
|
uuid: string;
|
||||||
|
status: string;
|
||||||
|
actions: { uuid: string; name: string; buffer: number; material: string; };
|
||||||
|
machineTriggerId: string;
|
||||||
|
connectedArmBot: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ArmBotState {
|
||||||
|
uuid: string;
|
||||||
|
position: [number, number, number];
|
||||||
|
rotation: [number, number, number];
|
||||||
|
status: string;
|
||||||
|
material: string;
|
||||||
|
triggerId: string;
|
||||||
|
actions: {
|
||||||
|
uuid: string;
|
||||||
|
name: string;
|
||||||
|
speed: number;
|
||||||
|
processes: {
|
||||||
|
triggerId: string;
|
||||||
|
startPoint: string;
|
||||||
|
endPoint: string;
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
type IKAnimationControllerProps = {
|
type IKAnimationControllerProps = {
|
||||||
ikSolver: any;
|
ikSolver: any;
|
||||||
|
@ -16,6 +45,8 @@ type IKAnimationControllerProps = {
|
||||||
uuid: string;
|
uuid: string;
|
||||||
logStatus: (status: string) => void;
|
logStatus: (status: string) => void;
|
||||||
groupRef: React.RefObject<THREE.Group>;
|
groupRef: React.RefObject<THREE.Group>;
|
||||||
|
armBot: ArmBotState;
|
||||||
|
setStaticMachines: React.Dispatch<React.SetStateAction<StaticMachineState[]>>;
|
||||||
updateArmBotStatus: (status: string) => void;
|
updateArmBotStatus: (status: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,6 +58,8 @@ const IKAnimationController = ({
|
||||||
uuid,
|
uuid,
|
||||||
logStatus,
|
logStatus,
|
||||||
groupRef,
|
groupRef,
|
||||||
|
armBot,
|
||||||
|
setStaticMachines,
|
||||||
updateArmBotStatus
|
updateArmBotStatus
|
||||||
}: IKAnimationControllerProps) => {
|
}: IKAnimationControllerProps) => {
|
||||||
const [progress, setProgress] = useState(0);
|
const [progress, setProgress] = useState(0);
|
||||||
|
@ -36,6 +69,7 @@ const IKAnimationController = ({
|
||||||
const restSpeed = 0.1;
|
const restSpeed = 0.1;
|
||||||
const restPosition = new THREE.Vector3(0, 2, 1.6);
|
const restPosition = new THREE.Vector3(0, 2, 1.6);
|
||||||
const { isPlaying } = usePlayButtonStore();
|
const { isPlaying } = usePlayButtonStore();
|
||||||
|
const { simulationStates } = useSimulationStates();
|
||||||
|
|
||||||
// Track previous states for comparison
|
// Track previous states for comparison
|
||||||
const prevStateRef = useRef({
|
const prevStateRef = useRef({
|
||||||
|
@ -120,54 +154,56 @@ const IKAnimationController = ({
|
||||||
};
|
};
|
||||||
|
|
||||||
const processedCurves = useMemo(() => {
|
const processedCurves = useMemo(() => {
|
||||||
return process.map((p) => {
|
if (isPlaying)
|
||||||
const tempLift = 0.5;
|
return process.map((p) => {
|
||||||
const localStart = groupRef.current?.worldToLocal(p.startPoint.clone().add(new THREE.Vector3(0, tempLift, 0)));
|
const tempLift = 0.5;
|
||||||
const localEnd = groupRef.current?.worldToLocal(p.endPoint.clone().add(new THREE.Vector3(0, tempLift, 0)));
|
const localStart = groupRef.current?.worldToLocal(p.startPoint.clone().add(new THREE.Vector3(0, tempLift, 0)));
|
||||||
|
const localEnd = groupRef.current?.worldToLocal(p.endPoint.clone().add(new THREE.Vector3(0, tempLift, 0)));
|
||||||
|
|
||||||
if (localStart && localEnd) {
|
if (localStart && localEnd) {
|
||||||
|
|
||||||
const mid = new THREE.Vector3(
|
const mid = new THREE.Vector3(
|
||||||
(localStart.x + localEnd.x) / 1,
|
(localStart.x + localEnd.x) / 1,
|
||||||
Math.max(localStart.y, localEnd.y) + 0.8,
|
Math.max(localStart.y, localEnd.y) + 0.8,
|
||||||
(localStart.z + localEnd.z) / 0.9
|
(localStart.z + localEnd.z) / 0.9
|
||||||
);
|
);
|
||||||
|
|
||||||
const points = [
|
const points = [
|
||||||
restPosition.clone(),
|
restPosition.clone(),
|
||||||
localStart.clone(),
|
localStart.clone(),
|
||||||
mid.clone(),
|
mid.clone(),
|
||||||
localEnd.clone(),
|
localEnd.clone(),
|
||||||
restPosition.clone(),
|
restPosition.clone(),
|
||||||
];
|
];
|
||||||
const curve = new THREE.CatmullRomCurve3(points);
|
const curve = new THREE.CatmullRomCurve3(points);
|
||||||
const restToStartDist = points[0].distanceTo(points[1]);
|
const restToStartDist = points[0].distanceTo(points[1]);
|
||||||
const startToEndDist = points[1].distanceTo(points[3]);
|
const startToEndDist = points[1].distanceTo(points[3]);
|
||||||
const endToRestDist = points[3].distanceTo(points[4]);
|
const endToRestDist = points[3].distanceTo(points[4]);
|
||||||
|
|
||||||
const totalDist = restToStartDist + startToEndDist + endToRestDist;
|
const totalDist = restToStartDist + startToEndDist + endToRestDist;
|
||||||
const restToStartRange = [0, restToStartDist / totalDist];
|
const restToStartRange = [0, restToStartDist / totalDist];
|
||||||
const startToEndRange = [
|
const startToEndRange = [
|
||||||
restToStartRange[1],
|
restToStartRange[1],
|
||||||
restToStartRange[1] + startToEndDist / totalDist,
|
restToStartRange[1] + startToEndDist / totalDist,
|
||||||
];
|
];
|
||||||
const endToRestRange = [startToEndRange[1], 1];
|
const endToRestRange = [startToEndRange[1], 1];
|
||||||
|
|
||||||
return {
|
return {
|
||||||
trigger: p.triggerId,
|
trigger: p.triggerId,
|
||||||
curve,
|
curve,
|
||||||
speed: p.speed,
|
speed: p.speed,
|
||||||
restToStartRange,
|
restToStartRange,
|
||||||
startToEndRange,
|
startToEndRange,
|
||||||
endToRestRange,
|
endToRestRange,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, [process, groupRef]);
|
}, [process, groupRef, isPlaying]);
|
||||||
|
|
||||||
const activeCurve = useMemo(() => {
|
const activeCurve = useMemo(() => {
|
||||||
return processedCurves.find((c) => c?.trigger === selectedTrigger);
|
if (isPlaying && processedCurves)
|
||||||
}, [processedCurves, selectedTrigger]);
|
return processedCurves.find((c) => c?.trigger === selectedTrigger);
|
||||||
|
}, [processedCurves, selectedTrigger, isPlaying]);
|
||||||
|
|
||||||
// Initial movement to rest position
|
// Initial movement to rest position
|
||||||
useFrame((_, delta) => {
|
useFrame((_, delta) => {
|
||||||
|
@ -195,7 +231,7 @@ const IKAnimationController = ({
|
||||||
|
|
||||||
// Main animation loop
|
// Main animation loop
|
||||||
useFrame((_, delta) => {
|
useFrame((_, delta) => {
|
||||||
if (!ikSolver || !activeCurve || isInitializing) return;
|
if (!ikSolver || !activeCurve || isInitializing || !isPlaying) return;
|
||||||
|
|
||||||
const { curve, speed, restToStartRange, startToEndRange, endToRestRange } = activeCurve;
|
const { curve, speed, restToStartRange, startToEndRange, endToRestRange } = activeCurve;
|
||||||
const targetBone = ikSolver.mesh.skeleton.bones.find(
|
const targetBone = ikSolver.mesh.skeleton.bones.find(
|
||||||
|
@ -213,6 +249,35 @@ const IKAnimationController = ({
|
||||||
} else if (progress >= startToEndRange[0] && progress < startToEndRange[1]) {
|
} else if (progress >= startToEndRange[0] && progress < startToEndRange[1]) {
|
||||||
currentSpeed = speed;
|
currentSpeed = speed;
|
||||||
currentStatus = "moving"; // Moving between points
|
currentStatus = "moving"; // Moving between points
|
||||||
|
if (1 - progress < 0.05) {
|
||||||
|
// Find the process that matches the current trigger
|
||||||
|
const currentProcess = process.find(p => p.triggerId === selectedTrigger);
|
||||||
|
if (currentProcess) {
|
||||||
|
const triggerId = currentProcess.triggerId;
|
||||||
|
|
||||||
|
const endPoint = armBot.actions.processes.find((process) => process.triggerId === triggerId)?.endPoint;
|
||||||
|
|
||||||
|
// Search simulationStates for a StaticMachine that has a point matching this endPointId
|
||||||
|
const matchedStaticMachine = simulationStates.find(
|
||||||
|
(state) =>
|
||||||
|
state.type === "StaticMachine" &&
|
||||||
|
state.points?.uuid === endPoint// check for static machine with matching point uuid
|
||||||
|
) as any;
|
||||||
|
|
||||||
|
if (matchedStaticMachine) {
|
||||||
|
setStaticMachines((machines) => {
|
||||||
|
return machines.map((machine) => {
|
||||||
|
if (machine.uuid === matchedStaticMachine.modeluuid) {
|
||||||
|
return { ...machine, status: "running" };
|
||||||
|
} else {
|
||||||
|
return machine;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
} else if (progress >= endToRestRange[0] && progress < 1) {
|
} else if (progress >= endToRestRange[0] && progress < 1) {
|
||||||
currentSpeed = restSpeed;
|
currentSpeed = restSpeed;
|
||||||
currentStatus = "moving"; // Returning to rest
|
currentStatus = "moving"; // Returning to rest
|
||||||
|
|
|
@ -8,23 +8,55 @@ import { CCDIKSolver, CCDIKHelper, } from "three/examples/jsm/animation/CCDIKSol
|
||||||
import IKAnimationController from "./IKAnimationController";
|
import IKAnimationController from "./IKAnimationController";
|
||||||
import { TransformControls } from "@react-three/drei";
|
import { TransformControls } from "@react-three/drei";
|
||||||
|
|
||||||
|
interface StaticMachineState {
|
||||||
|
uuid: string;
|
||||||
|
status: string;
|
||||||
|
actions: { uuid: string; name: string; buffer: number; material: string; };
|
||||||
|
machineTriggerId: string;
|
||||||
|
connectedArmBot: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ArmBotState {
|
||||||
|
uuid: string;
|
||||||
|
position: [number, number, number];
|
||||||
|
rotation: [number, number, number];
|
||||||
|
status: string;
|
||||||
|
material: string;
|
||||||
|
triggerId: string;
|
||||||
|
actions: {
|
||||||
|
uuid: string;
|
||||||
|
name: string;
|
||||||
|
speed: number;
|
||||||
|
processes: {
|
||||||
|
triggerId: string;
|
||||||
|
startPoint: string;
|
||||||
|
endPoint: string;
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
const IkInstances = ({
|
const IkInstances = ({
|
||||||
uuid,
|
uuid,
|
||||||
|
selectedTrigger,
|
||||||
modelUrl,
|
modelUrl,
|
||||||
processes,
|
processes,
|
||||||
position,
|
position,
|
||||||
rotation,
|
rotation,
|
||||||
|
armBot,
|
||||||
|
setStaticMachines,
|
||||||
updateArmBotStatus
|
updateArmBotStatus
|
||||||
}: {
|
}: {
|
||||||
uuid: string;
|
uuid: string;
|
||||||
|
selectedTrigger: string;
|
||||||
modelUrl: string;
|
modelUrl: string;
|
||||||
processes: any;
|
processes: any;
|
||||||
position: [number, number, number];
|
position: [number, number, number];
|
||||||
rotation: [number, number, number];
|
rotation: [number, number, number];
|
||||||
|
armBot: ArmBotState;
|
||||||
|
setStaticMachines: React.Dispatch<React.SetStateAction<StaticMachineState[]>>;
|
||||||
updateArmBotStatus: (status: string) => void;
|
updateArmBotStatus: (status: string) => void;
|
||||||
}) => {
|
}) => {
|
||||||
const [ikSolver, setIkSolver] = useState<any>(null);
|
const [ikSolver, setIkSolver] = useState<any>(null);
|
||||||
const [selectedTrigger, setSelectedTrigger] = useState<string>("");
|
|
||||||
const gltf = useLoader(GLTFLoader, modelUrl, (loader) => {
|
const gltf = useLoader(GLTFLoader, modelUrl, (loader) => {
|
||||||
const draco = new DRACOLoader();
|
const draco = new DRACOLoader();
|
||||||
draco.setDecoderPath("https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/");
|
draco.setDecoderPath("https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/");
|
||||||
|
@ -82,17 +114,6 @@ const IkInstances = ({
|
||||||
|
|
||||||
}, [gltf]);
|
}, [gltf]);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const triggers = ["9f4a9b8b-e60d-4754-8c99-d71979da0e71", "b77b4f0a-ce55-4fe0-a181-a43ab3d01c83"];
|
|
||||||
let index = 0;
|
|
||||||
|
|
||||||
const cycleTriggers = setInterval(() => {
|
|
||||||
setSelectedTrigger(triggers[index]);
|
|
||||||
index = (index + 1) % triggers.length;
|
|
||||||
}, 10000);
|
|
||||||
|
|
||||||
return () => clearInterval(cycleTriggers);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const logStatus = (status: string) => {
|
const logStatus = (status: string) => {
|
||||||
// console.log(status);
|
// console.log(status);
|
||||||
|
@ -119,6 +140,8 @@ const IkInstances = ({
|
||||||
uuid={uuid}
|
uuid={uuid}
|
||||||
logStatus={logStatus}
|
logStatus={logStatus}
|
||||||
groupRef={groupRef}
|
groupRef={groupRef}
|
||||||
|
armBot={armBot}
|
||||||
|
setStaticMachines={setStaticMachines}
|
||||||
updateArmBotStatus={updateArmBotStatus}
|
updateArmBotStatus={updateArmBotStatus}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -11,11 +11,23 @@ import { ProcessData } from "./types";
|
||||||
import { useSimulationStates } from "../../../store/store";
|
import { useSimulationStates } from "../../../store/store";
|
||||||
import { retrieveGLTF } from "../../../utils/indexDB/idbUtils";
|
import { retrieveGLTF } from "../../../utils/indexDB/idbUtils";
|
||||||
|
|
||||||
|
interface ArmBotState {
|
||||||
|
uuid: string;
|
||||||
|
position: [number, number, number];
|
||||||
|
rotation: [number, number, number];
|
||||||
|
status: string;
|
||||||
|
material: string;
|
||||||
|
triggerId: string;
|
||||||
|
actions: { uuid: string; name: string; speed: number; processes: { triggerId: string; startPoint: string; endPoint: string }[]; };
|
||||||
|
}
|
||||||
|
|
||||||
interface ProcessContainerProps {
|
interface ProcessContainerProps {
|
||||||
processes: ProcessData[];
|
processes: ProcessData[];
|
||||||
setProcesses: React.Dispatch<React.SetStateAction<any[]>>;
|
setProcesses: React.Dispatch<React.SetStateAction<any[]>>;
|
||||||
agvRef: any;
|
agvRef: any;
|
||||||
MaterialRef: any;
|
MaterialRef: any;
|
||||||
|
armBots: ArmBotState[];
|
||||||
|
setArmBots: React.Dispatch<React.SetStateAction<ArmBotState[]>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ProcessAnimator: React.FC<ProcessContainerProps> = ({
|
const ProcessAnimator: React.FC<ProcessContainerProps> = ({
|
||||||
|
@ -23,6 +35,8 @@ const ProcessAnimator: React.FC<ProcessContainerProps> = ({
|
||||||
setProcesses,
|
setProcesses,
|
||||||
agvRef,
|
agvRef,
|
||||||
MaterialRef,
|
MaterialRef,
|
||||||
|
armBots,
|
||||||
|
setArmBots
|
||||||
}) => {
|
}) => {
|
||||||
const gltf = useLoader(GLTFLoader, crate) as GLTF;
|
const gltf = useLoader(GLTFLoader, crate) as GLTF;
|
||||||
const groupRef = useRef<THREE.Group>(null);
|
const groupRef = useRef<THREE.Group>(null);
|
||||||
|
@ -42,7 +56,7 @@ const ProcessAnimator: React.FC<ProcessContainerProps> = ({
|
||||||
getPointDataForAnimationIndex,
|
getPointDataForAnimationIndex,
|
||||||
processes: processedProcesses,
|
processes: processedProcesses,
|
||||||
checkAndCountTriggers,
|
checkAndCountTriggers,
|
||||||
} = useProcessAnimation(processes, setProcesses, agvRef);
|
} = useProcessAnimation(processes, setProcesses, agvRef, armBots, setArmBots);
|
||||||
|
|
||||||
const baseMaterials = useMemo(() => ({
|
const baseMaterials = useMemo(() => ({
|
||||||
Box: new THREE.MeshStandardMaterial({ color: 0x8b4513 }),
|
Box: new THREE.MeshStandardMaterial({ color: 0x8b4513 }),
|
||||||
|
|
|
@ -2,11 +2,23 @@ import React, { useState } from "react";
|
||||||
import ProcessCreator from "./processCreator";
|
import ProcessCreator from "./processCreator";
|
||||||
import ProcessAnimator from "./processAnimator";
|
import ProcessAnimator from "./processAnimator";
|
||||||
|
|
||||||
|
interface ArmBotState {
|
||||||
|
uuid: string;
|
||||||
|
position: [number, number, number];
|
||||||
|
rotation: [number, number, number];
|
||||||
|
status: string;
|
||||||
|
material: string;
|
||||||
|
triggerId: string;
|
||||||
|
actions: { uuid: string; name: string; speed: number; processes: { triggerId: string; startPoint: string; endPoint: string }[]; };
|
||||||
|
}
|
||||||
|
|
||||||
interface ProcessContainerProps {
|
interface ProcessContainerProps {
|
||||||
processes: any[];
|
processes: any[];
|
||||||
setProcesses: React.Dispatch<React.SetStateAction<any[]>>;
|
setProcesses: React.Dispatch<React.SetStateAction<any[]>>;
|
||||||
agvRef: any;
|
agvRef: any;
|
||||||
MaterialRef: any;
|
MaterialRef: any;
|
||||||
|
armBots: ArmBotState[];
|
||||||
|
setArmBots: React.Dispatch<React.SetStateAction<ArmBotState[]>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ProcessContainer: React.FC<ProcessContainerProps> = ({
|
const ProcessContainer: React.FC<ProcessContainerProps> = ({
|
||||||
|
@ -14,6 +26,8 @@ const ProcessContainer: React.FC<ProcessContainerProps> = ({
|
||||||
setProcesses,
|
setProcesses,
|
||||||
agvRef,
|
agvRef,
|
||||||
MaterialRef,
|
MaterialRef,
|
||||||
|
armBots,
|
||||||
|
setArmBots
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -23,6 +37,8 @@ const ProcessContainer: React.FC<ProcessContainerProps> = ({
|
||||||
setProcesses={setProcesses}
|
setProcesses={setProcesses}
|
||||||
agvRef={agvRef}
|
agvRef={agvRef}
|
||||||
MaterialRef={MaterialRef}
|
MaterialRef={MaterialRef}
|
||||||
|
armBots={armBots}
|
||||||
|
setArmBots={setArmBots}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
|
@ -38,7 +38,7 @@ export interface ProcessPath {
|
||||||
pathPosition: number[];
|
pathPosition: number[];
|
||||||
pathRotation: number[];
|
pathRotation: number[];
|
||||||
speed: number;
|
speed: number;
|
||||||
type: "Conveyor" | "Vehicle";
|
type: "Conveyor" | "Vehicle" | "ArmBot";
|
||||||
isActive: boolean
|
isActive: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,10 +39,22 @@ interface PlayAgvState {
|
||||||
setPlayAgv: (data: any) => void;
|
setPlayAgv: (data: any) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface ArmBotState {
|
||||||
|
uuid: string;
|
||||||
|
position: [number, number, number];
|
||||||
|
rotation: [number, number, number];
|
||||||
|
status: string;
|
||||||
|
material: string;
|
||||||
|
triggerId: string;
|
||||||
|
actions: { uuid: string; name: string; speed: number; processes: { triggerId: string; startPoint: string; endPoint: string }[]; };
|
||||||
|
}
|
||||||
|
|
||||||
export const useProcessAnimation = (
|
export const useProcessAnimation = (
|
||||||
processes: ProcessData[],
|
processes: ProcessData[],
|
||||||
setProcesses: React.Dispatch<React.SetStateAction<any[]>>,
|
setProcesses: React.Dispatch<React.SetStateAction<any[]>>,
|
||||||
agvRef: any
|
agvRef: any,
|
||||||
|
armBots: ArmBotState[],
|
||||||
|
setArmBots: React.Dispatch<React.SetStateAction<ArmBotState[]>>
|
||||||
) => {
|
) => {
|
||||||
// State and refs initialization
|
// State and refs initialization
|
||||||
const { isPlaying, setIsPlaying } = usePlayButtonStore();
|
const { isPlaying, setIsPlaying } = usePlayButtonStore();
|
||||||
|
@ -438,6 +450,8 @@ export const useProcessAnimation = (
|
||||||
[handleMaterialSwap]
|
[handleMaterialSwap]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const deferredArmBotUpdates = useRef<{ uuid: string; triggerId: string }[]>([]);
|
||||||
|
|
||||||
// Trigger counting system
|
// Trigger counting system
|
||||||
const checkAndCountTriggers = useCallback(
|
const checkAndCountTriggers = useCallback(
|
||||||
(
|
(
|
||||||
|
@ -457,46 +471,54 @@ export const useProcessAnimation = (
|
||||||
const point = getPointDataForAnimationIndex(process, currentPointIndex);
|
const point = getPointDataForAnimationIndex(process, currentPointIndex);
|
||||||
if (!point?.triggers) return prev;
|
if (!point?.triggers) return prev;
|
||||||
|
|
||||||
const onHitTriggers = point.triggers.filter(
|
const onHitTriggers = point.triggers.filter((t: Trigger) => t.type === "On-Hit" && t.isUsed);
|
||||||
(t: Trigger) => t.type === "On-Hit" && t.isUsed
|
|
||||||
);
|
|
||||||
if (onHitTriggers.length === 0) return prev;
|
if (onHitTriggers.length === 0) return prev;
|
||||||
|
|
||||||
let newTriggerCounts = { ...processState.triggerCounts };
|
let newTriggerCounts = { ...processState.triggerCounts };
|
||||||
const newTriggerLogs = [...processState.triggerLogs];
|
const newTriggerLogs = [...processState.triggerLogs];
|
||||||
let shouldLog = false;
|
let shouldLog = false;
|
||||||
|
|
||||||
// Find all vehicle paths for this process
|
const vehiclePaths = process.paths.filter((path) => path.type === "Vehicle");
|
||||||
const vehiclePaths = process.paths.filter(
|
const armBotPaths = process.paths.filter((path) => path.type === "ArmBot");
|
||||||
(path) => path.type === "Vehicle"
|
|
||||||
);
|
|
||||||
|
|
||||||
// Check if any vehicle is active for this process
|
const activeVehicles = vehiclePaths.filter((path) => {
|
||||||
const activeVehicles = vehiclePaths.filter(path => {
|
|
||||||
const vehicleId = path.modeluuid;
|
const vehicleId = path.modeluuid;
|
||||||
const vehicleEntry = agvRef.current.find(
|
const vehicleEntry = agvRef.current.find((v: any) => v.vehicleId === vehicleId && v.processId === processId);
|
||||||
(v: any) => v.vehicleId === vehicleId && v.processId === processId
|
|
||||||
);
|
|
||||||
return vehicleEntry?.isActive;
|
return vehicleEntry?.isActive;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Only count triggers if no vehicles are active for this process
|
// Check if any ArmBot is active for this process
|
||||||
|
// const activeArmBots = armBotPaths.filter((path) => {
|
||||||
|
// const armBotId = path.modeluuid;
|
||||||
|
// const armBotEntry = armBots.find((a: any) => a.uuid === armBotId);
|
||||||
|
// return armBotEntry;
|
||||||
|
// });
|
||||||
|
|
||||||
|
// Only count triggers if no vehicles and no ArmBots are active for this process
|
||||||
|
|
||||||
if (activeVehicles.length === 0) {
|
if (activeVehicles.length === 0) {
|
||||||
onHitTriggers.forEach((trigger: Trigger) => {
|
onHitTriggers.forEach((trigger: Trigger) => {
|
||||||
const triggerKey = `${point.uuid}-${trigger.uuid}`;
|
const connections = point.connections?.targets || [];
|
||||||
newTriggerCounts[triggerKey] = (newTriggerCounts[triggerKey] || 0) + 1;
|
|
||||||
shouldLog = true;
|
connections.forEach((connection) => {
|
||||||
newTriggerLogs.push({
|
const connectedModelUUID = connection.modelUUID;
|
||||||
timestamp: currentTime,
|
|
||||||
pointId: point.uuid,
|
const matchingArmPath = armBotPaths.find((path) => path.modeluuid === connectedModelUUID);
|
||||||
objectId,
|
|
||||||
triggerId: trigger.uuid,
|
if (matchingArmPath) {
|
||||||
|
deferredArmBotUpdates.current.push({
|
||||||
|
uuid: connectedModelUUID,
|
||||||
|
triggerId: trigger.uuid,
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let processTotalHits = Object.values(newTriggerCounts).reduce((a, b) => a + b, 0);
|
let processTotalHits = Object.values(newTriggerCounts).reduce((a, b) => a + b, 0);
|
||||||
|
|
||||||
|
// Handle logic for vehicles and ArmBots when a trigger is hit
|
||||||
if (shouldLog) {
|
if (shouldLog) {
|
||||||
vehiclePaths.forEach((vehiclePath) => {
|
vehiclePaths.forEach((vehiclePath) => {
|
||||||
if (vehiclePath.points?.length > 0) {
|
if (vehiclePath.points?.length > 0) {
|
||||||
|
@ -506,7 +528,10 @@ export const useProcessAnimation = (
|
||||||
|
|
||||||
if (maxHitCount !== undefined) {
|
if (maxHitCount !== undefined) {
|
||||||
const vehicleId = vehiclePath.modeluuid;
|
const vehicleId = vehiclePath.modeluuid;
|
||||||
let vehicleEntry = agvRef.current.find((v: any) => v.vehicleId === vehicleId && v.processId === processId);
|
let vehicleEntry = agvRef.current.find(
|
||||||
|
(v: any) =>
|
||||||
|
v.vehicleId === vehicleId && v.processId === processId
|
||||||
|
);
|
||||||
|
|
||||||
if (!vehicleEntry) {
|
if (!vehicleEntry) {
|
||||||
vehicleEntry = {
|
vehicleEntry = {
|
||||||
|
@ -515,14 +540,13 @@ export const useProcessAnimation = (
|
||||||
maxHitCount: maxHitCount,
|
maxHitCount: maxHitCount,
|
||||||
isActive: false,
|
isActive: false,
|
||||||
hitCount: 0,
|
hitCount: 0,
|
||||||
status: 'stationed'
|
status: "stationed",
|
||||||
};
|
};
|
||||||
agvRef.current.push(vehicleEntry);
|
agvRef.current.push(vehicleEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (!vehicleEntry.isActive && vehicleEntry.status === 'picking') {
|
|
||||||
if (!vehicleEntry.isActive) {
|
if (!vehicleEntry.isActive) {
|
||||||
vehicleEntry.hitCount = processTotalHits;
|
vehicleEntry.hitCount++;
|
||||||
vehicleEntry.lastUpdated = currentTime;
|
vehicleEntry.lastUpdated = currentTime;
|
||||||
|
|
||||||
if (vehicleEntry.hitCount >= vehicleEntry.maxHitCount) {
|
if (vehicleEntry.hitCount >= vehicleEntry.maxHitCount) {
|
||||||
|
@ -546,9 +570,21 @@ export const useProcessAnimation = (
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
},
|
}, []);
|
||||||
[]
|
|
||||||
);
|
useEffect(() => {
|
||||||
|
if (deferredArmBotUpdates.current.length > 0) {
|
||||||
|
const updates = [...deferredArmBotUpdates.current];
|
||||||
|
deferredArmBotUpdates.current = [];
|
||||||
|
|
||||||
|
setArmBots((prev) =>
|
||||||
|
prev.map((bot) => {
|
||||||
|
const update = updates.find((u) => u.uuid === bot.uuid);
|
||||||
|
return update ? { ...bot, triggerId: update.triggerId } : bot;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}, [animationStates]);
|
||||||
|
|
||||||
// Utility functions
|
// Utility functions
|
||||||
const hasNonInheritActions = useCallback(
|
const hasNonInheritActions = useCallback(
|
||||||
|
|
|
@ -6,6 +6,7 @@ import useModuleStore from "../../store/useModuleStore";
|
||||||
import ProcessContainer from "./process/processContainer";
|
import ProcessContainer from "./process/processContainer";
|
||||||
import Agv from "../builder/agv/agv";
|
import Agv from "../builder/agv/agv";
|
||||||
import ArmBot from "./armbot/ArmBot";
|
import ArmBot from "./armbot/ArmBot";
|
||||||
|
import StaticMachine from "./staticMachine/staticMachine";
|
||||||
|
|
||||||
interface ArmBotState {
|
interface ArmBotState {
|
||||||
uuid: string;
|
uuid: string;
|
||||||
|
@ -17,10 +18,19 @@ interface ArmBotState {
|
||||||
actions: { uuid: string; name: string; speed: number; processes: { triggerId: string; startPoint: string; endPoint: string }[]; };
|
actions: { uuid: string; name: string; speed: number; processes: { triggerId: string; startPoint: string; endPoint: string }[]; };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface StaticMachineState {
|
||||||
|
uuid: string;
|
||||||
|
status: string;
|
||||||
|
actions: { uuid: string; name: string; buffer: number; material: string; };
|
||||||
|
machineTriggerId: string;
|
||||||
|
connectedArmBot: string;
|
||||||
|
}
|
||||||
|
|
||||||
function Simulation() {
|
function Simulation() {
|
||||||
const { activeModule } = useModuleStore();
|
const { activeModule } = useModuleStore();
|
||||||
const pathsGroupRef = useRef() as React.MutableRefObject<THREE.Group>;
|
const pathsGroupRef = useRef() as React.MutableRefObject<THREE.Group>;
|
||||||
const [armBots, setArmBots] = useState<ArmBotState[]>([]);
|
const [armBots, setArmBots] = useState<ArmBotState[]>([]);
|
||||||
|
const [staticMachines, setStaticMachines] = useState<StaticMachineState[]>([]);
|
||||||
const [processes, setProcesses] = useState<any[]>([]);
|
const [processes, setProcesses] = useState<any[]>([]);
|
||||||
const agvRef = useRef([]);
|
const agvRef = useRef([]);
|
||||||
const MaterialRef = useRef([]);
|
const MaterialRef = useRef([]);
|
||||||
|
@ -38,6 +48,8 @@ function Simulation() {
|
||||||
setProcesses={setProcesses}
|
setProcesses={setProcesses}
|
||||||
agvRef={agvRef}
|
agvRef={agvRef}
|
||||||
MaterialRef={MaterialRef}
|
MaterialRef={MaterialRef}
|
||||||
|
armBots={armBots}
|
||||||
|
setArmBots={setArmBots}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Agv
|
<Agv
|
||||||
|
@ -48,7 +60,8 @@ function Simulation() {
|
||||||
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
<ArmBot armBots={armBots} setArmBots={setArmBots} />
|
<StaticMachine setArmBots={setArmBots} staticMachines={staticMachines} setStaticMachines={setStaticMachines} />
|
||||||
|
<ArmBot armBots={armBots} setArmBots={setArmBots} setStaticMachines={setStaticMachines} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,77 @@
|
||||||
|
import React, { useEffect } from 'react'
|
||||||
|
import * as SimulationTypes from '../../../types/simulationTypes';
|
||||||
|
import { useSimulationStates } from '../../../store/store';
|
||||||
|
import StaticMachineInstances from './staticMachineInstances';
|
||||||
|
|
||||||
|
interface ArmBotState {
|
||||||
|
uuid: string;
|
||||||
|
position: [number, number, number];
|
||||||
|
rotation: [number, number, number];
|
||||||
|
status: string;
|
||||||
|
material: string;
|
||||||
|
triggerId: string;
|
||||||
|
actions: { uuid: string; name: string; speed: number; processes: { triggerId: string; startPoint: string; endPoint: string }[]; };
|
||||||
|
}
|
||||||
|
|
||||||
|
interface StaticMachineState {
|
||||||
|
uuid: string;
|
||||||
|
status: string;
|
||||||
|
actions: { uuid: string; name: string; buffer: number; material: string; };
|
||||||
|
machineTriggerId: string;
|
||||||
|
connectedArmBot: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
type StaticMachineProps = {
|
||||||
|
setArmBots: React.Dispatch<React.SetStateAction<ArmBotState[]>>;
|
||||||
|
staticMachines: StaticMachineState[];
|
||||||
|
setStaticMachines: React.Dispatch<React.SetStateAction<StaticMachineState[]>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
function StaticMachine({ setArmBots, staticMachines, setStaticMachines }: StaticMachineProps) {
|
||||||
|
|
||||||
|
const { simulationStates } = useSimulationStates();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const filtered = simulationStates.filter((s): s is SimulationTypes.StaticMachineEventsSchema => s.type === "StaticMachine");
|
||||||
|
const initialStates: StaticMachineState[] = filtered
|
||||||
|
.filter(machine => machine.points.connections.targets.length > 0)
|
||||||
|
.map(machine => ({
|
||||||
|
uuid: machine.modeluuid,
|
||||||
|
status: "idle",
|
||||||
|
actions: machine.points.actions,
|
||||||
|
machineTriggerId: machine.points.triggers.uuid,
|
||||||
|
connectedArmBot: machine.points.connections.targets[0].modelUUID
|
||||||
|
}));
|
||||||
|
setStaticMachines(initialStates);
|
||||||
|
}, [simulationStates]);
|
||||||
|
|
||||||
|
const updateArmBotTriggerAndMachineStatus = (armBotUuid: string, triggerId: string, machineId: string) => {
|
||||||
|
setArmBots((prevArmBots) => {
|
||||||
|
return prevArmBots.map(bot => {
|
||||||
|
if (bot.uuid === armBotUuid) {
|
||||||
|
return { ...bot, triggerId: triggerId };
|
||||||
|
}
|
||||||
|
return bot;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
setStaticMachines((prevStaticMachines) => {
|
||||||
|
return prevStaticMachines.map(machine => {
|
||||||
|
if (machine.uuid === machineId) {
|
||||||
|
return { ...machine, status: "idle" };
|
||||||
|
} else {
|
||||||
|
return machine;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{staticMachines.map((machine, index) => (
|
||||||
|
<StaticMachineInstances key={index} machine={machine} updateArmBotTriggerAndMachineStatus={updateArmBotTriggerAndMachineStatus} />
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default StaticMachine;
|
|
@ -0,0 +1,33 @@
|
||||||
|
import React, { useEffect } from 'react'
|
||||||
|
import { useAnimationPlaySpeed } from '../../../store/usePlayButtonStore';
|
||||||
|
|
||||||
|
interface StaticMachineState {
|
||||||
|
uuid: string;
|
||||||
|
status: string;
|
||||||
|
actions: { uuid: string; name: string; buffer: number; material: string; };
|
||||||
|
machineTriggerId: string;
|
||||||
|
connectedArmBot: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
type StaticMachineInstancesProps = {
|
||||||
|
machine: StaticMachineState,
|
||||||
|
updateArmBotTriggerAndMachineStatus: (armBotUuid: string, triggerId: string, machineId: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
function StaticMachineInstances({ machine, updateArmBotTriggerAndMachineStatus }: StaticMachineInstancesProps) {
|
||||||
|
const { speed } = useAnimationPlaySpeed();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (machine.status === 'running') {
|
||||||
|
setTimeout(() => {
|
||||||
|
updateArmBotTriggerAndMachineStatus(machine.connectedArmBot, machine.machineTriggerId, machine.uuid);
|
||||||
|
}, machine.actions.buffer * 1000 * speed);
|
||||||
|
}
|
||||||
|
}, [machine])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<></>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default StaticMachineInstances
|
|
@ -64,7 +64,7 @@ interface StaticMachineEventsSchema {
|
||||||
uuid: string;
|
uuid: string;
|
||||||
position: [number, number, number];
|
position: [number, number, number];
|
||||||
rotation: [number, number, number];
|
rotation: [number, number, number];
|
||||||
actions: { uuid: string; name: string; buffer: number | string; material: string; isUsed: boolean; };
|
actions: { uuid: string; name: string; buffer: number; material: string; };
|
||||||
triggers: { uuid: string; name: string; type: string };
|
triggers: { uuid: string; name: string; type: string };
|
||||||
connections: {
|
connections: {
|
||||||
source: { modelUUID: string; pointUUID: string };
|
source: { modelUUID: string; pointUUID: string };
|
||||||
|
@ -103,7 +103,7 @@ export type EventData = {
|
||||||
isLocked: boolean;
|
isLocked: boolean;
|
||||||
isVisible: boolean;
|
isVisible: boolean;
|
||||||
eventData?:
|
eventData?:
|
||||||
| {
|
{
|
||||||
type: "Conveyor";
|
type: "Conveyor";
|
||||||
points: {
|
points: {
|
||||||
uuid: string;
|
uuid: string;
|
||||||
|
|
Loading…
Reference in New Issue