From 4e652bb48e1dfcc3d1c98c15c049e90818771281 Mon Sep 17 00:00:00 2001 From: SreeNath14 <153710861+SreeNath14@users.noreply.github.com> Date: Thu, 24 Apr 2025 09:47:44 +0530 Subject: [PATCH 01/13] feat: Enhance Robotic Arm functionality with state management and action handling --- .../instances/animator/roboticArmAnimator.tsx | 2 +- .../armInstance/roboticArmInstance.tsx | 52 ++- .../instances/roboticArmInstances.tsx | 12 +- .../simulation/roboticArm/roboticArm.tsx | 98 +++++- app/src/modules/simulation/simulation.tsx | 24 +- app/src/store/simulation/useArmBotStore.ts | 298 +++++++++--------- 6 files changed, 319 insertions(+), 167 deletions(-) diff --git a/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx b/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx index 0cd4fe2..6b35a43 100644 --- a/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx +++ b/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx @@ -1,6 +1,6 @@ import React from 'react' -function RoboticArmAnimator() { +function RoboticArmAnimator({ armUuid, HandleCallback, currentPhase }: any) { return ( <> ) diff --git a/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx index 2817906..42b775a 100644 --- a/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx +++ b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx @@ -1,14 +1,58 @@ -import React from 'react' +import React, { useEffect, useState } from 'react' import IKInstance from '../ikInstance/ikInstance'; import RoboticArmAnimator from '../animator/roboticArmAnimator'; +import { usePlayButtonStore } from '../../../../../store/usePlayButtonStore'; +import { useArmBotStore } from '../../../../../store/simulation/useArmBotStore'; + +function RoboticArmInstance({ armBot }: any) { + const { isPlaying } = usePlayButtonStore(); + const [currentPhase, setCurrentPhase] = useState<(string)>("init"); + console.log('currentPhase: ', currentPhase); + const { armBots, addArmBot, addCurrentAction } = useArmBotStore(); + + useEffect(() => { + + console.log('isPlaying: ', isPlaying); + if (isPlaying) { + //Moving armBot from initial point to rest position. + + if (armBot?.isActive && armBot?.state == "idle" && currentPhase == "init") { + addCurrentAction(armBot.modelUuid, 'action-001'); + setCurrentPhase("moving-to-rest"); + + } + //Waiting for trigger. + if (!armBot?.isActive && armBot?.state == "idle" && currentPhase == "moving-to-rest") { + setCurrentPhase("rest"); + } + // Moving armBot from rest position to pick up point. + if (!armBot?.isActive && armBot?.state == "idle" && currentPhase == "rest") { + + } + //Moving arm from start point to end point. + if (armBot?.isActive && armBot?.state == "running " && currentPhase == "rest-to-start ") { + + } + //Moving arm from end point to idle. + if (armBot?.isActive && armBot?.state == "running" && currentPhase == "end-to-start") { + + } + + } + + }, [currentPhase, armBot, isPlaying]) + + const HandleCallback = () => { + if (armBot.isActive && armBot.state == "idle" && currentPhase == "init") { + addCurrentAction('armbot-xyz-001', 'action-001'); + } + } -function RoboticArmInstance() { return ( <> - - + ) diff --git a/app/src/modules/simulation/roboticArm/instances/roboticArmInstances.tsx b/app/src/modules/simulation/roboticArm/instances/roboticArmInstances.tsx index 6e8a70a..1f963c8 100644 --- a/app/src/modules/simulation/roboticArm/instances/roboticArmInstances.tsx +++ b/app/src/modules/simulation/roboticArm/instances/roboticArmInstances.tsx @@ -1,11 +1,21 @@ import React from 'react' import RoboticArmInstance from './armInstance/roboticArmInstance'; +import { useArmBotStore } from '../../../../store/simulation/useArmBotStore'; function RoboticArmInstances() { + const { armBots } = useArmBotStore(); + + return ( <> + { + armBots?.map((robot: any) => ( - + + ) + ) + + } ) diff --git a/app/src/modules/simulation/roboticArm/roboticArm.tsx b/app/src/modules/simulation/roboticArm/roboticArm.tsx index 1270d93..7899f56 100644 --- a/app/src/modules/simulation/roboticArm/roboticArm.tsx +++ b/app/src/modules/simulation/roboticArm/roboticArm.tsx @@ -1,15 +1,103 @@ -import React from 'react' -import RoboticArmInstances from './instances/roboticArmInstances'; -import IkInstances from './instances/ikInstances'; +import React, { useEffect } from "react"; +import RoboticArmInstances from "./instances/roboticArmInstances"; +import IkInstances from "./instances/ikInstances"; +import { log } from "node:console"; +import { useArmBotStore } from "../../../store/simulation/useArmBotStore"; function RoboticArm() { + const { armBots, addArmBot, addCurrentAction } = useArmBotStore(); + + const armBotStatusSample: RoboticArmEventSchema[] = [ + { + state: "idle", + // currentAction: { + // actionUuid: "action-001", + // actionName: "Pick Component", + // }, + modelUuid: "armbot-xyz-001", + modelName: "ArmBot-X200", + position: [0, 0, 0], + rotation: [91.94347308985614, 0, 6.742905194869091], + type: "roboticArm", + speed: 1.5, + point: { + uuid: "point-123", + position: [0, 1.5, 0], + rotation: [0, 0, 0], + actions: [ + { + actionUuid: "action-001", + actionName: "Pick Component", + actionType: "pickAndPlace", + process: { + startPoint: [1.2, 0.3, 0.5], + endPoint: [-0.8, 1.1, 0.7], + }, + triggers: [ + { + triggerUuid: "trigger-001", + triggerName: "Start Trigger", + triggerType: "onStart", + delay: 0, + triggeredAsset: { + triggeredModel: { + modelName: "Conveyor A1", + modelUuid: "conveyor-01", + }, + triggeredPoint: { + pointName: "Start Point", + pointUuid: "conveyor-01-point-001", + }, + triggeredAction: { + actionName: "Move Forward", + actionUuid: "conveyor-action-01", + }, + }, + }, + { + triggerUuid: "trigger-002", + triggerName: "Complete Trigger", + triggerType: "onComplete", + delay: 0, + triggeredAsset: { + triggeredModel: { + modelName: "StaticMachine B2", + modelUuid: "machine-02", + }, + triggeredPoint: { + pointName: "Receive Point", + pointUuid: "machine-02-point-001", + }, + triggeredAction: { + actionName: "Process Part", + actionUuid: "machine-action-01", + }, + }, + }, + ], + }, + ], + }, + }, + ]; + + useEffect(() => { + addArmBot('123', armBotStatusSample[0]); + // addCurrentAction('armbot-xyz-001', 'action-001'); + }, []); + + + useEffect(() => { + console.log('armBots: ', armBots); + }, [armBots]); + return ( <> - ) + ); } -export default RoboticArm; \ No newline at end of file +export default RoboticArm; diff --git a/app/src/modules/simulation/simulation.tsx b/app/src/modules/simulation/simulation.tsx index 1be292e..556ed01 100644 --- a/app/src/modules/simulation/simulation.tsx +++ b/app/src/modules/simulation/simulation.tsx @@ -1,30 +1,30 @@ -import React, { useEffect } from 'react'; -import { useEventsStore } from '../../store/simulation/useEventsStore'; -import { useProductStore } from '../../store/simulation/useProductStore'; -import Vehicles from './vehicle/vehicles'; -import Points from './events/points/points'; +import React, { useEffect } from "react"; +import { useEventsStore } from "../../store/simulation/useEventsStore"; +import { useProductStore } from "../../store/simulation/useProductStore"; +import Vehicles from "./vehicle/vehicles"; +import Points from "./events/points/points"; +import RoboticArm from "./roboticArm/roboticArm"; function Simulation() { const { events } = useEventsStore(); const { products } = useProductStore(); useEffect(() => { - console.log('events: ', events); - }, [events]) + console.log("events: ", events); + }, [events]); useEffect(() => { // console.log('products: ', products); - }, [products]) + }, [products]); return ( <> - - + - ) + ); } -export default Simulation \ No newline at end of file +export default Simulation; diff --git a/app/src/store/simulation/useArmBotStore.ts b/app/src/store/simulation/useArmBotStore.ts index 493a068..84f0ec9 100644 --- a/app/src/store/simulation/useArmBotStore.ts +++ b/app/src/store/simulation/useArmBotStore.ts @@ -1,160 +1,170 @@ -import { create } from 'zustand'; -import { immer } from 'zustand/middleware/immer'; +import { create } from "zustand"; +import { immer } from "zustand/middleware/immer"; interface ArmBotStore { - armBots: ArmBotStatus[]; + armBots: ArmBotStatus[]; - addArmBot: (productId: string, event: RoboticArmEventSchema) => void; - removeArmBot: (modelUuid: string) => void; - updateArmBot: ( - modelUuid: string, - updates: Partial> - ) => void; + addArmBot: (productId: string, event: RoboticArmEventSchema) => void; + removeArmBot: (modelUuid: string) => void; - addCurrentAction: (modelUuid: string, actionUuid: string) => void; - removeCurrentAction: (modelUuid: string) => void; + updateArmBot: ( + modelUuid: string, + updates: Partial> + ) => void; - addAction: (modelUuid: string, action: RoboticArmPointSchema['actions'][number]) => void; - removeAction: (modelUuid: string, actionUuid: string) => void; + addCurrentAction: (modelUuid: string, actionUuid: string) => void; + removeCurrentAction: (modelUuid: string) => void; - setArmBotActive: (modelUuid: string, isActive: boolean) => void; + addAction: ( + modelUuid: string, + action: RoboticArmPointSchema["actions"][number] + ) => void; + removeAction: (modelUuid: string, actionUuid: string) => void; - incrementActiveTime: (modelUuid: string, incrementBy: number) => void; - incrementIdleTime: (modelUuid: string, incrementBy: number) => void; + setArmBotActive: (modelUuid: string, isActive: boolean) => void; - getArmBotById: (modelUuid: string) => ArmBotStatus | undefined; - getArmBotsByProduct: (productId: string) => ArmBotStatus[]; - getArmBotsByState: (state: string) => ArmBotStatus[]; - getActiveArmBots: () => ArmBotStatus[]; - getIdleArmBots: () => ArmBotStatus[]; - getArmBotsByCurrentAction: (actionUuid: string) => ArmBotStatus[]; + incrementActiveTime: (modelUuid: string, incrementBy: number) => void; + incrementIdleTime: (modelUuid: string, incrementBy: number) => void; + + getArmBotById: (modelUuid: string) => ArmBotStatus | undefined; + getArmBotsByProduct: (productId: string) => ArmBotStatus[]; + getArmBotsByState: (state: string) => ArmBotStatus[]; + getActiveArmBots: () => ArmBotStatus[]; + getIdleArmBots: () => ArmBotStatus[]; + getArmBotsByCurrentAction: (actionUuid: string) => ArmBotStatus[]; } export const useArmBotStore = create()( - immer((set, get) => ({ - armBots: [], + immer((set, get) => ({ + armBots: [], - addArmBot: (productId, event) => { - set((state) => { - state.armBots.push({ - ...event, - productId, - isActive: false, - idleTime: 0, - activeTime: 0, - state: 'idle', - }); - }); - }, + addArmBot: (productId, event) => { + set((state) => { + state.armBots.push({ + ...event, + productId, + isActive: false, + idleTime: 0, + activeTime: 0, + state: "idle", + }); + }); + }, - removeArmBot: (modelUuid) => { - set((state) => { - state.armBots = state.armBots.filter(a => a.modelUuid !== modelUuid); - }); - }, + removeArmBot: (modelUuid) => { + set((state) => { + state.armBots = state.armBots.filter((a) => a.modelUuid !== modelUuid); + }); + }, - updateArmBot: (modelUuid, updates) => { - set((state) => { - const armBot = state.armBots.find(a => a.modelUuid === modelUuid); - if (armBot) { - Object.assign(armBot, updates); - } - }); - }, - - addCurrentAction: (modelUuid, actionUuid) => { - set((state) => { - const armBot = state.armBots.find(a => a.modelUuid === modelUuid); - if (armBot) { - const action = armBot.point.actions.find(a => a.actionUuid === actionUuid); - if (action) { - armBot.currentAction = { - actionUuid: action.actionUuid, - actionName: action.actionName, - }; - armBot.isActive = true; - } - } - }); - }, - - removeCurrentAction: (modelUuid) => { - set((state) => { - const armBot = state.armBots.find(a => a.modelUuid === modelUuid); - if (armBot) { - armBot.currentAction = undefined; - armBot.isActive = false; - } - }); - }, - - addAction: (modelUuid, action) => { - set((state) => { - const armBot = state.armBots.find(a => a.modelUuid === modelUuid); - if (armBot) { - armBot.point.actions.push(action); - } - }); - }, - - removeAction: (modelUuid, actionUuid) => { - set((state) => { - const armBot = state.armBots.find(a => a.modelUuid === modelUuid); - if (armBot) { - armBot.point.actions = armBot.point.actions.filter(a => a.actionUuid !== actionUuid); - } - }); - }, - - setArmBotActive: (modelUuid, isActive) => { - set((state) => { - const armBot = state.armBots.find(a => a.modelUuid === modelUuid); - if (armBot) { - armBot.isActive = isActive; - } - }); - }, - - incrementActiveTime: (modelUuid, incrementBy) => { - set((state) => { - const armBot = state.armBots.find(a => a.modelUuid === modelUuid); - if (armBot) { - armBot.activeTime += incrementBy; - } - }); - }, - - incrementIdleTime: (modelUuid, incrementBy) => { - set((state) => { - const armBot = state.armBots.find(a => a.modelUuid === modelUuid); - if (armBot) { - armBot.idleTime += incrementBy; - } - }); - }, - - getArmBotById: (modelUuid) => { - return get().armBots.find(a => a.modelUuid === modelUuid); - }, - - getArmBotsByProduct: (productId) => { - return get().armBots.filter(a => a.productId === productId); - }, - - getArmBotsByState: (state) => { - return get().armBots.filter(a => a.state === state); - }, - - getActiveArmBots: () => { - return get().armBots.filter(a => a.isActive); - }, - - getIdleArmBots: () => { - return get().armBots.filter(a => !a.isActive && a.state === 'idle'); - }, - - getArmBotsByCurrentAction: (actionUuid) => { - return get().armBots.filter(a => a.currentAction?.actionUuid === actionUuid); + updateArmBot: (modelUuid, updates) => { + set((state) => { + const armBot = state.armBots.find((a) => a.modelUuid === modelUuid); + if (armBot) { + Object.assign(armBot, updates); } - })) + }); + }, + + addCurrentAction: (modelUuid, actionUuid) => { + set((state) => { + const armBot = state.armBots.find((a) => a.modelUuid === modelUuid); + if (armBot) { + const action = armBot.point.actions.find( + (a) => a.actionUuid === actionUuid + ); + if (action) { + armBot.currentAction = { + actionUuid: action.actionUuid, + actionName: action.actionName, + }; + armBot.isActive = true; + } + } + }); + }, + + removeCurrentAction: (modelUuid) => { + set((state) => { + const armBot = state.armBots.find((a) => a.modelUuid === modelUuid); + if (armBot) { + armBot.currentAction = undefined; + armBot.isActive = false; + } + }); + }, + + addAction: (modelUuid, action) => { + set((state) => { + const armBot = state.armBots.find((a) => a.modelUuid === modelUuid); + if (armBot) { + armBot.point.actions.push(action); + } + }); + }, + + removeAction: (modelUuid, actionUuid) => { + set((state) => { + const armBot = state.armBots.find((a) => a.modelUuid === modelUuid); + if (armBot) { + armBot.point.actions = armBot.point.actions.filter( + (a) => a.actionUuid !== actionUuid + ); + } + }); + }, + + setArmBotActive: (modelUuid, isActive) => { + set((state) => { + const armBot = state.armBots.find((a) => a.modelUuid === modelUuid); + if (armBot) { + armBot.isActive = isActive; + } + }); + }, + + incrementActiveTime: (modelUuid, incrementBy) => { + set((state) => { + const armBot = state.armBots.find((a) => a.modelUuid === modelUuid); + if (armBot) { + armBot.activeTime += incrementBy; + } + }); + }, + + incrementIdleTime: (modelUuid, incrementBy) => { + set((state) => { + const armBot = state.armBots.find((a) => a.modelUuid === modelUuid); + if (armBot) { + armBot.idleTime += incrementBy; + } + }); + }, + + getArmBotById: (modelUuid) => { + return get().armBots.find((a) => a.modelUuid === modelUuid); + }, + + getArmBotsByProduct: (productId) => { + return get().armBots.filter((a) => a.productId === productId); + }, + + getArmBotsByState: (state) => { + return get().armBots.filter((a) => a.state === state); + }, + + getActiveArmBots: () => { + return get().armBots.filter((a) => a.isActive); + }, + + getIdleArmBots: () => { + return get().armBots.filter((a) => !a.isActive && a.state === "idle"); + }, + + getArmBotsByCurrentAction: (actionUuid) => { + return get().armBots.filter( + (a) => a.currentAction?.actionUuid === actionUuid + ); + }, + })) ); From a305c3c00635bdced28b15149e52bfdc81a94d1b Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Thu, 24 Apr 2025 16:38:42 +0530 Subject: [PATCH 02/13] Refactor EventProperties component to utilize new state management for selected event data and asset selection; implement action handling based on asset type and improve action rendering logic. Enhance Simulations component to support adding and removing events from products; integrate new asset selection store for better state management. Fix import paths in Design component and related files to ensure correct module resolution. Update Tools component to correct import paths for template saving functionality. Refactor EditWidgetOption component to simplify option handling and remove unnecessary state management. Add new mechanics components for various asset types (Conveyor, Machine, Robotic Arm, Storage, Vehicle) as placeholders for future implementation. Implement Trigger and TriggerConnector components to manage right-click interactions and asset selection in the simulation environment. Enhance product store with new helper functions for event and action retrieval based on UUIDs. Introduce new selected event data and asset state management in the simulation store for improved event handling. Update simulation types to include new action types and improve type definitions for better type safety. Remove obsolete temp markdown file from triggers directory. --- .../layout/sidebarLeft/SideBarLeft.tsx | 4 +- .../visualization/widgets/WidgetsFloating.tsx | 8 +- .../layout/sidebarRight/SideBarRight.tsx | 277 +++++------ .../eventProperties/EventProperties.tsx | 435 ++++++++++-------- .../mechanics/conveyorMechanics.tsx | 10 + .../mechanics/machineMechanics.tsx | 10 + .../mechanics/roboticArmMechanics.tsx | 10 + .../mechanics/storageMechanics.tsx | 10 + .../mechanics/vehicleMechanics.tsx | 10 + .../sidebarRight/simulation/Simulations.tsx | 46 +- .../visualization/design/Design.tsx | 4 +- app/src/components/ui/Tools.tsx | 2 +- .../components/ui/menu/EditWidgetOption.tsx | 12 +- app/src/modules/builder/builder.tsx | 2 +- .../events/points/creator/pointsCreator.tsx | 21 +- .../modules/simulation/products/products.tsx | 7 +- app/src/modules/simulation/simulation.tsx | 35 +- .../triggers/connector/triggerConnector.tsx | 126 +++++ app/src/modules/simulation/triggers/temp.md | 0 .../modules/simulation/triggers/trigger.tsx | 14 + .../visualization/RealTimeVisulization.tsx | 6 +- .../visulization/zone/getSelect2dZoneData.ts | 2 +- app/src/store/simulation/useProductStore.ts | 88 ++++ .../store/simulation/useSimulationStore.ts | 44 ++ app/src/store/useModuleStore.ts | 9 +- app/src/types/simulationTypes.d.ts | 4 +- 26 files changed, 813 insertions(+), 383 deletions(-) create mode 100644 app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/conveyorMechanics.tsx create mode 100644 app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/machineMechanics.tsx create mode 100644 app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/roboticArmMechanics.tsx create mode 100644 app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx create mode 100644 app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/vehicleMechanics.tsx create mode 100644 app/src/modules/simulation/triggers/connector/triggerConnector.tsx delete mode 100644 app/src/modules/simulation/triggers/temp.md create mode 100644 app/src/modules/simulation/triggers/trigger.tsx diff --git a/app/src/components/layout/sidebarLeft/SideBarLeft.tsx b/app/src/components/layout/sidebarLeft/SideBarLeft.tsx index dc412f7..e0b56d4 100644 --- a/app/src/components/layout/sidebarLeft/SideBarLeft.tsx +++ b/app/src/components/layout/sidebarLeft/SideBarLeft.tsx @@ -5,8 +5,8 @@ import Header from "./Header"; import useToggleStore from "../../../store/useUIToggleStore"; import Assets from "./Assets"; import useModuleStore from "../../../store/useModuleStore"; -import Widgets from ".//visualization/widgets/Widgets"; -import Templates from "../../../modules//visualization/template/Templates"; +import Widgets from "./visualization/widgets/Widgets"; +import Templates from "../../../modules/visualization/template/Templates"; import Search from "../../ui/inputs/Search"; const SideBarLeft: React.FC = () => { diff --git a/app/src/components/layout/sidebarLeft/visualization/widgets/WidgetsFloating.tsx b/app/src/components/layout/sidebarLeft/visualization/widgets/WidgetsFloating.tsx index 50d9712..b5ae0bb 100644 --- a/app/src/components/layout/sidebarLeft/visualization/widgets/WidgetsFloating.tsx +++ b/app/src/components/layout/sidebarLeft/visualization/widgets/WidgetsFloating.tsx @@ -5,11 +5,11 @@ import { GlobeIcon, WalletIcon, } from "../../../../icons/3dChartIcons"; -import SimpleCard from "../../../../../modules//visualization/widgets/floating/cards/SimpleCard"; +import SimpleCard from "../../../../../modules/visualization/widgets/floating/cards/SimpleCard"; -import WarehouseThroughput from "../../../../../modules//visualization/widgets/floating/cards/WarehouseThroughput"; -import ProductivityDashboard from "../../../../../modules//visualization/widgets/floating/cards/ProductivityDashboard"; -import FleetEfficiency from "../../../../../modules//visualization/widgets/floating/cards/FleetEfficiency"; +import WarehouseThroughput from "../../../../../modules/visualization/widgets/floating/cards/WarehouseThroughput"; +import ProductivityDashboard from "../../../../../modules/visualization/widgets/floating/cards/ProductivityDashboard"; +import FleetEfficiency from "../../../../../modules/visualization/widgets/floating/cards/FleetEfficiency"; interface Widget { id: string; diff --git a/app/src/components/layout/sidebarRight/SideBarRight.tsx b/app/src/components/layout/sidebarRight/SideBarRight.tsx index b13944c..f5668bf 100644 --- a/app/src/components/layout/sidebarRight/SideBarRight.tsx +++ b/app/src/components/layout/sidebarRight/SideBarRight.tsx @@ -1,173 +1,148 @@ -import React, { useEffect, useState } from "react"; +import React, { useEffect } from "react"; import Header from "./Header"; import useModuleStore, { - useSubModuleStore, + useSubModuleStore, } from "../../../store/useModuleStore"; import { - AnalysisIcon, - MechanicsIcon, - PropertiesIcon, - SimulationIcon, + AnalysisIcon, + MechanicsIcon, + PropertiesIcon, + SimulationIcon, } from "../../icons/SimulationIcons"; import useToggleStore from "../../../store/useUIToggleStore"; import Visualization from "./visualization/Visualization"; import Analysis from "./analysis/Analysis"; import Simulations from "./simulation/Simulations"; import { useSelectedFloorItem } from "../../../store/store"; +import { useSelectedEventData, useSelectedEventSphere } from "../../../store/simulation/useSimulationStore"; import GlobalProperties from "./properties/GlobalProperties"; import AsstePropertiies from "./properties/AssetProperties"; import ZoneProperties from "./properties/ZoneProperties"; import EventProperties from "./properties/eventProperties/EventProperties"; const SideBarRight: React.FC = () => { - const { activeModule } = useModuleStore(); - const { toggleUI } = useToggleStore(); - const { subModule, setSubModule } = useSubModuleStore(); - const { selectedFloorItem } = useSelectedFloorItem(); + const { activeModule } = useModuleStore(); + const { toggleUI } = useToggleStore(); + const { subModule, setSubModule } = useSubModuleStore(); + const { selectedFloorItem } = useSelectedFloorItem(); + const { selectedEventData } = useSelectedEventData(); + const { selectedEventSphere } = useSelectedEventSphere(); - // Reset activeList whenever activeModule changes - useEffect(() => { - if (activeModule !== "simulation") setSubModule("properties"); - if (activeModule === "simulation") setSubModule("mechanics"); - }, [activeModule]); + // Reset activeList whenever activeModule changes + useEffect(() => { + if (activeModule !== "simulation") setSubModule("properties"); + if (activeModule === "simulation") setSubModule("simulations"); + }, [activeModule]); - // romove late - const dummyData = { - assetType: "store", - selectedPoint: { - name: "Point A", - uuid: "123e4567-e89b-12d3-a456-426614174000", - actions: [ - { - uuid: "action-1", - name: "Action One", - }, - { - uuid: "action-2", - name: "Action Two", - }, - { - uuid: "action-3", - name: "Action Three", - }, - ], - }, - selectedItem: { - item: { - uuid: "item-1", - name: "Item One", - isUsed: false, - }, - }, - setSelectedPoint: (value: string) => { - console.log(`Selected point updated to: ${value}`); - }, - selectedActionSphere: "Sphere A", - }; + useEffect(() => { + if (activeModule !== "mechanics" && selectedEventData && selectedEventSphere) { + setSubModule("mechanics"); + } else { + if (activeModule === 'simulation') { + setSubModule("simulations"); + } + }; + }, [activeModule, selectedEventData, selectedEventSphere]) - return ( -
-
- {toggleUI && ( -
- {/* {activeModule === "builder" && ( */} -
setSubModule("properties")} - > - -
- {/* )} */} - {activeModule === "simulation" && ( - <> -
setSubModule("mechanics")} - > - -
-
setSubModule("simulations")} - > - -
-
setSubModule("analysis")} - > - -
- - )} + return ( +
+
+ {toggleUI && ( +
+
setSubModule("properties")} + > + +
+ {activeModule === "simulation" && ( + <> +
setSubModule("mechanics")} + > + +
+
setSubModule("simulations")} + > + +
+
setSubModule("analysis")} + > + +
+ + )} +
+ )} + {/* process builder */} + {toggleUI && + subModule === "properties" && + activeModule !== "visualization" && + !selectedFloorItem && ( +
+
+ +
+
+ )} + {toggleUI && + subModule === "properties" && + activeModule !== "visualization" && + selectedFloorItem && ( +
+
+ +
+
+ )} + {toggleUI && + subModule === "zoneProperties" && + (activeModule === "builder" || activeModule === "simulation") && ( +
+
+ +
+
+ )} + {/* simulation */} + {toggleUI && activeModule === "simulation" && ( + <> + {subModule === "simulations" && ( +
+
+ +
+
+ )} + {subModule === "mechanics" && selectedEventData && selectedEventSphere && ( +
+
+ +
+
+ )} + {subModule === "analysis" && ( +
+
+ +
+
+ )} + + )} + {/* realtime visualization */} + {toggleUI && activeModule === "visualization" && }
- )} - {/* process builder */} - {toggleUI && - subModule === "properties" && - activeModule !== "visualization" && - !selectedFloorItem && ( -
-
- -
-
- )} - {toggleUI && - subModule === "properties" && - activeModule !== "visualization" && - selectedFloorItem && ( -
-
- -
-
- )} - {toggleUI && - subModule === "zoneProperties" && - (activeModule === "builder" || activeModule === "simulation") && ( -
-
- -
-
- )} - {/* simulation */} - - {toggleUI && activeModule === "simulation" && ( - <> - {subModule === "mechanics" && ( -
-
- -
-
- )} - {subModule === "analysis" && ( -
-
- -
-
- )} - {subModule === "simulations" && ( -
-
- -
-
- )} - - )} - - {/* realtime visualization */} - {toggleUI && activeModule === "visualization" && } -
- ); + ); }; -export default SideBarRight; +export default SideBarRight; \ No newline at end of file diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx index c3ec6e7..6c44947 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx @@ -1,10 +1,10 @@ -import React, { useRef, useState } from "react"; +import React, { useEffect, useRef, useState } from "react"; import InputWithDropDown from "../../../../ui/inputs/InputWithDropDown"; import LabledDropdown from "../../../../ui/inputs/LabledDropdown"; import { - AddIcon, - RemoveIcon, - ResizeHeightIcon, + AddIcon, + RemoveIcon, + ResizeHeightIcon, } from "../../../../icons/ExportCommonIcons"; import RenameInput from "../../../../ui/inputs/RenameInput"; import { handleResize } from "../../../../../functions/handleResizePannel"; @@ -20,191 +20,260 @@ import ProcessAction from "./actions/ProcessAction"; import StorageAction from "./actions/StorageAction"; import Trigger from "./trigger/Trigger"; -interface EventPropertiesProps { - assetType: string; - selectedPoint: { - name: string; - uuid: string; - actions: { - uuid: string; - name: string; - }[]; - }; - selectedItem: { - item: { - uuid: string; - name: string; - } | null; - }; - setSelectedPoint: (value: string) => void; - selectedActionSphere: string; -} +import { useSelectedEventData, useSelectedProduct } from "../../../../../store/simulation/useSimulationStore"; +import { useProductStore } from "../../../../../store/simulation/useProductStore"; -const EventProperties: React.FC = ({ - assetType, - selectedPoint, - selectedItem, - setSelectedPoint, - selectedActionSphere, -}) => { - const actionsContainerRef = useRef(null); +const EventProperties: React.FC = () => { + const actionsContainerRef = useRef(null); - const [activeOption, setActiveOption] = useState("default"); - const [dummyactiveOption, setTypeOption] = useState("default"); + const [activeOption, setActiveOption] = useState("default"); + const [selectedItem, setSelectedItem] = useState<{ item: { uuid: string; name: string } | null; }>({ item: null }); + const { selectedEventData } = useSelectedEventData(); + const { getEventByModelUuid } = useProductStore(); + const { selectedProduct } = useSelectedProduct(); - const getAvailableActions = () => { - if (assetType === "conveyor") { - return { - defaultOption: "default", - options: ["default", "spawn", "swap", "despawn"], - }; - } - if (assetType === "vehicle") { - return { - defaultOption: "travel", - options: ["travel"], - }; - } - if (assetType === "roboticArm") { - return { - defaultOption: "pickAndPlace", - options: ["pickAndPlace"], - }; - } - if (assetType === "machine") { - return { - defaultOption: "process", - options: ["process"], - }; - } - if (assetType === "store") { - return { - defaultOption: "store", - options: ["store", "spawn"], - }; - } else { - return { - defaultOption: "default", - options: ["default"], - }; - } - }; + useEffect(() => { + const actions = getActions(); + if (actions.length > 0 && !selectedItem.item) { + setSelectedItem({ item: actions[0] }); + } + }, [selectedEventData]); - return ( -
-
-
{selectedPoint.name}
-
-
-
- {/*
- setTypeOption(option)} - /> -
*/} -
- {}} - onChange={(value) => console.log(value)} - /> -
-
- {}} - onChange={(value) => console.log(value)} - /> -
-
-
-
-
-
-
Actions
-
{}}> - Add -
-
-
-
- {selectedPoint?.actions.map((action) => ( -
-
handleActionToggle(action.uuid)} - > - -
- {selectedPoint?.actions.length > 1 && ( -
handleDeleteAction(action.uuid)} - > - + const getCurrentEventData = () => { + if (!selectedEventData?.data || !selectedProduct) return null; + const event = getEventByModelUuid(selectedProduct.productId, selectedEventData.data.modelUuid); + return event || null; + }; + + const getAssetType = () => { + const event = getCurrentEventData(); + if (!event) return null; + + switch (event.type) { + case 'transfer': return 'conveyor'; + case 'vehicle': return 'vehicle'; + case 'roboticArm': return 'roboticArm'; + case 'machine': return 'machine'; + case 'storageUnit': return 'storageUnit'; + default: return null; + } + }; + + const getAvailableActions = () => { + switch (getAssetType()) { + case "conveyor": + return { + defaultOption: "default", + options: ["default", "spawn", "swap", "despawn"], + }; + case "vehicle": + return { + defaultOption: "travel", + options: ["travel"], + }; + case "roboticArm": + return { + defaultOption: "pickAndPlace", + options: ["pickAndPlace"], + }; + case "machine": + return { + defaultOption: "process", + options: ["process"], + }; + case "storageUnit": + return { + defaultOption: "store", + options: ["store", "spawn"], + }; + default: + return { + defaultOption: "default", + options: ["default"], + }; + } + }; + + // Get actions based on asset type + const getActions = () => { + if (!selectedEventData?.data) return []; + + const event = selectedEventData.data; + switch (getAssetType()) { + case "conveyor": + return (event as ConveyorEventSchema).points + .find((point) => point.uuid === selectedEventData?.selectedPoint) + ?.action?.triggers.map((trigger) => ({ + uuid: trigger.triggerUuid, + name: trigger.triggerName, + })) || []; + case "vehicle": + return (event as VehicleEventSchema).point.action.triggers.map( + (trigger) => ({ + uuid: trigger.triggerUuid, + name: trigger.triggerName, + }) + ) || []; + case "roboticArm": + return (event as RoboticArmEventSchema).point.actions.flatMap( + (action) => + action.triggers.map((trigger) => ({ + uuid: trigger.triggerUuid, + name: trigger.triggerName, + })) + ) || []; + case "machine": + return (event as MachineEventSchema).point.action.triggers.map( + (trigger) => ({ + uuid: trigger.triggerUuid, + name: trigger.triggerName, + }) + ) || []; + case "storageUnit": + return [ + { + uuid: (event as StorageEventSchema).point.action.actionUuid, + name: (event as StorageEventSchema).point.action.actionName, + }, + ]; + default: + return []; + } + }; + + const handleActionToggle = (actionUuid: string) => { + const actions = getActions(); + const selected = actions.find(action => action.uuid === actionUuid); + if (selected) { + setSelectedItem({ item: selected }); + } + }; + + const handleDeleteAction = (actionUuid: string) => { + + }; + + const actions = getActions(); + + const getSpeed = () => { + if (!selectedEventData) return "0.5"; + if ("speed" in selectedEventData.data) return selectedEventData.data.speed.toString(); + return "0.5"; + }; + + return ( + <> + {getCurrentEventData() && +
+
+
{selectedEventData?.data.modelName}
+
+
+
+
+ { }} + onChange={(value) => console.log(value)} + /> +
+ +
+ { }} + onChange={(value) => console.log(value)} + /> +
+
+
+ {getAssetType() === 'roboticArm' && +
+
+
+
Actions
+
{ }}> + Add +
+
+
+
+ {actions.map((action) => ( +
+
handleActionToggle(action.uuid)} + > + +
+ {actions.length > 1 && ( +
handleDeleteAction(action.uuid)} + > + +
+ )} +
+ ))} +
+
handleResize(e, actionsContainerRef)} + > + +
+
+
+
+ } +
+
+ +
+
+ setActiveOption(option)} + /> + {activeOption === "default" && } + {activeOption === "spawn" && } + {activeOption === "swap" && } + {activeOption === "despawn" && } + {activeOption === "travel" && } + {activeOption === "pickAndPlace" && } + {activeOption === "process" && } + {activeOption === "store" && } +
+
+
+
- )}
- ))} -
-
handleResize(e, actionsContainerRef)} - > - -
-
-
-
-
-
- -
-
- setActiveOption(option)} - /> - {activeOption === "default" && } {/* done */} - {activeOption === "spawn" && } {/* done */} - {activeOption === "swap" && } {/* done */} - {activeOption === "despawn" && } {/* done */} - {activeOption === "travel" && } {/* done */} - {activeOption === "pickAndPlace" && } {/* done */} - {activeOption === "process" && } {/* done */} - {activeOption === "store" && } {/* done */} -
-
-
- -
-
- ); + } + + ); }; export default EventProperties; diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/conveyorMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/conveyorMechanics.tsx new file mode 100644 index 0000000..000a9d7 --- /dev/null +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/conveyorMechanics.tsx @@ -0,0 +1,10 @@ +import React from 'react' + +function ConveyorMechanics() { + return ( + <> + + ) +} + +export default ConveyorMechanics \ No newline at end of file diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/machineMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/machineMechanics.tsx new file mode 100644 index 0000000..b6e4fb9 --- /dev/null +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/machineMechanics.tsx @@ -0,0 +1,10 @@ +import React from 'react' + +function MachineMechanics() { + return ( + <> + + ) +} + +export default MachineMechanics \ No newline at end of file diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/roboticArmMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/roboticArmMechanics.tsx new file mode 100644 index 0000000..56e4c27 --- /dev/null +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/roboticArmMechanics.tsx @@ -0,0 +1,10 @@ +import React from 'react' + +function RoboticArmMechanics() { + return ( + <> + + ) +} + +export default RoboticArmMechanics \ No newline at end of file diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx new file mode 100644 index 0000000..0cda40e --- /dev/null +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx @@ -0,0 +1,10 @@ +import React from 'react' + +function StorageMechanics() { + return ( + <> + + ) +} + +export default StorageMechanics \ No newline at end of file diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/vehicleMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/vehicleMechanics.tsx new file mode 100644 index 0000000..cdb32c4 --- /dev/null +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/vehicleMechanics.tsx @@ -0,0 +1,10 @@ +import React from 'react' + +function VehicleMechanics() { + return ( + <> + + ) +} + +export default VehicleMechanics \ No newline at end of file diff --git a/app/src/components/layout/sidebarRight/simulation/Simulations.tsx b/app/src/components/layout/sidebarRight/simulation/Simulations.tsx index cbb19fa..12a424c 100644 --- a/app/src/components/layout/sidebarRight/simulation/Simulations.tsx +++ b/app/src/components/layout/sidebarRight/simulation/Simulations.tsx @@ -7,9 +7,11 @@ import { } from "../../../icons/ExportCommonIcons"; import RenameInput from "../../../ui/inputs/RenameInput"; import { handleResize } from "../../../../functions/handleResizePannel"; -import { useSelectedProduct } from "../../../../store/simulation/useSimulationStore"; +import { useSelectedAsset, useSelectedProduct } from "../../../../store/simulation/useSimulationStore"; import { useProductStore } from "../../../../store/simulation/useProductStore"; import { generateUUID } from "three/src/math/MathUtils"; +import RenderOverlay from "../../../templates/Overlay"; +import EditWidgetOption from "../../../ui/menu/EditWidgetOption"; interface Event { pathName: string; @@ -31,14 +33,9 @@ const List: React.FC = ({ val }) => { const Simulations: React.FC = () => { const productsContainerRef = useRef(null); - const { products, addProduct, removeProduct, renameProduct } = useProductStore(); + const { products, addProduct, removeProduct, renameProduct, addEvent, removeEvent } = useProductStore(); const { selectedProduct, setSelectedProduct } = useSelectedProduct(); - - useEffect(() => { - if (products.length > 0 && selectedProduct.productId === '' && selectedProduct.productName === '') { - setSelectedProduct(products[0].productId, products[0].productName); - } - }, [products, selectedProduct]); + const { selectedAsset, clearSelectedAsset } = useSelectedAsset(); const handleAddProduct = () => { addProduct(`Product ${products.length + 1}`, generateUUID()); @@ -75,12 +72,26 @@ const Simulations: React.FC = () => { } }; + const handleAddEventToProduct = () => { + if (selectedAsset) { + addEvent(selectedProduct.productId, selectedAsset); + clearSelectedAsset(); + } + }; + + const handleRemoveEventFromProduct = () => { + if (selectedAsset) { + removeEvent(selectedProduct.productId, selectedAsset.modelUuid); + clearSelectedAsset(); + } + }; + const selectedProductData = products.find( (product) => product.productId === selectedProduct.productId ); - const events: Event[] = selectedProductData?.eventsData.map((event, index) => ({ - pathName: `${event.modelName} - ${event.type} #${index + 1}`, + const events: Event[] = selectedProductData?.eventsData.map((event) => ({ + pathName: event.modelName, })) || []; return ( @@ -165,6 +176,21 @@ const Simulations: React.FC = () => {
+ + {selectedAsset && + + { + if (option === 'Add to Product') { + handleAddEventToProduct(); + } else { + handleRemoveEventFromProduct(); + } + }} + /> + + } ); }; diff --git a/app/src/components/layout/sidebarRight/visualization/design/Design.tsx b/app/src/components/layout/sidebarRight/visualization/design/Design.tsx index 04a569a..234b936 100644 --- a/app/src/components/layout/sidebarRight/visualization/design/Design.tsx +++ b/app/src/components/layout/sidebarRight/visualization/design/Design.tsx @@ -1,9 +1,9 @@ import { useState, useEffect, useRef } from "react"; import { useWidgetStore } from "../../../../../store/useWidgetStore"; -import ChartComponent from "../../../sidebarLeft//visualization/widgets/ChartComponent"; +import ChartComponent from "../../../sidebarLeft/visualization/widgets/ChartComponent"; import RegularDropDown from "../../../../ui/inputs/RegularDropDown"; import { WalletIcon } from "../../../../icons/3dChartIcons"; -import SimpleCard from "../../../../../modules//visualization/widgets/floating/cards/SimpleCard"; +import SimpleCard from "../../../../../modules/visualization/widgets/floating/cards/SimpleCard"; interface Widget { id: string; diff --git a/app/src/components/ui/Tools.tsx b/app/src/components/ui/Tools.tsx index 70b1461..21ea6a7 100644 --- a/app/src/components/ui/Tools.tsx +++ b/app/src/components/ui/Tools.tsx @@ -15,7 +15,7 @@ import { } from "../icons/ExportToolsIcons"; import { ArrowIcon, TickIcon } from "../icons/ExportCommonIcons"; import useModuleStore, { useThreeDStore } from "../../store/useModuleStore"; -import { handleSaveTemplate } from "../../modules//visualization/functions/handleSaveTemplate"; +import { handleSaveTemplate } from "../../modules/visualization/functions/handleSaveTemplate"; import { usePlayButtonStore } from "../../store/usePlayButtonStore"; import useTemplateStore from "../../store/useTemplateStore"; import { useSelectedZoneStore } from "../../store/visualization/useZoneStore"; diff --git a/app/src/components/ui/menu/EditWidgetOption.tsx b/app/src/components/ui/menu/EditWidgetOption.tsx index 6fd1e94..eb937c8 100644 --- a/app/src/components/ui/menu/EditWidgetOption.tsx +++ b/app/src/components/ui/menu/EditWidgetOption.tsx @@ -1,23 +1,20 @@ import React, { useEffect } from "react"; import { - useEditWidgetOptionsStore, useLeftData, - useRightClickSelected, - useRightSelected, useTopData, } from "../../../store/visualization/useZone3DWidgetStore"; interface EditWidgetOptionProps { options: string[]; + onClick: (option: string) => void; } const EditWidgetOption: React.FC = ({ options, + onClick }) => { const { top } = useTopData(); const { left } = useLeftData(); - const { setRightSelect } = useRightSelected(); - const { setEditWidgetOptions } = useEditWidgetOptionsStore(); useEffect(() => { @@ -38,10 +35,7 @@ const EditWidgetOption: React.FC = ({
{ - setRightSelect(option); - setEditWidgetOptions(false); - }} + onClick={() => onClick(option)} > {option}
diff --git a/app/src/modules/builder/builder.tsx b/app/src/modules/builder/builder.tsx index e7f83e2..e5ff1c1 100644 --- a/app/src/modules/builder/builder.tsx +++ b/app/src/modules/builder/builder.tsx @@ -51,7 +51,7 @@ import Ground from "../scene/environment/ground"; // import ZoneGroup from "../groups/zoneGroup1"; import { findEnvironment } from "../../services/factoryBuilder/environment/findEnvironment"; import Layer2DVisibility from "./geomentries/layers/layer2DVisibility"; -import DrieHtmlTemp from "..//visualization/mqttTemp/drieHtmlTemp"; +import DrieHtmlTemp from "../visualization/mqttTemp/drieHtmlTemp"; import ZoneGroup from "./groups/zoneGroup"; import useModuleStore from "../../store/useModuleStore"; import MeasurementTool from "../scene/tools/measurementTool"; diff --git a/app/src/modules/simulation/events/points/creator/pointsCreator.tsx b/app/src/modules/simulation/events/points/creator/pointsCreator.tsx index 8baacd9..1b3defa 100644 --- a/app/src/modules/simulation/events/points/creator/pointsCreator.tsx +++ b/app/src/modules/simulation/events/points/creator/pointsCreator.tsx @@ -4,15 +4,32 @@ import { useEventsStore } from '../../../../../store/simulation/useEventsStore'; import useModuleStore from '../../../../../store/useModuleStore'; import { TransformControls } from '@react-three/drei'; import { detectModifierKeys } from '../../../../../utils/shortcutkeys/detectModifierKeys'; -import { useSelectedEventSphere } from '../../../../../store/simulation/useSimulationStore'; +import { useSelectedEventSphere, useSelectedEventData } from '../../../../../store/simulation/useSimulationStore'; function PointsCreator() { - const { events, updatePoint, getPointByUuid } = useEventsStore(); + const { events, updatePoint, getPointByUuid, getEventByModelUuid } = useEventsStore(); const { activeModule } = useModuleStore(); const transformRef = useRef(null); const [transformMode, setTransformMode] = useState<"translate" | "rotate" | null>(null); const sphereRefs = useRef<{ [key: string]: THREE.Mesh }>({}); const { selectedEventSphere, setSelectedEventSphere, clearSelectedEventSphere } = useSelectedEventSphere(); + const { setSelectedEventData, clearSelectedEventData } = useSelectedEventData(); + + useEffect(() => { + if (selectedEventSphere) { + const eventData = getEventByModelUuid(selectedEventSphere.userData.modelUuid); + if (eventData) { + setSelectedEventData( + eventData, + selectedEventSphere.userData.pointUuid + ); + } else { + clearSelectedEventData(); + } + } else { + clearSelectedEventData(); + } + }, [selectedEventSphere]); useEffect(() => { const handleKeyDown = (e: KeyboardEvent) => { diff --git a/app/src/modules/simulation/products/products.tsx b/app/src/modules/simulation/products/products.tsx index 2e9a16e..2ddd7d1 100644 --- a/app/src/modules/simulation/products/products.tsx +++ b/app/src/modules/simulation/products/products.tsx @@ -1,13 +1,18 @@ import React, { useEffect } from 'react' import { useProductStore } from '../../../store/simulation/useProductStore' import * as THREE from 'three'; +import { useSelectedProduct } from '../../../store/simulation/useSimulationStore'; function Products() { const { products, addProduct } = useProductStore(); + const { setSelectedProduct } = useSelectedProduct(); useEffect(() => { if (products.length === 0) { - addProduct('Product 1', THREE.MathUtils.generateUUID()); + const id = THREE.MathUtils.generateUUID(); + const name = 'Product 1'; + addProduct(name, id); + setSelectedProduct(id, name); } }, [products]) diff --git a/app/src/modules/simulation/simulation.tsx b/app/src/modules/simulation/simulation.tsx index f02b066..4197716 100644 --- a/app/src/modules/simulation/simulation.tsx +++ b/app/src/modules/simulation/simulation.tsx @@ -10,39 +10,52 @@ import Machine from './machine/machine'; import StorageUnit from './storageUnit/storageUnit'; import Simulator from './simulator/simulator'; import Products from './products/products'; +import Trigger from './triggers/trigger'; +import useModuleStore from '../../store/useModuleStore'; function Simulation() { + const { activeModule } = useModuleStore(); const { events } = useEventsStore(); const { products } = useProductStore(); useEffect(() => { - console.log('events: ', events); + // console.log('events: ', events); }, [events]) useEffect(() => { - // console.log('products: ', products); + console.log('products: ', products); }, [products]) return ( <> - + {activeModule === 'simulation' && - + <> - + - + - + - + - + - + - + + + + + + + + + + + } ) diff --git a/app/src/modules/simulation/triggers/connector/triggerConnector.tsx b/app/src/modules/simulation/triggers/connector/triggerConnector.tsx new file mode 100644 index 0000000..b38e6dd --- /dev/null +++ b/app/src/modules/simulation/triggers/connector/triggerConnector.tsx @@ -0,0 +1,126 @@ +import { useThree } from '@react-three/fiber' +import React, { useEffect } from 'react' +import { Object3D } from 'three'; +import { useSubModuleStore } from '../../../../store/useModuleStore'; +import { useLeftData, useTopData } from '../../../../store/visualization/useZone3DWidgetStore'; +import { useEventsStore } from '../../../../store/simulation/useEventsStore'; +import { useProductStore } from '../../../../store/simulation/useProductStore'; +import { useSelectedProduct } from '../../../../store/simulation/useSimulationStore'; +import { useSelectedAsset } from '../../../../store/simulation/useSimulationStore'; + +function TriggerConnector() { + const { gl, raycaster, scene } = useThree(); + const { subModule } = useSubModuleStore(); + const { setTop } = useTopData(); + const { setLeft } = useLeftData(); + const { getIsEventInProduct } = useProductStore(); + const { getEventByModelUuid } = useEventsStore(); + const { selectedProduct } = useSelectedProduct(); + const { selectedAsset, setSelectedAsset, clearSelectedAsset } = useSelectedAsset(); + + useEffect(() => { + + const canvasElement = gl.domElement; + + let drag = false; + let isRightMouseDown = false; + + const onMouseDown = (evt: MouseEvent) => { + if (selectedAsset) { + clearSelectedAsset(); + } + if (evt.button === 2) { + isRightMouseDown = true; + drag = false; + } + }; + + const onMouseUp = (evt: MouseEvent) => { + if (evt.button === 2) { + isRightMouseDown = false; + } + } + + const onMouseMove = () => { + if (isRightMouseDown) { + drag = true; + } + }; + + const handleRightClick = (evt: MouseEvent) => { + if (drag) return; + evt.preventDefault(); + const canvasElement = gl.domElement; + if (!canvasElement) return; + + let intersects = raycaster.intersectObjects(scene.children, true); + if (intersects.length > 0 && intersects[0]?.object?.parent?.parent?.position && intersects[0]?.object?.parent?.parent?.scale && intersects[0]?.object?.parent?.parent?.rotation) { + let currentObject = intersects[0].object; + + while (currentObject) { + if (currentObject.name === "Scene") { + break; + } + currentObject = currentObject.parent as Object3D; + } + if (currentObject) { + const isInProduct = getIsEventInProduct(selectedProduct.productId, currentObject.uuid); + + if (isInProduct) { + const event = getEventByModelUuid(currentObject.uuid); + if (event) { + setSelectedAsset(event) + const canvasRect = canvasElement.getBoundingClientRect(); + const relativeX = evt.clientX - canvasRect.left; + const relativeY = evt.clientY - canvasRect.top; + + setTop(relativeY); + setLeft(relativeX); + } else { + clearSelectedAsset() + } + } else { + const event = getEventByModelUuid(currentObject.uuid); + if (event) { + setSelectedAsset(event) + const canvasRect = canvasElement.getBoundingClientRect(); + const relativeX = evt.clientX - canvasRect.left; + const relativeY = evt.clientY - canvasRect.top; + + setTop(relativeY); + setLeft(relativeX); + } else { + clearSelectedAsset() + } + } + + } + } else { + clearSelectedAsset() + } + + }; + + if (subModule === 'simulations') { + canvasElement.addEventListener("mousedown", onMouseDown); + canvasElement.addEventListener("mouseup", onMouseUp); + canvasElement.addEventListener("mousemove", onMouseMove); + canvasElement.addEventListener('contextmenu', handleRightClick); + } + + return () => { + canvasElement.removeEventListener("mousedown", onMouseDown); + canvasElement.removeEventListener("mouseup", onMouseUp); + canvasElement.removeEventListener("mousemove", onMouseMove); + canvasElement.removeEventListener('contextmenu', handleRightClick); + }; + + }, [gl, subModule, selectedProduct, selectedAsset]); + + return ( + <> + + ) +} + +export default TriggerConnector \ No newline at end of file diff --git a/app/src/modules/simulation/triggers/temp.md b/app/src/modules/simulation/triggers/temp.md deleted file mode 100644 index e69de29..0000000 diff --git a/app/src/modules/simulation/triggers/trigger.tsx b/app/src/modules/simulation/triggers/trigger.tsx new file mode 100644 index 0000000..110da2e --- /dev/null +++ b/app/src/modules/simulation/triggers/trigger.tsx @@ -0,0 +1,14 @@ +import React from 'react' +import TriggerConnector from './connector/triggerConnector' + +function Trigger() { + return ( + <> + + + + + ) +} + +export default Trigger \ No newline at end of file diff --git a/app/src/modules/visualization/RealTimeVisulization.tsx b/app/src/modules/visualization/RealTimeVisulization.tsx index cd2c57c..30f0014 100644 --- a/app/src/modules/visualization/RealTimeVisulization.tsx +++ b/app/src/modules/visualization/RealTimeVisulization.tsx @@ -125,7 +125,7 @@ const RealTimeVisulization: React.FC = () => { {} ); setZonesData(formattedData); - } catch (error) {} + } catch (error) { } } GetZoneData(); @@ -362,6 +362,10 @@ const RealTimeVisulization: React.FC = () => { "RotateY", "Delete", ]} + onClick={(e) => { + setRightSelect(e); + setEditWidgetOptions(false); + }} /> )} diff --git a/app/src/services/visulization/zone/getSelect2dZoneData.ts b/app/src/services/visulization/zone/getSelect2dZoneData.ts index b2c39e9..00d4dfe 100644 --- a/app/src/services/visulization/zone/getSelect2dZoneData.ts +++ b/app/src/services/visulization/zone/getSelect2dZoneData.ts @@ -7,7 +7,7 @@ export const getSelect2dZoneData = async ( ) => { try { const response = await fetch( - `${url_Backend_dwinzo}/api/v2/Zone/visualization/${ZoneId}?organization=${organization}`, + `${url_Backend_dwinzo}/api/v2/ZoneVisualization/${ZoneId}?organization=${organization}`, { method: "GET", headers: { diff --git a/app/src/store/simulation/useProductStore.ts b/app/src/store/simulation/useProductStore.ts index 81feb7f..91576c7 100644 --- a/app/src/store/simulation/useProductStore.ts +++ b/app/src/store/simulation/useProductStore.ts @@ -55,6 +55,11 @@ type ProductsStore = { // Helper functions getProductById: (productId: string) => { productName: string; productId: string; eventsData: EventsSchema[] } | undefined; + getEventByModelUuid: (productId: string, modelUuid: string) => EventsSchema | 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; + getTriggerByUuid: (productId: string, triggerUuid: string) => TriggerSchema | undefined; + getIsEventInProduct: (productId: string, modelUuid: string) => boolean; }; export const useProductStore = create()( @@ -417,6 +422,89 @@ export const useProductStore = create()( // Helper functions getProductById: (productId) => { return get().products.find(p => p.productId === productId); + }, + + getEventByModelUuid: (productId, modelUuid) => { + const product = get().getProductById(productId); + if (!product) return undefined; + return product.eventsData.find(e => 'modelUuid' in e && e.modelUuid === modelUuid); + }, + + getPointByUuid: (productId, modelUuid, pointUuid) => { + const event = get().getEventByModelUuid(productId, modelUuid); + if (!event) return undefined; + + if ('points' in event) { + return (event as ConveyorEventSchema).points.find(p => p.uuid === pointUuid); + } else if ('point' in event && (event as any).point.uuid === pointUuid) { + return (event as VehicleEventSchema | RoboticArmEventSchema | MachineEventSchema | StorageEventSchema).point; + } + return undefined; + }, + + getActionByUuid: (productId, actionUuid) => { + const product = get().products.find(p => p.productId === productId); + if (!product) return undefined; + + for (const event of product.eventsData) { + if ('points' in event) { + for (const point of (event as ConveyorEventSchema).points) { + if (point.action?.actionUuid === actionUuid) { + return point.action; + } + } + } else if ('point' in event) { + const point = (event as any).point; + if ('action' in point && point.action?.actionUuid === actionUuid) { + return point.action; + } else if ('actions' in point) { + const action = point.actions.find((a: any) => a.actionUuid === actionUuid); + if (action) return action; + } + } + } + return undefined; + }, + + getTriggerByUuid: (productId, triggerUuid) => { + const product = get().products.find(p => p.productId === productId); + if (!product) return undefined; + + for (const event of product.eventsData) { + if ('points' in event) { + for (const point of (event as ConveyorEventSchema).points) { + for (const trigger of point.action?.triggers || []) { + if (trigger.triggerUuid === triggerUuid) { + return trigger; + } + } + } + } else if ('point' in event) { + const point = (event as any).point; + if ('action' in point) { + for (const trigger of point.action?.triggers || []) { + if (trigger.triggerUuid === triggerUuid) { + return trigger; + } + } + } else if ('actions' in point) { + for (const action of point.actions) { + for (const trigger of action.triggers || []) { + if (trigger.triggerUuid === triggerUuid) { + return trigger; + } + } + } + } + } + } + return undefined; + }, + + getIsEventInProduct: (productId, modelUuid) => { + const product = get().getProductById(productId); + if (!product) return false; + return product.eventsData.some(e => 'modelUuid' in e && e.modelUuid === modelUuid); } })) ); diff --git a/app/src/store/simulation/useSimulationStore.ts b/app/src/store/simulation/useSimulationStore.ts index 9c0fc00..ae6ac81 100644 --- a/app/src/store/simulation/useSimulationStore.ts +++ b/app/src/store/simulation/useSimulationStore.ts @@ -24,6 +24,50 @@ export const useSelectedEventSphere = create()( })) ); +interface SelectedEventDataState { + selectedEventData: { data: EventsSchema; selectedPoint: string } | undefined; + setSelectedEventData: (data: EventsSchema, selectedPoint: string) => void; + clearSelectedEventData: () => void; +} + +export const useSelectedEventData = create()( + immer((set) => ({ + selectedEventData: undefined, + setSelectedEventData: (data, selectedPoint) => { + set((state) => { + state.selectedEventData = { data, selectedPoint }; + }); + }, + clearSelectedEventData: () => { + set((state) => { + state.selectedEventData = undefined; + }); + }, + })) +); + +interface SelectedAssetState { + selectedAsset: EventsSchema | undefined; + setSelectedAsset: (EventData: EventsSchema) => void; + clearSelectedAsset: () => void; +} + +export const useSelectedAsset = create()( + immer((set) => ({ + selectedAsset: undefined, + setSelectedAsset: (EventData) => { + set((state) => { + state.selectedAsset = EventData; + }); + }, + clearSelectedAsset: () => { + set((state) => { + state.selectedAsset = undefined; + }); + }, + })) +); + interface SelectedProductState { selectedProduct: { productId: string; productName: string }; setSelectedProduct: (productId: string, productName: string) => void; diff --git a/app/src/store/useModuleStore.ts b/app/src/store/useModuleStore.ts index 1012792..3cc1d00 100644 --- a/app/src/store/useModuleStore.ts +++ b/app/src/store/useModuleStore.ts @@ -13,14 +13,17 @@ const useModuleStore = create((set) => ({ export default useModuleStore; // New store for subModule + +type SubModule = 'properties' | 'simulations' | 'mechanics' | 'analysis' | 'zoneProperties'; + interface SubModuleStore { - subModule: string; - setSubModule: (subModule: string) => void; + subModule: SubModule; + setSubModule: (subModule: SubModule) => void; } const useSubModuleStore = create((set) => ({ subModule: "properties", // Initial subModule state - setSubModule: (subModule) => set({ subModule }), // Update subModule state + setSubModule: (value) => set({ subModule: value }), // Update subModule state })); export { useSubModuleStore }; diff --git a/app/src/types/simulationTypes.d.ts b/app/src/types/simulationTypes.d.ts index 1b99456..12c0dc2 100644 --- a/app/src/types/simulationTypes.d.ts +++ b/app/src/types/simulationTypes.d.ts @@ -25,7 +25,7 @@ interface ConveyorPointSchema { action: { actionUuid: string; actionName: string; - actionType: "default" | "spawn" | "swap" | "despawn"; + actionType: "default" | "spawn" | "swap" | "delay" | "despawn"; material: string; delay: number | "inherit"; spawnInterval: number | "inherit"; @@ -119,6 +119,8 @@ interface StorageEventSchema extends AssetEventSchema { point: StoragePointSchema; } +type PointsScheme = ConveyorPointSchema | VehiclePointSchema | RoboticArmPointSchema | MachinePointSchema | StoragePointSchema; + type EventsSchema = ConveyorEventSchema | VehicleEventSchema | RoboticArmEventSchema | MachineEventSchema | StorageEventSchema; type productsSchema = { From c5d4679068287e3d605a4d5e3887e7ee839a61ef Mon Sep 17 00:00:00 2001 From: Gomathi9520 Date: Thu, 24 Apr 2025 17:51:52 +0530 Subject: [PATCH 03/13] fix --- app/src/modules/simulation/roboticArm/roboticArm.tsx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/app/src/modules/simulation/roboticArm/roboticArm.tsx b/app/src/modules/simulation/roboticArm/roboticArm.tsx index 7899f56..4295ac7 100644 --- a/app/src/modules/simulation/roboticArm/roboticArm.tsx +++ b/app/src/modules/simulation/roboticArm/roboticArm.tsx @@ -1,7 +1,5 @@ -import React, { useEffect } from "react"; +import { useEffect } from "react"; import RoboticArmInstances from "./instances/roboticArmInstances"; -import IkInstances from "./instances/ikInstances"; -import { log } from "node:console"; import { useArmBotStore } from "../../../store/simulation/useArmBotStore"; function RoboticArm() { @@ -85,7 +83,7 @@ function RoboticArm() { addArmBot('123', armBotStatusSample[0]); // addCurrentAction('armbot-xyz-001', 'action-001'); }, []); - + useEffect(() => { console.log('armBots: ', armBots); From 4310b473d0065251848538956477c7a104bab12e Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Thu, 24 Apr 2025 19:15:36 +0530 Subject: [PATCH 04/13] feat: Enhance EventProperties and mechanics components with new state management and action handling; add DelayAction component and remove unused IkInstances --- .../layout/sidebarRight/SideBarRight.tsx | 2 +- .../eventProperties/EventProperties.tsx | 272 ++++++++++-------- .../eventProperties/actions/DelayAction.tsx | 22 ++ .../eventProperties/actions/DespawnAction.tsx | 11 - .../mechanics/conveyorMechanics.tsx | 78 ++++- .../mechanics/roboticArmMechanics.tsx | 164 ++++++++++- .../mechanics/vehicleMechanics.tsx | 70 ++++- .../roboticArm/instances/ikInstances.tsx | 14 - 8 files changed, 481 insertions(+), 152 deletions(-) create mode 100644 app/src/components/layout/sidebarRight/properties/eventProperties/actions/DelayAction.tsx delete mode 100644 app/src/modules/simulation/roboticArm/instances/ikInstances.tsx diff --git a/app/src/components/layout/sidebarRight/SideBarRight.tsx b/app/src/components/layout/sidebarRight/SideBarRight.tsx index f5668bf..5c37dec 100644 --- a/app/src/components/layout/sidebarRight/SideBarRight.tsx +++ b/app/src/components/layout/sidebarRight/SideBarRight.tsx @@ -123,7 +123,7 @@ const SideBarRight: React.FC = () => { )} - {subModule === "mechanics" && selectedEventData && selectedEventSphere && ( + {subModule === "mechanics" && (
diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx index 6c44947..887aaaa 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx @@ -22,6 +22,9 @@ import Trigger from "./trigger/Trigger"; import { useSelectedEventData, useSelectedProduct } from "../../../../../store/simulation/useSimulationStore"; import { useProductStore } from "../../../../../store/simulation/useProductStore"; +import ConveyorMechanics from "./mechanics/conveyorMechanics"; +import VehicleMechanics from "./mechanics/vehicleMechanics"; +import RoboticArmMechanics from "./mechanics/roboticArmMechanics"; const EventProperties: React.FC = () => { const actionsContainerRef = useRef(null); @@ -32,21 +35,43 @@ const EventProperties: React.FC = () => { const { getEventByModelUuid } = useProductStore(); const { selectedProduct } = useSelectedProduct(); + // State for derived values + const [currentEventData, setCurrentEventData] = useState(null); + const [assetType, setAssetType] = useState(null); + const [availableActions, setAvailableActions] = useState({ + defaultOption: "default", + options: ["default"] + }); + const [actions, setActions] = useState<{ uuid: string; name: string }[]>([]); + const [speed, setSpeed] = useState("0.5"); + useEffect(() => { - const actions = getActions(); - if (actions.length > 0 && !selectedItem.item) { - setSelectedItem({ item: actions[0] }); + const event = getCurrentEventData(); + setCurrentEventData(event); + + const type = determineAssetType(event); + setAssetType(type); + + const actionsConfig = determineAvailableActions(type); + setAvailableActions(actionsConfig); + + const actionList = getActionList(event, type); + setActions(actionList); + + if (actionList.length > 0 && !selectedItem.item) { + setSelectedItem({ item: actionList[0] }); } - }, [selectedEventData]); + + const currentSpeed = getCurrentSpeed(); + setSpeed(currentSpeed); + }, [selectedEventData, selectedProduct]); const getCurrentEventData = () => { if (!selectedEventData?.data || !selectedProduct) return null; - const event = getEventByModelUuid(selectedProduct.productId, selectedEventData.data.modelUuid); - return event || null; + return getEventByModelUuid(selectedProduct.productId, selectedEventData.data.modelUuid) || null; }; - const getAssetType = () => { - const event = getCurrentEventData(); + const determineAssetType = (event: EventsSchema | null) => { if (!event) return null; switch (event.type) { @@ -59,8 +84,8 @@ const EventProperties: React.FC = () => { } }; - const getAvailableActions = () => { - switch (getAssetType()) { + const determineAvailableActions = (type: string | null) => { + switch (type) { case "conveyor": return { defaultOption: "default", @@ -94,12 +119,10 @@ const EventProperties: React.FC = () => { } }; - // Get actions based on asset type - const getActions = () => { + const getActionList = (event: EventsSchema | null, type: string | null) => { if (!selectedEventData?.data) return []; - const event = selectedEventData.data; - switch (getAssetType()) { + switch (type) { case "conveyor": return (event as ConveyorEventSchema).points .find((point) => point.uuid === selectedEventData?.selectedPoint) @@ -141,8 +164,13 @@ const EventProperties: React.FC = () => { } }; + const getCurrentSpeed = () => { + if (!selectedEventData) return "0.5"; + if ("speed" in selectedEventData.data) return selectedEventData.data.speed.toString(); + return "0.5"; + }; + const handleActionToggle = (actionUuid: string) => { - const actions = getActions(); const selected = actions.find(action => action.uuid === actionUuid); if (selected) { setSelectedItem({ item: selected }); @@ -150,130 +178,128 @@ const EventProperties: React.FC = () => { }; const handleDeleteAction = (actionUuid: string) => { - - }; - - const actions = getActions(); - - const getSpeed = () => { - if (!selectedEventData) return "0.5"; - if ("speed" in selectedEventData.data) return selectedEventData.data.speed.toString(); - return "0.5"; + // Implementation for delete action }; return ( <> - {getCurrentEventData() && -
-
-
{selectedEventData?.data.modelName}
-
-
-
-
- { }} - onChange={(value) => console.log(value)} - /> -
+
+ {currentEventData && + <> +
+
{selectedEventData?.data.modelName}
+
+
+
+
+ { }} + onChange={(value) => console.log(value)} + /> +
-
- { }} - onChange={(value) => console.log(value)} - /> +
+ { }} + onChange={(value) => console.log(value)} + /> +
-
- {getAssetType() === 'roboticArm' && -
-
-
-
Actions
-
{ }}> - Add -
-
-
-
- {actions.map((action) => ( -
-
handleActionToggle(action.uuid)} - > - -
- {actions.length > 1 && ( -
handleDeleteAction(action.uuid)} - > - -
- )} -
- ))} + {assetType === 'roboticArm' && +
+
+
+
Actions
+
{ }}> + Add +
handleResize(e, actionsContainerRef)} + className="lists-main-container" + ref={actionsContainerRef} + style={{ height: "120px" }} > - +
+ {actions.map((action) => ( +
+
handleActionToggle(action.uuid)} + > + +
+ {actions.length > 1 && ( +
handleDeleteAction(action.uuid)} + > + +
+ )} +
+ ))} +
+
handleResize(e, actionsContainerRef)} + > + +
+ } +
+
+ +
+
+ setActiveOption(option)} + /> + {activeOption === "default" && } + {activeOption === "spawn" && } + {activeOption === "swap" && } + {activeOption === "despawn" && } + {activeOption === "travel" && } + {activeOption === "pickAndPlace" && } + {activeOption === "process" && } + {activeOption === "store" && } +
- } -
-
- +
+
-
- setActiveOption(option)} - /> - {activeOption === "default" && } - {activeOption === "spawn" && } - {activeOption === "swap" && } - {activeOption === "despawn" && } - {activeOption === "travel" && } - {activeOption === "pickAndPlace" && } - {activeOption === "process" && } - {activeOption === "store" && } -
-
-
- -
-
- } + + {/* {assetType === 'conveyor' && } + {assetType === 'vehicle' && } + {assetType === 'roboticArm' && } */} + + } +
); }; -export default EventProperties; +export default EventProperties; \ No newline at end of file diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/actions/DelayAction.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/DelayAction.tsx new file mode 100644 index 0000000..e4bceb9 --- /dev/null +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/DelayAction.tsx @@ -0,0 +1,22 @@ +import React from "react"; +import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown"; + +const DelayAction: React.FC = () => { + return ( + <> + { }} + onChange={(value) => console.log(value)} + /> + + ); +}; + +export default DelayAction; diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/actions/DespawnAction.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/DespawnAction.tsx index a0f081f..0d54476 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/actions/DespawnAction.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/DespawnAction.tsx @@ -4,17 +4,6 @@ import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown"; const DespawnAction: React.FC = () => { return ( <> - {}} - onChange={(value) => console.log(value)} - /> ); }; diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/conveyorMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/conveyorMechanics.tsx index 000a9d7..4f3122b 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/conveyorMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/conveyorMechanics.tsx @@ -1,8 +1,84 @@ -import React from 'react' +import { useEffect, useState } from 'react' +import InputWithDropDown from '../../../../../ui/inputs/InputWithDropDown' +import DelayAction from '../actions/DelayAction' +import RenameInput from '../../../../../ui/inputs/RenameInput' +import LabledDropdown from '../../../../../ui/inputs/LabledDropdown' +import DespawnAction from '../actions/DespawnAction' +import SwapAction from '../actions/SwapAction' +import SpawnAction from '../actions/SpawnAction' +import DefaultAction from '../actions/DefaultAction' +import Trigger from '../trigger/Trigger' +import { useSelectedEventData, useSelectedProduct } from "../../../../../../store/simulation/useSimulationStore"; +import { useProductStore } from "../../../../../../store/simulation/useProductStore"; function ConveyorMechanics() { + const [activeOption, setActiveOption] = useState("default"); + const [selectedPointData, setSelectedPointData] = useState(); + const { selectedEventData } = useSelectedEventData(); + const { getPointByUuid } = useProductStore(); + const { selectedProduct } = useSelectedProduct(); + + useEffect(() => { + if (selectedEventData) { + const point = getPointByUuid(selectedProduct.productId, selectedEventData?.data.modelUuid, selectedEventData?.selectedPoint); + if (point && 'action' in point) { + setSelectedPointData(point as PointsScheme & { action: { actionType: string } }); + setActiveOption((point as PointsScheme & { action: { actionType: string } }).action.actionType); + } + } + }, [selectedProduct, selectedEventData]) + + const availableActions = { + defaultOption: "default", + options: ["default", "spawn", "swap", "delay", "despawn"], + }; + return ( <> + {selectedEventData && + <> +
+
+
+ { }} + onChange={(value) => console.log(value)} + /> +
+
+
+ +
+
+ +
+
+ setActiveOption(option)} + /> + {activeOption === "default" && } + {activeOption === "spawn" && } + {activeOption === "swap" && } + {activeOption === "despawn" && } + {activeOption === "delay" && } +
+
+
+ +
+ + } ) } diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/roboticArmMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/roboticArmMechanics.tsx index 56e4c27..9a044ac 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/roboticArmMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/roboticArmMechanics.tsx @@ -1,8 +1,170 @@ -import React from 'react' +import { useEffect, useRef, useState } from 'react' +import * as THREE from 'three'; +import InputWithDropDown from '../../../../../ui/inputs/InputWithDropDown' +import RenameInput from '../../../../../ui/inputs/RenameInput' +import LabledDropdown from '../../../../../ui/inputs/LabledDropdown' +import Trigger from '../trigger/Trigger' +import { useSelectedEventData, useSelectedProduct } from "../../../../../../store/simulation/useSimulationStore"; +import { useProductStore } from "../../../../../../store/simulation/useProductStore"; +import { AddIcon, RemoveIcon, ResizeHeightIcon } from '../../../../../icons/ExportCommonIcons' +import { handleResize } from '../../../../../../functions/handleResizePannel' +import PickAndPlaceAction from '../actions/PickAndPlaceAction' function RoboticArmMechanics() { + const actionsContainerRef = useRef(null); + + const [activeOption, setActiveOption] = useState("pickAndPlace"); + const [selectedItem, setSelectedItem] = useState<{ item: { uuid: string; name: string } | null; }>({ item: null }); + const { selectedEventData } = useSelectedEventData(); + const { getEventByModelUuid, addAction } = useProductStore(); + const { selectedProduct } = useSelectedProduct(); + + const availableActions = { + defaultOption: "pickAndPlace", + options: ["pickAndPlace"] + }; + const [actions, setActions] = useState<{ uuid: string; name: string }[]>([]); + + useEffect(() => { + const event = getCurrentEventData(); + const actionList = getActionList(event as RoboticArmEventSchema); + setActions(actionList); + + if (actionList.length > 0 && !selectedItem.item) { + setSelectedItem({ item: actionList[0] }); + } + }, [selectedEventData, selectedProduct]); + + const getCurrentEventData = () => { + if (!selectedEventData?.data || !selectedProduct) return null; + return getEventByModelUuid(selectedProduct.productId, selectedEventData.data.modelUuid) || null; + }; + + const getActionList = (event: RoboticArmEventSchema) => { + if (!event || !('point' in event)) return []; + + return event.point.actions.flatMap( + (action) => + action.triggers.map((trigger) => ({ + uuid: trigger.triggerUuid, + name: trigger.triggerName, + })) + ) || []; + }; + + const handleActionToggle = (actionUuid: string) => { + const action = actions.find(a => a.uuid === actionUuid); + if (action) { + setSelectedItem({ item: action }); + } + }; + + const handleAddAction = () => { + if (selectedEventData) { + const newEvent = { + actionUuid: THREE.MathUtils.generateUUID(), + actionName: `Action ${actions.length + 1}`, + actionType: "pickAndPlace" as const, + process: { + startPoint: null as [number, number, number] | null, + endPoint: null as [number, number, number] | null + }, + triggers: [] as TriggerSchema[] + } + addAction( + selectedProduct.productId, + selectedEventData?.data.modelUuid, + selectedEventData?.selectedPoint, + newEvent + ) + } + }; + + const handleDeleteAction = (actionUuid: string) => { + + }; + return ( <> +
+
+
+ { }} + onChange={(value) => console.log(value)} + /> +
+
+
+
+
+
+
Actions
+
handleAddAction()}> + Add +
+
+
+
+ {actions.map((action) => ( +
+
handleActionToggle(action.uuid)} + > + +
+ {actions.length > 1 && ( +
handleDeleteAction(action.uuid)} + > + +
+ )} +
+ ))} +
+
handleResize(e, actionsContainerRef)} + > + +
+
+
+
+
+
+ +
+
+ setActiveOption(option)} + /> + {activeOption === "pickAndPlace" && } +
+
+
+ +
) } diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/vehicleMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/vehicleMechanics.tsx index cdb32c4..b689734 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/vehicleMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/vehicleMechanics.tsx @@ -1,8 +1,76 @@ -import React from 'react' +import { useEffect, useState } from 'react' +import InputWithDropDown from '../../../../../ui/inputs/InputWithDropDown' +import RenameInput from '../../../../../ui/inputs/RenameInput' +import LabledDropdown from '../../../../../ui/inputs/LabledDropdown' +import Trigger from '../trigger/Trigger' +import { useSelectedEventData, useSelectedProduct } from "../../../../../../store/simulation/useSimulationStore"; +import { useProductStore } from "../../../../../../store/simulation/useProductStore"; +import TravelAction from '../actions/TravelAction' function VehicleMechanics() { + const [activeOption, setActiveOption] = useState("default"); + const [selectedPointData, setSelectedPointData] = useState(); + const { selectedEventData } = useSelectedEventData(); + const { getPointByUuid } = useProductStore(); + const { selectedProduct } = useSelectedProduct(); + + useEffect(() => { + if (selectedEventData) { + const point = getPointByUuid(selectedProduct.productId, selectedEventData?.data.modelUuid, selectedEventData?.selectedPoint); + if (point && 'action' in point) { + setSelectedPointData(point as PointsScheme & { action: { actionType: string } }); + setActiveOption((point as PointsScheme & { action: { actionType: string } }).action.actionType); + } + } + }, [selectedProduct, selectedEventData]) + + const availableActions = { + defaultOption: "travel", + options: ["travel"], + }; + return ( <> + {selectedEventData && + <> +
+
+
+ { }} + onChange={(value) => console.log(value)} + /> +
+
+
+ +
+
+ +
+
+ setActiveOption(option)} + /> + {activeOption === "travel" && } +
+
+
+ +
+ + } ) } diff --git a/app/src/modules/simulation/roboticArm/instances/ikInstances.tsx b/app/src/modules/simulation/roboticArm/instances/ikInstances.tsx deleted file mode 100644 index d44ddd2..0000000 --- a/app/src/modules/simulation/roboticArm/instances/ikInstances.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import React from 'react' -import IKInstance from './ikInstance/ikInstance'; - -function IkInstances() { - return ( - <> - - - - - ) -} - -export default IkInstances; \ No newline at end of file From bfcb67c3c8ea9e7fa0877bdffe9a1b05a00d2437 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Fri, 25 Apr 2025 11:19:40 +0530 Subject: [PATCH 05/13] feat: Enhance EventProperties and mechanics components with new mechanics; refactor action handling and improve state management for various actions --- .../eventProperties/EventProperties.tsx | 122 +------------ .../eventProperties/actions/DelayAction.tsx | 20 ++- .../eventProperties/actions/ProcessAction.tsx | 58 +++++-- .../eventProperties/actions/SpawnAction.tsx | 93 +++++++--- .../eventProperties/actions/SwapAction.tsx | 27 ++- .../eventProperties/actions/TravelAction.tsx | 100 +++++++---- .../mechanics/conveyorMechanics.tsx | 162 ++++++++++++++++-- .../mechanics/machineMechanics.tsx | 116 ++++++++++++- .../mechanics/storageMechanics.tsx | 51 +++++- .../mechanics/vehicleMechanics.tsx | 151 ++++++++++++++-- .../ui/inputs/PreviewSelectionWithUpload.tsx | 6 - .../IntialLoad/loadInitialFloorItems.ts | 2 +- 12 files changed, 663 insertions(+), 245 deletions(-) diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx index 887aaaa..21781f0 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx @@ -25,6 +25,8 @@ import { useProductStore } from "../../../../../store/simulation/useProductStore import ConveyorMechanics from "./mechanics/conveyorMechanics"; import VehicleMechanics from "./mechanics/vehicleMechanics"; import RoboticArmMechanics from "./mechanics/roboticArmMechanics"; +import MachineMechanics from "./mechanics/machineMechanics"; +import StorageMechanics from "./mechanics/storageMechanics"; const EventProperties: React.FC = () => { const actionsContainerRef = useRef(null); @@ -170,17 +172,6 @@ const EventProperties: React.FC = () => { return "0.5"; }; - const handleActionToggle = (actionUuid: string) => { - const selected = actions.find(action => action.uuid === actionUuid); - if (selected) { - setSelectedItem({ item: selected }); - } - }; - - const handleDeleteAction = (actionUuid: string) => { - // Implementation for delete action - }; - return ( <>
@@ -189,112 +180,11 @@ const EventProperties: React.FC = () => {
{selectedEventData?.data.modelName}
-
-
-
- { }} - onChange={(value) => console.log(value)} - /> -
- -
- { }} - onChange={(value) => console.log(value)} - /> -
-
-
- {assetType === 'roboticArm' && -
-
-
-
Actions
-
{ }}> - Add -
-
-
-
- {actions.map((action) => ( -
-
handleActionToggle(action.uuid)} - > - -
- {actions.length > 1 && ( -
handleDeleteAction(action.uuid)} - > - -
- )} -
- ))} -
-
handleResize(e, actionsContainerRef)} - > - -
-
-
-
- } -
-
- -
-
- setActiveOption(option)} - /> - {activeOption === "default" && } - {activeOption === "spawn" && } - {activeOption === "swap" && } - {activeOption === "despawn" && } - {activeOption === "travel" && } - {activeOption === "pickAndPlace" && } - {activeOption === "process" && } - {activeOption === "store" && } -
-
-
- -
- - {/* {assetType === 'conveyor' && } + {assetType === 'conveyor' && } {assetType === 'vehicle' && } - {assetType === 'roboticArm' && } */} + {assetType === 'roboticArm' && } + {assetType === 'machine' && } + {assetType === 'storageUnit' && } }
diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/actions/DelayAction.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/DelayAction.tsx index e4bceb9..2bb63d4 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/actions/DelayAction.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/DelayAction.tsx @@ -1,19 +1,27 @@ import React from "react"; import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown"; -const DelayAction: React.FC = () => { +interface DelayActionProps { + value: string; + defaultValue: string; + min: number; + max: number; + onChange: (value: string) => void; +} + +const DelayAction: React.FC = ({ value, defaultValue, min, max, onChange }) => { return ( <> { }} - onChange={(value) => console.log(value)} + onChange={onChange} /> ); diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/actions/ProcessAction.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/ProcessAction.tsx index a27894e..331cf1b 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/actions/ProcessAction.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/ProcessAction.tsx @@ -2,23 +2,47 @@ import React from "react"; import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown"; import SwapAction from "./SwapAction"; -const ProcessAction: React.FC = () => { - return ( - <> - {}} - onChange={(value) => console.log(value)} - /> - - - ); +interface ProcessActionProps { + value: string; + min: number; + max: number; + defaultValue: string; + onChange: (value: string) => void; + swapOptions: string[]; + swapDefaultOption: string; + onSwapSelect: (value: string) => void; +} + +const ProcessAction: React.FC = ({ + value, + min, + max, + defaultValue, + onChange, + swapOptions, + swapDefaultOption, + onSwapSelect, +}) => { + return ( + <> + { }} + onChange={onChange} + /> + + + ); }; export default ProcessAction; diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/actions/SpawnAction.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/SpawnAction.tsx index 0c37cdb..7d8002e 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/actions/SpawnAction.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/SpawnAction.tsx @@ -1,35 +1,72 @@ import React from "react"; import PreviewSelectionWithUpload from "../../../../../ui/inputs/PreviewSelectionWithUpload"; import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown"; +import LabledDropdown from "../../../../../ui/inputs/LabledDropdown"; -const SpawnAction: React.FC = () => { - return ( - <> - {}} - onChange={(value) => console.log(value)} - /> - {}} - onChange={(value) => console.log(value)} - /> - - - ); +interface SpawnActionProps { + onChangeInterval: (value: string) => void; + onChangeCount: (value: string) => void; + defaultOption: string; + options: string[]; + onSelect: (option: string) => void; + intervalValue: string; + countValue: string; + intervalMin: number; + intervalMax: number; + intervalDefaultValue: string; + countMin: number; + countMax: number; + countDefaultValue: string; +} + +const SpawnAction: React.FC = ({ + onChangeInterval, + onChangeCount, + defaultOption, + options, + onSelect, + intervalValue, + countValue, + intervalMin, + intervalMax, + intervalDefaultValue, + countMin, + countMax, + countDefaultValue, +}) => { + return ( + <> + { }} + onChange={onChangeInterval} + /> + { }} + onChange={onChangeCount} + /> + {/* */} + + + ); }; export default SpawnAction; diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/actions/SwapAction.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/SwapAction.tsx index 2e18d80..23b203f 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/actions/SwapAction.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/SwapAction.tsx @@ -1,12 +1,27 @@ import React from "react"; import PreviewSelectionWithUpload from "../../../../../ui/inputs/PreviewSelectionWithUpload"; +import LabledDropdown from "../../../../../ui/inputs/LabledDropdown"; -const SwapAction: React.FC = () => { - return ( - <> - - - ); +interface SwapActionProps { + onSelect: (option: string) => void; + defaultOption: string; + options: string[]; +} + +const SwapAction: React.FC = ({ onSelect, defaultOption, options }) => { + + return ( + <> + {/* */} + + + + ); }; export default SwapAction; diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/actions/TravelAction.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/TravelAction.tsx index ee4bda0..49eb683 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/actions/TravelAction.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/TravelAction.tsx @@ -2,35 +2,77 @@ import React from "react"; import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown"; import EyeDropInput from "../../../../../ui/inputs/EyeDropInput"; -const TravelAction: React.FC = () => { - return ( - <> - {}} - onChange={(value) => console.log(value)} - /> - {}} - onChange={(value) => console.log(value)} - /> - {}} /> - {}} /> - - ); +interface TravelActionProps { + loadCapacity: { + value: string; + min: number; + max: number; + defaultValue: string; + onChange: (value: string) => void; + }; + unloadDuration: { + value: string; + min: number; + max: number; + defaultValue: string; + onChange: (value: string) => void; + }; + pickPoint?: { + value: string; + onChange: (value: string) => void; + }; + unloadPoint?: { + value: string; + onChange: (value: string) => void; + }; +} + +const TravelAction: React.FC = ({ + loadCapacity, + unloadDuration, + pickPoint, + unloadPoint, +}) => { + return ( + <> + { }} + onChange={loadCapacity.onChange} + /> + { }} + onChange={unloadDuration.onChange} + /> + {pickPoint && ( + + )} + {unloadPoint && ( + + )} + + ); }; export default TravelAction; diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/conveyorMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/conveyorMechanics.tsx index 4f3122b..c13bd75 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/conveyorMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/conveyorMechanics.tsx @@ -12,27 +12,116 @@ import { useSelectedEventData, useSelectedProduct } from "../../../../../../stor import { useProductStore } from "../../../../../../store/simulation/useProductStore"; function ConveyorMechanics() { - const [activeOption, setActiveOption] = useState("default"); - const [selectedPointData, setSelectedPointData] = useState(); + const [activeOption, setActiveOption] = useState<"default" | "spawn" | "swap" | "delay" | "despawn">("default"); + const [selectedPointData, setSelectedPointData] = useState(); const { selectedEventData } = useSelectedEventData(); - const { getPointByUuid } = useProductStore(); + const { getPointByUuid, updateEvent, updateAction } = useProductStore(); const { selectedProduct } = useSelectedProduct(); useEffect(() => { if (selectedEventData) { - const point = getPointByUuid(selectedProduct.productId, selectedEventData?.data.modelUuid, selectedEventData?.selectedPoint); + const point = getPointByUuid( + selectedProduct.productId, + selectedEventData?.data.modelUuid, + selectedEventData?.selectedPoint + ) as ConveyorPointSchema | undefined; if (point && 'action' in point) { - setSelectedPointData(point as PointsScheme & { action: { actionType: string } }); - setActiveOption((point as PointsScheme & { action: { actionType: string } }).action.actionType); + setSelectedPointData(point); + setActiveOption(point.action.actionType as "default" | "spawn" | "swap" | "delay" | "despawn"); } } }, [selectedProduct, selectedEventData]) + const handleSpeedChange = (value: string) => { + if (!selectedEventData) return; + updateEvent( + selectedProduct.productId, + selectedEventData.data.modelUuid, + { speed: parseFloat(value) } + ); + }; + + const handleActionTypeChange = (option: string) => { + if (!selectedEventData || !selectedPointData) return; + const validOption = option as "default" | "spawn" | "swap" | "delay" | "despawn"; + setActiveOption(validOption); + + updateAction( + selectedPointData.action.actionUuid, + { actionType: validOption } + ); + }; + + const handleRenameAction = (newName: string) => { + if (!selectedPointData) return; + updateAction( + selectedPointData.action.actionUuid, + { actionName: newName } + ); + }; + + const handleSpawnCountChange = (value: string) => { + if (!selectedPointData) return; + updateAction( + selectedPointData.action.actionUuid, + { spawnCount: value === "inherit" ? "inherit" : parseFloat(value) } + ); + }; + + const handleSpawnIntervalChange = (value: string) => { + if (!selectedPointData) return; + updateAction( + selectedPointData.action.actionUuid, + { spawnInterval: value === "inherit" ? "inherit" : parseFloat(value) } + ); + }; + + const handleMaterialSelect = (material: string) => { + if (!selectedPointData) return; + updateAction( + selectedPointData.action.actionUuid, + { material } + ); + }; + + const handleDelayChange = (value: string) => { + if (!selectedPointData) return; + updateAction( + selectedPointData.action.actionUuid, + { delay: value === "inherit" ? "inherit" : parseFloat(value) } + ); + }; + const availableActions = { defaultOption: "default", options: ["default", "spawn", "swap", "delay", "despawn"], }; + // Get current values from store + const currentSpeed = selectedEventData?.data.type === "transfer" + ? selectedEventData.data.speed.toString() + : "0.5"; + + const currentActionName = selectedPointData + ? selectedPointData.action.actionName + : "Action Name"; + + const currentMaterial = selectedPointData + ? selectedPointData.action.material + : "Default material"; + + const currentSpawnCount = selectedPointData + ? selectedPointData.action.spawnCount?.toString() || "1" + : "1"; + + const currentSpawnInterval = selectedPointData + ? selectedPointData.action.spawnInterval?.toString() || "1" + : "1"; + + const currentDelay = selectedPointData + ? selectedPointData.action.delay?.toString() || "0" + : "0"; + return ( <> {selectedEventData && @@ -42,14 +131,14 @@ function ConveyorMechanics() {
{ }} - onChange={(value) => console.log(value)} + onChange={handleSpeedChange} />
@@ -57,21 +146,58 @@ function ConveyorMechanics() {
- +
setActiveOption(option)} + onSelect={handleActionTypeChange} /> - {activeOption === "default" && } - {activeOption === "spawn" && } - {activeOption === "swap" && } - {activeOption === "despawn" && } - {activeOption === "delay" && } + {activeOption === "default" && + + } + {activeOption === "spawn" && + + } + {activeOption === "swap" && + + } + {activeOption === "despawn" && + + } + {activeOption === "delay" && + + }
diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/machineMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/machineMechanics.tsx index b6e4fb9..138ed7c 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/machineMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/machineMechanics.tsx @@ -1,8 +1,122 @@ -import React from 'react' +import { useEffect, useState } from 'react' +import RenameInput from '../../../../../ui/inputs/RenameInput' +import LabledDropdown from '../../../../../ui/inputs/LabledDropdown' +import Trigger from '../trigger/Trigger' +import { useSelectedEventData, useSelectedProduct } from "../../../../../../store/simulation/useSimulationStore"; +import { useProductStore } from "../../../../../../store/simulation/useProductStore"; +import ProcessAction from '../actions/ProcessAction' function MachineMechanics() { + const [activeOption, setActiveOption] = useState<"default" | "process">("default"); + const [selectedPointData, setSelectedPointData] = useState(); + const { selectedEventData } = useSelectedEventData(); + const { getPointByUuid, updateAction } = useProductStore(); + const { selectedProduct } = useSelectedProduct(); + + useEffect(() => { + if (selectedEventData) { + const point = getPointByUuid( + selectedProduct.productId, + selectedEventData?.data.modelUuid, + selectedEventData?.selectedPoint + ) as MachinePointSchema | undefined; + if (point && 'action' in point) { + setSelectedPointData(point); + setActiveOption(point.action.actionType as "process"); + } + } + }, [selectedProduct, selectedEventData]) + + const handleActionTypeChange = (option: string) => { + if (!selectedEventData || !selectedPointData) return; + const validOption = option as "process"; + setActiveOption(validOption); + + updateAction( + selectedPointData.action.actionUuid, + { actionType: validOption } + ); + }; + + const handleRenameAction = (newName: string) => { + if (!selectedPointData) return; + updateAction( + selectedPointData.action.actionUuid, + { actionName: newName } + ); + }; + + const handleProcessTimeChange = (value: string) => { + if (!selectedPointData) return; + updateAction( + selectedPointData.action.actionUuid, + { processTime: parseFloat(value) } + ); + }; + + const handleMaterialSelect = (material: string) => { + if (!selectedPointData) return; + updateAction( + selectedPointData.action.actionUuid, + { swapMaterial: material } + ); + }; + + // Get current values from store + const currentActionName = selectedPointData + ? selectedPointData.action.actionName + : "Action Name"; + + const currentProcessTime = selectedPointData + ? selectedPointData.action.processTime.toString() + : "1"; + + const currentMaterial = selectedPointData + ? selectedPointData.action.swapMaterial + : "Default material"; + + const availableActions = { + defaultOption: "process", + options: ["process"], + }; + return ( <> + {selectedEventData && + <> +
+
+ +
+
+ + {activeOption === "process" && + + } +
+
+
+ +
+ + } ) } diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx index 0cda40e..d513768 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx @@ -1,8 +1,57 @@ -import React from 'react' +import { useEffect, useState } from 'react' +import RenameInput from '../../../../../ui/inputs/RenameInput' +import LabledDropdown from '../../../../../ui/inputs/LabledDropdown' +import Trigger from '../trigger/Trigger' +import { useSelectedEventData, useSelectedProduct } from "../../../../../../store/simulation/useSimulationStore"; +import { useProductStore } from "../../../../../../store/simulation/useProductStore"; +import StorageAction from '../actions/StorageAction'; function StorageMechanics() { + const [activeOption, setActiveOption] = useState("default"); + const [selectedPointData, setSelectedPointData] = useState(); + const { selectedEventData } = useSelectedEventData(); + const { getPointByUuid } = useProductStore(); + const { selectedProduct } = useSelectedProduct(); + + useEffect(() => { + if (selectedEventData) { + const point = getPointByUuid(selectedProduct.productId, selectedEventData?.data.modelUuid, selectedEventData?.selectedPoint); + if (point && 'action' in point) { + setSelectedPointData(point as PointsScheme & { action: { actionType: string } }); + setActiveOption((point as PointsScheme & { action: { actionType: string } }).action.actionType); + } + } + }, [selectedProduct, selectedEventData]) + + const availableActions = { + defaultOption: "store", + options: ["store", "spawn"], + }; + return ( <> + {selectedEventData && + <> +
+
+ +
+
+ setActiveOption(option)} + /> + {activeOption === "store" && } +
+
+
+ +
+ + } ) } diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/vehicleMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/vehicleMechanics.tsx index b689734..cc2bfa0 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/vehicleMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/vehicleMechanics.tsx @@ -8,22 +8,114 @@ import { useProductStore } from "../../../../../../store/simulation/useProductSt import TravelAction from '../actions/TravelAction' function VehicleMechanics() { - const [activeOption, setActiveOption] = useState("default"); - const [selectedPointData, setSelectedPointData] = useState(); + const [activeOption, setActiveOption] = useState<"default" | "travel">("default"); + const [selectedPointData, setSelectedPointData] = useState(); const { selectedEventData } = useSelectedEventData(); - const { getPointByUuid } = useProductStore(); + const { getPointByUuid, updateEvent, updateAction } = useProductStore(); const { selectedProduct } = useSelectedProduct(); useEffect(() => { if (selectedEventData) { - const point = getPointByUuid(selectedProduct.productId, selectedEventData?.data.modelUuid, selectedEventData?.selectedPoint); - if (point && 'action' in point) { - setSelectedPointData(point as PointsScheme & { action: { actionType: string } }); - setActiveOption((point as PointsScheme & { action: { actionType: string } }).action.actionType); + const point = getPointByUuid( + selectedProduct.productId, + selectedEventData.data.modelUuid, + selectedEventData.selectedPoint + ) as VehiclePointSchema | undefined; + + if (point) { + setSelectedPointData(point); + setActiveOption(point.action.actionType as "travel"); } } }, [selectedProduct, selectedEventData]) + const handleSpeedChange = (value: string) => { + if (!selectedEventData) return; + updateEvent( + selectedProduct.productId, + selectedEventData.data.modelUuid, + { speed: parseFloat(value) } + ); + }; + + const handleActionTypeChange = (option: string) => { + if (!selectedEventData || !selectedPointData) return; + const validOption = option as "travel"; + setActiveOption(validOption); + + updateAction( + selectedPointData.action.actionUuid, + { actionType: validOption } + ); + }; + + const handleRenameAction = (newName: string) => { + if (!selectedPointData) return; + updateAction( + selectedPointData.action.actionUuid, + { actionName: newName } + ); + }; + + const handleLoadCapacityChange = (value: string) => { + if (!selectedPointData) return; + updateAction( + selectedPointData.action.actionUuid, + { loadCapacity: parseFloat(value) } + ); + }; + + const handleUnloadDurationChange = (value: string) => { + if (!selectedPointData) return; + updateAction( + selectedPointData.action.actionUuid, + { unLoadDuration: parseFloat(value) } + ); + }; + + const handlePickPointChange = (value: string) => { + if (!selectedPointData) return; + const [x, y, z] = value.split(',').map(Number); + updateAction( + selectedPointData.action.actionUuid, + { pickUpPoint: { x, y, z } } + ); + }; + + const handleUnloadPointChange = (value: string) => { + if (!selectedPointData) return; + const [x, y, z] = value.split(',').map(Number); + updateAction( + selectedPointData.action.actionUuid, + { unLoadPoint: { x, y, z } } + ); + }; + + // Get current values from store + const currentSpeed = selectedEventData?.data.type === "vehicle" + ? selectedEventData.data.speed.toString() + : "0.5"; + + const currentActionName = selectedPointData + ? selectedPointData.action.actionName + : "Action Name"; + + const currentLoadCapacity = selectedPointData + ? selectedPointData.action.loadCapacity.toString() + : "1"; + + const currentUnloadDuration = selectedPointData + ? selectedPointData.action.unLoadDuration.toString() + : "1"; + + const currentPickPoint = selectedPointData?.action.pickUpPoint + ? `${selectedPointData.action.pickUpPoint.x},${selectedPointData.action.pickUpPoint.y},${selectedPointData.action.pickUpPoint.z}` + : ""; + + const currentUnloadPoint = selectedPointData?.action.unLoadPoint + ? `${selectedPointData.action.unLoadPoint.x},${selectedPointData.action.unLoadPoint.y},${selectedPointData.action.unLoadPoint.z}` + : ""; + const availableActions = { defaultOption: "travel", options: ["travel"], @@ -38,14 +130,14 @@ function VehicleMechanics() {
{ }} - onChange={(value) => console.log(value)} + onChange={handleSpeedChange} />
@@ -53,17 +145,44 @@ function VehicleMechanics() {
- +
setActiveOption(option)} + onSelect={handleActionTypeChange} /> - {activeOption === "travel" && } + + {activeOption === 'travel' && + + }
diff --git a/app/src/components/ui/inputs/PreviewSelectionWithUpload.tsx b/app/src/components/ui/inputs/PreviewSelectionWithUpload.tsx index e2c2936..3e14517 100644 --- a/app/src/components/ui/inputs/PreviewSelectionWithUpload.tsx +++ b/app/src/components/ui/inputs/PreviewSelectionWithUpload.tsx @@ -35,12 +35,6 @@ const PreviewSelectionWithUpload: React.FC = () => { Upload here
- console.log(option)} - />
); diff --git a/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts b/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts index 2378bf3..82b5596 100644 --- a/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts +++ b/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts @@ -243,7 +243,7 @@ function processLoadedModel( rotation: [0, 0, 0], action: { actionUuid: THREE.MathUtils.generateUUID(), - actionName: `Action ${index}`, + actionName: `Action ${index + 1}`, actionType: 'default', material: 'inherit', delay: 0, From c0e0bcb69d9880522313419f5e3d8884446cd7d8 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Fri, 25 Apr 2025 11:49:39 +0530 Subject: [PATCH 06/13] refactor: Update material default value and remove console logs for cleaner output --- .../modules/builder/IntialLoad/loadInitialFloorItems.ts | 2 +- .../instances/armInstance/roboticArmInstance.tsx | 4 ++-- .../roboticArm/instances/roboticArmInstances.tsx | 9 +++------ app/src/modules/simulation/roboticArm/roboticArm.tsx | 2 +- app/src/modules/simulation/simulation.tsx | 2 +- 5 files changed, 8 insertions(+), 11 deletions(-) diff --git a/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts b/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts index 82b5596..0359f1f 100644 --- a/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts +++ b/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts @@ -245,7 +245,7 @@ function processLoadedModel( actionUuid: THREE.MathUtils.generateUUID(), actionName: `Action ${index + 1}`, actionType: 'default', - material: 'inherit', + material: 'Default material', delay: 0, spawnInterval: 5, spawnCount: 1, diff --git a/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx index 42b775a..4b6e0a0 100644 --- a/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx +++ b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx @@ -7,12 +7,12 @@ import { useArmBotStore } from '../../../../../store/simulation/useArmBotStore'; function RoboticArmInstance({ armBot }: any) { const { isPlaying } = usePlayButtonStore(); const [currentPhase, setCurrentPhase] = useState<(string)>("init"); - console.log('currentPhase: ', currentPhase); + // console.log('currentPhase: ', currentPhase); const { armBots, addArmBot, addCurrentAction } = useArmBotStore(); useEffect(() => { - console.log('isPlaying: ', isPlaying); + // console.log('isPlaying: ', isPlaying); if (isPlaying) { //Moving armBot from initial point to rest position. diff --git a/app/src/modules/simulation/roboticArm/instances/roboticArmInstances.tsx b/app/src/modules/simulation/roboticArm/instances/roboticArmInstances.tsx index 1f963c8..6f578e9 100644 --- a/app/src/modules/simulation/roboticArm/instances/roboticArmInstances.tsx +++ b/app/src/modules/simulation/roboticArm/instances/roboticArmInstances.tsx @@ -9,12 +9,9 @@ function RoboticArmInstances() { return ( <> { - armBots?.map((robot: any) => ( - - - ) - ) - + armBots?.map((robot) => ( + + )) } diff --git a/app/src/modules/simulation/roboticArm/roboticArm.tsx b/app/src/modules/simulation/roboticArm/roboticArm.tsx index 4295ac7..89f6b76 100644 --- a/app/src/modules/simulation/roboticArm/roboticArm.tsx +++ b/app/src/modules/simulation/roboticArm/roboticArm.tsx @@ -86,7 +86,7 @@ function RoboticArm() { useEffect(() => { - console.log('armBots: ', armBots); + // console.log('armBots: ', armBots); }, [armBots]); return ( diff --git a/app/src/modules/simulation/simulation.tsx b/app/src/modules/simulation/simulation.tsx index 757a9ef..5ca0ec5 100644 --- a/app/src/modules/simulation/simulation.tsx +++ b/app/src/modules/simulation/simulation.tsx @@ -23,7 +23,7 @@ function Simulation() { }, [events]) useEffect(() => { - console.log('products: ', products); + // console.log('products: ', products); }, [products]) return ( From a1a1eacb795d4732b9f6d82d52312246167a2da3 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Fri, 25 Apr 2025 13:47:46 +0530 Subject: [PATCH 07/13] feat: Refactor event data handling and API integration; update variable names for consistency and clarity --- .../layout/sidebarRight/SideBarRight.tsx | 2 +- .../eventProperties/EventProperties.tsx | 131 ------------------ .../eventProperties/actions/StorageAction.tsx | 36 +++-- .../mechanics/machineMechanics.tsx | 1 - .../mechanics/storageMechanics.tsx | 80 +++++++++-- .../sidebarRight/simulation/Simulations.tsx | 2 +- .../instances/roboticArmInstances.tsx | 9 +- .../simulation/UpsertProductOrEventApi.ts | 26 ++++ .../services/simulation/deleteEventDataApi.ts | 26 ++++ .../simulation/deleteProductDataApi.ts | 25 ++++ app/src/services/simulation/getProductApi.ts | 25 ++++ .../services/simulation/getallProductsApi.ts | 25 ++++ app/src/services/simulation/temp.md | 0 app/src/store/simulation/useProductStore.ts | 42 +++--- app/src/types/simulationTypes.d.ts | 3 +- 15 files changed, 245 insertions(+), 188 deletions(-) create mode 100644 app/src/services/simulation/UpsertProductOrEventApi.ts create mode 100644 app/src/services/simulation/deleteEventDataApi.ts create mode 100644 app/src/services/simulation/deleteProductDataApi.ts create mode 100644 app/src/services/simulation/getProductApi.ts create mode 100644 app/src/services/simulation/getallProductsApi.ts delete mode 100644 app/src/services/simulation/temp.md diff --git a/app/src/components/layout/sidebarRight/SideBarRight.tsx b/app/src/components/layout/sidebarRight/SideBarRight.tsx index 5c37dec..38f0b18 100644 --- a/app/src/components/layout/sidebarRight/SideBarRight.tsx +++ b/app/src/components/layout/sidebarRight/SideBarRight.tsx @@ -37,7 +37,7 @@ const SideBarRight: React.FC = () => { useEffect(() => { if (activeModule !== "mechanics" && selectedEventData && selectedEventSphere) { setSubModule("mechanics"); - } else { + } else if (!selectedEventData && !selectedEventSphere) { if (activeModule === 'simulation') { setSubModule("simulations"); } diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx index 21781f0..ca32594 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx @@ -1,25 +1,4 @@ import React, { useEffect, useRef, useState } from "react"; -import InputWithDropDown from "../../../../ui/inputs/InputWithDropDown"; -import LabledDropdown from "../../../../ui/inputs/LabledDropdown"; -import { - AddIcon, - RemoveIcon, - ResizeHeightIcon, -} from "../../../../icons/ExportCommonIcons"; -import RenameInput from "../../../../ui/inputs/RenameInput"; -import { handleResize } from "../../../../../functions/handleResizePannel"; -import { handleActionToggle } from "./functions/handleActionToggle"; -import { handleDeleteAction } from "./functions/handleDeleteAction"; -import DefaultAction from "./actions/DefaultAction"; -import SpawnAction from "./actions/SpawnAction"; -import SwapAction from "./actions/SwapAction"; -import DespawnAction from "./actions/DespawnAction"; -import TravelAction from "./actions/TravelAction"; -import PickAndPlaceAction from "./actions/PickAndPlaceAction"; -import ProcessAction from "./actions/ProcessAction"; -import StorageAction from "./actions/StorageAction"; -import Trigger from "./trigger/Trigger"; - import { useSelectedEventData, useSelectedProduct } from "../../../../../store/simulation/useSimulationStore"; import { useProductStore } from "../../../../../store/simulation/useProductStore"; import ConveyorMechanics from "./mechanics/conveyorMechanics"; @@ -29,23 +8,11 @@ import MachineMechanics from "./mechanics/machineMechanics"; import StorageMechanics from "./mechanics/storageMechanics"; const EventProperties: React.FC = () => { - const actionsContainerRef = useRef(null); - - const [activeOption, setActiveOption] = useState("default"); - const [selectedItem, setSelectedItem] = useState<{ item: { uuid: string; name: string } | null; }>({ item: null }); const { selectedEventData } = useSelectedEventData(); const { getEventByModelUuid } = useProductStore(); const { selectedProduct } = useSelectedProduct(); - - // State for derived values const [currentEventData, setCurrentEventData] = useState(null); const [assetType, setAssetType] = useState(null); - const [availableActions, setAvailableActions] = useState({ - defaultOption: "default", - options: ["default"] - }); - const [actions, setActions] = useState<{ uuid: string; name: string }[]>([]); - const [speed, setSpeed] = useState("0.5"); useEffect(() => { const event = getCurrentEventData(); @@ -54,18 +21,6 @@ const EventProperties: React.FC = () => { const type = determineAssetType(event); setAssetType(type); - const actionsConfig = determineAvailableActions(type); - setAvailableActions(actionsConfig); - - const actionList = getActionList(event, type); - setActions(actionList); - - if (actionList.length > 0 && !selectedItem.item) { - setSelectedItem({ item: actionList[0] }); - } - - const currentSpeed = getCurrentSpeed(); - setSpeed(currentSpeed); }, [selectedEventData, selectedProduct]); const getCurrentEventData = () => { @@ -86,92 +41,6 @@ const EventProperties: React.FC = () => { } }; - const determineAvailableActions = (type: string | null) => { - switch (type) { - case "conveyor": - return { - defaultOption: "default", - options: ["default", "spawn", "swap", "despawn"], - }; - case "vehicle": - return { - defaultOption: "travel", - options: ["travel"], - }; - case "roboticArm": - return { - defaultOption: "pickAndPlace", - options: ["pickAndPlace"], - }; - case "machine": - return { - defaultOption: "process", - options: ["process"], - }; - case "storageUnit": - return { - defaultOption: "store", - options: ["store", "spawn"], - }; - default: - return { - defaultOption: "default", - options: ["default"], - }; - } - }; - - const getActionList = (event: EventsSchema | null, type: string | null) => { - if (!selectedEventData?.data) return []; - - switch (type) { - case "conveyor": - return (event as ConveyorEventSchema).points - .find((point) => point.uuid === selectedEventData?.selectedPoint) - ?.action?.triggers.map((trigger) => ({ - uuid: trigger.triggerUuid, - name: trigger.triggerName, - })) || []; - case "vehicle": - return (event as VehicleEventSchema).point.action.triggers.map( - (trigger) => ({ - uuid: trigger.triggerUuid, - name: trigger.triggerName, - }) - ) || []; - case "roboticArm": - return (event as RoboticArmEventSchema).point.actions.flatMap( - (action) => - action.triggers.map((trigger) => ({ - uuid: trigger.triggerUuid, - name: trigger.triggerName, - })) - ) || []; - case "machine": - return (event as MachineEventSchema).point.action.triggers.map( - (trigger) => ({ - uuid: trigger.triggerUuid, - name: trigger.triggerName, - }) - ) || []; - case "storageUnit": - return [ - { - uuid: (event as StorageEventSchema).point.action.actionUuid, - name: (event as StorageEventSchema).point.action.actionName, - }, - ]; - default: - return []; - } - }; - - const getCurrentSpeed = () => { - if (!selectedEventData) return "0.5"; - if ("speed" in selectedEventData.data) return selectedEventData.data.speed.toString(); - return "0.5"; - }; - return ( <>
diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/actions/StorageAction.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/StorageAction.tsx index ab2109b..5c9bf86 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/actions/StorageAction.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/StorageAction.tsx @@ -1,20 +1,28 @@ import React from "react"; import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown"; -const StorageAction: React.FC = () => { - return ( - {}} - onChange={(value) => console.log(value)} - /> - ); +interface StorageActionProps { + value: string; + min: number; + max: number; + defaultValue: string; + onChange: (value: string) => void; +} + +const StorageAction: React.FC = ({ value, min, max, defaultValue, onChange }) => { + return ( + { }} + onChange={onChange} + /> + ); }; export default StorageAction; diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/machineMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/machineMechanics.tsx index 138ed7c..e131864 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/machineMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/machineMechanics.tsx @@ -96,7 +96,6 @@ function MachineMechanics() { defaultOption="process" options={availableActions.options} onSelect={handleActionTypeChange} - disabled={true} /> {activeOption === "process" && (); + const [activeOption, setActiveOption] = useState<"default" | "store" | "spawn">("default"); + const [selectedPointData, setSelectedPointData] = useState(); const { selectedEventData } = useSelectedEventData(); - const { getPointByUuid } = useProductStore(); + const { getPointByUuid, updateAction } = useProductStore(); const { selectedProduct } = useSelectedProduct(); useEffect(() => { if (selectedEventData) { - const point = getPointByUuid(selectedProduct.productId, selectedEventData?.data.modelUuid, selectedEventData?.selectedPoint); + const point = getPointByUuid( + selectedProduct.productId, + selectedEventData?.data.modelUuid, + selectedEventData?.selectedPoint + ) as StoragePointSchema | undefined; if (point && 'action' in point) { - setSelectedPointData(point as PointsScheme & { action: { actionType: string } }); - setActiveOption((point as PointsScheme & { action: { actionType: string } }).action.actionType); + setSelectedPointData(point); + setActiveOption(point.action.actionType as "store" | "spawn"); } } }, [selectedProduct, selectedEventData]) + const handleActionTypeChange = (option: string) => { + if (!selectedEventData || !selectedPointData) return; + const validOption = option as "store" | "spawn"; + setActiveOption(validOption); + + updateAction( + selectedPointData.action.actionUuid, + { actionType: validOption } + ); + }; + + const handleRenameAction = (newName: string) => { + if (!selectedPointData) return; + updateAction( + selectedPointData.action.actionUuid, + { actionName: newName } + ); + }; + + const handleCapacityChange = (value: string) => { + if (!selectedPointData) return; + updateAction( + selectedPointData.action.actionUuid, + { storageCapacity: parseInt(value) } + ); + }; + + // Get current values from store + const currentActionName = selectedPointData + ? selectedPointData.action.actionName + : "Action Name"; + + const currentCapacity = selectedPointData + ? selectedPointData.action.storageCapacity.toString() + : "0"; + const availableActions = { defaultOption: "store", options: ["store", "spawn"], }; - + return ( <> {selectedEventData && <>
- +
setActiveOption(option)} + onSelect={handleActionTypeChange} /> - {activeOption === "store" && } + {activeOption === "store" && + + } + {activeOption === "spawn" && ( +
+

Spawn configuration options would go here

+
+ )}
diff --git a/app/src/components/layout/sidebarRight/simulation/Simulations.tsx b/app/src/components/layout/sidebarRight/simulation/Simulations.tsx index 12a424c..d6b4ac8 100644 --- a/app/src/components/layout/sidebarRight/simulation/Simulations.tsx +++ b/app/src/components/layout/sidebarRight/simulation/Simulations.tsx @@ -90,7 +90,7 @@ const Simulations: React.FC = () => { (product) => product.productId === selectedProduct.productId ); - const events: Event[] = selectedProductData?.eventsData.map((event) => ({ + const events: Event[] = selectedProductData?.eventDatas.map((event) => ({ pathName: event.modelName, })) || []; diff --git a/app/src/modules/simulation/roboticArm/instances/roboticArmInstances.tsx b/app/src/modules/simulation/roboticArm/instances/roboticArmInstances.tsx index 6f578e9..415c1d3 100644 --- a/app/src/modules/simulation/roboticArm/instances/roboticArmInstances.tsx +++ b/app/src/modules/simulation/roboticArm/instances/roboticArmInstances.tsx @@ -8,11 +8,10 @@ function RoboticArmInstances() { return ( <> - { - armBots?.map((robot) => ( - - )) - } + + {armBots?.map((robot) => ( + + ))} ) diff --git a/app/src/services/simulation/UpsertProductOrEventApi.ts b/app/src/services/simulation/UpsertProductOrEventApi.ts new file mode 100644 index 0000000..27fa126 --- /dev/null +++ b/app/src/services/simulation/UpsertProductOrEventApi.ts @@ -0,0 +1,26 @@ +let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; + +export const addProductOrEventApi = async (body: any) => { + try { + const response = await fetch(`${url_Backend_dwinzo}/api/v2/UpsertProductOrEvent`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(body), + }); + + if (!response.ok) { + throw new Error("Failed to add product or event"); + } + + const result = await response.json(); + return result; + } catch (error) { + if (error instanceof Error) { + throw new Error(error.message); + } else { + throw new Error("An unknown error occurred"); + } + } +}; diff --git a/app/src/services/simulation/deleteEventDataApi.ts b/app/src/services/simulation/deleteEventDataApi.ts new file mode 100644 index 0000000..f263065 --- /dev/null +++ b/app/src/services/simulation/deleteEventDataApi.ts @@ -0,0 +1,26 @@ +let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; + +export const deleteEventDataApi = async (body: any) => { + try { + const response = await fetch(`${url_Backend_dwinzo}/api/v2/EventDataDelete`, { + method: "PATCH", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(body), + }); + + if (!response.ok) { + throw new Error("Failed to delete event data"); + } + + const result = await response.json(); + return result; + } catch (error) { + if (error instanceof Error) { + throw new Error(error.message); + } else { + throw new Error("An unknown error occurred"); + } + } +}; diff --git a/app/src/services/simulation/deleteProductDataApi.ts b/app/src/services/simulation/deleteProductDataApi.ts new file mode 100644 index 0000000..06718f8 --- /dev/null +++ b/app/src/services/simulation/deleteProductDataApi.ts @@ -0,0 +1,25 @@ +let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; + +export const deleteProductDataApi = async (productId: string, organization: string) => { + try { + const response = await fetch(`${url_Backend_dwinzo}/api/v2/productDataDelete?productId=${productId}&organization=${organization}`, { + method: "PATCH", + headers: { + "Content-Type": "application/json", + }, + }); + + if (!response.ok) { + throw new Error("Failed to delete product data"); + } + + const result = await response.json(); + return result; + } catch (error) { + if (error instanceof Error) { + throw new Error(error.message); + } else { + throw new Error("An unknown error occurred"); + } + } +}; diff --git a/app/src/services/simulation/getProductApi.ts b/app/src/services/simulation/getProductApi.ts new file mode 100644 index 0000000..cf80013 --- /dev/null +++ b/app/src/services/simulation/getProductApi.ts @@ -0,0 +1,25 @@ +let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; + +export const getProductApi = async (productId: string, organization: string) => { + try { + const response = await fetch(`${url_Backend_dwinzo}/api/v2/productDatas?productId=${productId}&organization=${organization}`, { + method: "GET", + headers: { + "Content-Type": "application/json", + }, + }); + + if (!response.ok) { + throw new Error("Failed to fetch product data"); + } + + const result = await response.json(); + return result; + } catch (error) { + if (error instanceof Error) { + throw new Error(error.message); + } else { + throw new Error("An unknown error occurred"); + } + } +}; \ No newline at end of file diff --git a/app/src/services/simulation/getallProductsApi.ts b/app/src/services/simulation/getallProductsApi.ts new file mode 100644 index 0000000..46627f9 --- /dev/null +++ b/app/src/services/simulation/getallProductsApi.ts @@ -0,0 +1,25 @@ +let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; + +export const getAllProductsApi = async ( organization: string) => { + try { + const response = await fetch(`${url_Backend_dwinzo}/api/v2/AllProducts/${organization}`, { + method: "GET", + headers: { + "Content-Type": "application/json", + }, + }); + + if (!response.ok) { + throw new Error("Failed to fetch all products data"); + } + + const result = await response.json(); + return result; + } catch (error) { + if (error instanceof Error) { + throw new Error(error.message); + } else { + throw new Error("An unknown error occurred"); + } + } +}; \ No newline at end of file diff --git a/app/src/services/simulation/temp.md b/app/src/services/simulation/temp.md deleted file mode 100644 index e69de29..0000000 diff --git a/app/src/store/simulation/useProductStore.ts b/app/src/store/simulation/useProductStore.ts index 91576c7..8ec74cf 100644 --- a/app/src/store/simulation/useProductStore.ts +++ b/app/src/store/simulation/useProductStore.ts @@ -7,7 +7,7 @@ type ProductsStore = { // Product-level actions addProduct: (productName: string, productId: string) => void; removeProduct: (productId: string) => void; - updateProduct: (productId: string, updates: Partial<{ productName: string; eventsData: EventsSchema[] }>) => void; + updateProduct: (productId: string, updates: Partial<{ productName: string; eventDatas: EventsSchema[] }>) => void; // Event-level actions addEvent: (productId: string, event: EventsSchema) => void; @@ -54,7 +54,7 @@ type ProductsStore = { renameTrigger: (triggerUuid: string, newName: string) => void; // Helper functions - getProductById: (productId: string) => { productName: string; productId: string; eventsData: EventsSchema[] } | undefined; + getProductById: (productId: string) => { productName: string; productId: string; eventDatas: EventsSchema[] } | undefined; getEventByModelUuid: (productId: string, modelUuid: string) => EventsSchema | 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; @@ -72,7 +72,7 @@ export const useProductStore = create()( const newProduct = { productName, productId: productId, - eventsData: [] + eventDatas: [] }; state.products.push(newProduct); }); @@ -98,7 +98,7 @@ export const useProductStore = create()( set((state) => { const product = state.products.find(p => p.productId === productId); if (product) { - product.eventsData.push(event); + product.eventDatas.push(event); } }); }, @@ -107,7 +107,7 @@ export const useProductStore = create()( set((state) => { const product = state.products.find(p => p.productId === productId); if (product) { - product.eventsData = product.eventsData.filter(e => 'modelUuid' in e && e.modelUuid !== modelUuid); + product.eventDatas = product.eventDatas.filter(e => 'modelUuid' in e && e.modelUuid !== modelUuid); } }); }, @@ -116,7 +116,7 @@ export const useProductStore = create()( set((state) => { const product = state.products.find(p => p.productId === productId); if (product) { - const event = product.eventsData.find(e => 'modelUuid' in e && e.modelUuid === modelUuid); + const event = product.eventDatas.find(e => 'modelUuid' in e && e.modelUuid === modelUuid); if (event) { Object.assign(event, updates); } @@ -129,7 +129,7 @@ export const useProductStore = create()( set((state) => { const product = state.products.find(p => p.productId === productId); if (product) { - const event = product.eventsData.find(e => 'modelUuid' in e && e.modelUuid === modelUuid); + const event = product.eventDatas.find(e => 'modelUuid' in e && e.modelUuid === modelUuid); if (event && 'points' in event) { (event as ConveyorEventSchema).points.push(point as ConveyorPointSchema); } else if (event && 'point' in event) { @@ -143,7 +143,7 @@ export const useProductStore = create()( set((state) => { const product = state.products.find(p => p.productId === productId); if (product) { - const event = product.eventsData.find(e => 'modelUuid' in e && e.modelUuid === modelUuid); + const event = product.eventDatas.find(e => 'modelUuid' in e && e.modelUuid === modelUuid); if (event && 'points' in event) { (event as ConveyorEventSchema).points = (event as ConveyorEventSchema).points.filter(p => p.uuid !== pointUuid); } else if (event && 'point' in event && (event as any).point.uuid === pointUuid) { @@ -157,7 +157,7 @@ export const useProductStore = create()( set((state) => { const product = state.products.find(p => p.productId === productId); if (product) { - const event = product.eventsData.find(e => 'modelUuid' in e && e.modelUuid === modelUuid); + const event = product.eventDatas.find(e => 'modelUuid' in e && e.modelUuid === modelUuid); if (event && 'points' in event) { const point = (event as ConveyorEventSchema).points.find(p => p.uuid === pointUuid); if (point) { @@ -175,7 +175,7 @@ export const useProductStore = create()( set((state) => { const product = state.products.find(p => p.productId === productId); if (product) { - const event = product.eventsData.find(e => 'modelUuid' in e && e.modelUuid === modelUuid); + const event = product.eventDatas.find(e => 'modelUuid' in e && e.modelUuid === modelUuid); if (event && 'points' in event) { const point = (event as ConveyorEventSchema).points.find(p => p.uuid === pointUuid); if (point) { @@ -195,7 +195,7 @@ export const useProductStore = create()( removeAction: (actionUuid: string) => { set((state) => { for (const product of state.products) { - for (const event of product.eventsData) { + for (const event of product.eventDatas) { if ('points' in event) { // Handle ConveyorEventSchema for (const point of (event as ConveyorEventSchema).points) { @@ -219,7 +219,7 @@ export const useProductStore = create()( updateAction: (actionUuid, updates) => { set((state) => { for (const product of state.products) { - for (const event of product.eventsData) { + for (const event of product.eventDatas) { if ('points' in event) { for (const point of (event as ConveyorEventSchema).points) { if (point.action && point.action.actionUuid === actionUuid) { @@ -249,7 +249,7 @@ export const useProductStore = create()( addTrigger: (actionUuid, trigger) => { set((state) => { for (const product of state.products) { - for (const event of product.eventsData) { + for (const event of product.eventDatas) { if ('points' in event) { for (const point of (event as ConveyorEventSchema).points) { if (point.action && point.action.actionUuid === actionUuid) { @@ -278,7 +278,7 @@ export const useProductStore = create()( removeTrigger: (triggerUuid) => { set((state) => { for (const product of state.products) { - for (const event of product.eventsData) { + for (const event of product.eventDatas) { if ('points' in event) { for (const point of (event as ConveyorEventSchema).points) { if (point.action && 'triggers' in point.action) { @@ -305,7 +305,7 @@ export const useProductStore = create()( updateTrigger: (triggerUuid, updates) => { set((state) => { for (const product of state.products) { - for (const event of product.eventsData) { + for (const event of product.eventDatas) { if ('points' in event) { for (const point of (event as ConveyorEventSchema).points) { if (point.action && 'triggers' in point.action) { @@ -354,7 +354,7 @@ export const useProductStore = create()( renameAction: (actionUuid, newName) => { set((state) => { for (const product of state.products) { - for (const event of product.eventsData) { + for (const event of product.eventDatas) { if ('points' in event) { for (const point of (event as ConveyorEventSchema).points) { if (point.action && point.action.actionUuid === actionUuid) { @@ -383,7 +383,7 @@ export const useProductStore = create()( renameTrigger: (triggerUuid, newName) => { set((state) => { for (const product of state.products) { - for (const event of product.eventsData) { + for (const event of product.eventDatas) { if ('points' in event) { for (const point of (event as ConveyorEventSchema).points) { if (point.action && 'triggers' in point.action) { @@ -427,7 +427,7 @@ export const useProductStore = create()( getEventByModelUuid: (productId, modelUuid) => { const product = get().getProductById(productId); if (!product) return undefined; - return product.eventsData.find(e => 'modelUuid' in e && e.modelUuid === modelUuid); + return product.eventDatas.find(e => 'modelUuid' in e && e.modelUuid === modelUuid); }, getPointByUuid: (productId, modelUuid, pointUuid) => { @@ -446,7 +446,7 @@ export const useProductStore = create()( const product = get().products.find(p => p.productId === productId); if (!product) return undefined; - for (const event of product.eventsData) { + for (const event of product.eventDatas) { if ('points' in event) { for (const point of (event as ConveyorEventSchema).points) { if (point.action?.actionUuid === actionUuid) { @@ -470,7 +470,7 @@ export const useProductStore = create()( const product = get().products.find(p => p.productId === productId); if (!product) return undefined; - for (const event of product.eventsData) { + for (const event of product.eventDatas) { if ('points' in event) { for (const point of (event as ConveyorEventSchema).points) { for (const trigger of point.action?.triggers || []) { @@ -504,7 +504,7 @@ export const useProductStore = create()( getIsEventInProduct: (productId, modelUuid) => { const product = get().getProductById(productId); if (!product) return false; - return product.eventsData.some(e => 'modelUuid' in e && e.modelUuid === modelUuid); + return product.eventDatas.some(e => 'modelUuid' in e && e.modelUuid === modelUuid); } })) ); diff --git a/app/src/types/simulationTypes.d.ts b/app/src/types/simulationTypes.d.ts index 12c0dc2..eb49368 100644 --- a/app/src/types/simulationTypes.d.ts +++ b/app/src/types/simulationTypes.d.ts @@ -126,7 +126,7 @@ type EventsSchema = ConveyorEventSchema | VehicleEventSchema | RoboticArmEventSc type productsSchema = { productName: string; productId: string; - eventsData: EventsSchema[]; + eventDatas: EventsSchema[]; }[] @@ -135,6 +135,7 @@ interface ConveyorStatus extends ConveyorEventSchema { isActive: boolean; idleTime: number; activeTime: number; + } interface MachineStatus extends MachineEventSchema { From d7a22f5bfbd4e5c9edc717aa1bbecb4414833fa5 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Fri, 25 Apr 2025 16:06:24 +0530 Subject: [PATCH 08/13] feat: Refactor PickAndPlaceAction component to accept props for pick and place points; enhance RoboticArmMechanics with action handling and state management --- .../actions/PickAndPlaceAction.tsx | 26 +- .../mechanics/roboticArmMechanics.tsx | 366 +++++++++++------- app/src/components/ui/list/List.tsx | 3 - .../simulation/roboticArm/roboticArm.tsx | 2 + app/src/modules/simulation/simulation.tsx | 2 +- .../store/simulation/useSimulationStore.ts | 24 ++ 6 files changed, 281 insertions(+), 142 deletions(-) diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/actions/PickAndPlaceAction.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/PickAndPlaceAction.tsx index 9574669..175a824 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/actions/PickAndPlaceAction.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/PickAndPlaceAction.tsx @@ -1,13 +1,25 @@ import React from "react"; import EyeDropInput from "../../../../../ui/inputs/EyeDropInput"; -const PickAndPlaceAction: React.FC = () => { - return ( - <> - {}} /> - {}} /> - - ); +interface PickAndPlaceActionProps { + pickPointValue: string; + pickPointOnChange: (value: string) => void; + placePointValue: string; + placePointOnChange: (value: string) => void; +} + +const PickAndPlaceAction: React.FC = ({ + pickPointValue, + pickPointOnChange, + placePointValue, + placePointOnChange, +}) => { + return ( + <> + + + + ); }; export default PickAndPlaceAction; diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/roboticArmMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/roboticArmMechanics.tsx index 9a044ac..78a32f5 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/roboticArmMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/roboticArmMechanics.tsx @@ -4,7 +4,7 @@ import InputWithDropDown from '../../../../../ui/inputs/InputWithDropDown' import RenameInput from '../../../../../ui/inputs/RenameInput' import LabledDropdown from '../../../../../ui/inputs/LabledDropdown' import Trigger from '../trigger/Trigger' -import { useSelectedEventData, useSelectedProduct } from "../../../../../../store/simulation/useSimulationStore"; +import { useSelectedEventData, useSelectedProduct, useSelectedAction } from "../../../../../../store/simulation/useSimulationStore"; import { useProductStore } from "../../../../../../store/simulation/useProductStore"; import { AddIcon, RemoveIcon, ResizeHeightIcon } from '../../../../../icons/ExportCommonIcons' import { handleResize } from '../../../../../../functions/handleResizePannel' @@ -12,159 +12,263 @@ import PickAndPlaceAction from '../actions/PickAndPlaceAction' function RoboticArmMechanics() { const actionsContainerRef = useRef(null); - - const [activeOption, setActiveOption] = useState("pickAndPlace"); - const [selectedItem, setSelectedItem] = useState<{ item: { uuid: string; name: string } | null; }>({ item: null }); + const [activeOption, setActiveOption] = useState<"default" | "pickAndPlace">("default"); + const [selectedPointData, setSelectedPointData] = useState(); const { selectedEventData } = useSelectedEventData(); - const { getEventByModelUuid, addAction } = useProductStore(); + const { getPointByUuid, updateEvent, updateAction, addAction, removeAction } = useProductStore(); const { selectedProduct } = useSelectedProduct(); - - const availableActions = { - defaultOption: "pickAndPlace", - options: ["pickAndPlace"] - }; - const [actions, setActions] = useState<{ uuid: string; name: string }[]>([]); + const { selectedAction, setSelectedAction, clearSelectedAction } = useSelectedAction(); useEffect(() => { - const event = getCurrentEventData(); - const actionList = getActionList(event as RoboticArmEventSchema); - setActions(actionList); - - if (actionList.length > 0 && !selectedItem.item) { - setSelectedItem({ item: actionList[0] }); + if (selectedEventData) { + const point = getPointByUuid( + selectedProduct.productId, + selectedEventData.data.modelUuid, + selectedEventData.selectedPoint + ) as RoboticArmPointSchema | undefined; + if (point) { + setSelectedPointData(point); + setActiveOption(point.actions[0].actionType as "default" | "pickAndPlace"); + if (point.actions.length > 0 && !selectedAction.actionId) { + setSelectedAction(point.actions[0].actionUuid, point.actions[0].actionName); + } + } + } else { + clearSelectedAction(); } }, [selectedEventData, selectedProduct]); - const getCurrentEventData = () => { - if (!selectedEventData?.data || !selectedProduct) return null; - return getEventByModelUuid(selectedProduct.productId, selectedEventData.data.modelUuid) || null; - }; - - const getActionList = (event: RoboticArmEventSchema) => { - if (!event || !('point' in event)) return []; - - return event.point.actions.flatMap( - (action) => - action.triggers.map((trigger) => ({ - uuid: trigger.triggerUuid, - name: trigger.triggerName, - })) - ) || []; - }; - - const handleActionToggle = (actionUuid: string) => { - const action = actions.find(a => a.uuid === actionUuid); - if (action) { - setSelectedItem({ item: action }); - } + const handleActionSelect = (actionUuid: string, actionName: string) => { + setSelectedAction(actionUuid, actionName); }; const handleAddAction = () => { - if (selectedEventData) { - const newEvent = { - actionUuid: THREE.MathUtils.generateUUID(), - actionName: `Action ${actions.length + 1}`, - actionType: "pickAndPlace" as const, - process: { - startPoint: null as [number, number, number] | null, - endPoint: null as [number, number, number] | null - }, - triggers: [] as TriggerSchema[] - } - addAction( - selectedProduct.productId, - selectedEventData?.data.modelUuid, - selectedEventData?.selectedPoint, - newEvent - ) - } + if (!selectedEventData || !selectedPointData) return; + + const newAction = { + actionUuid: THREE.MathUtils.generateUUID(), + actionName: `Action ${selectedPointData.actions.length + 1}`, + actionType: "pickAndPlace" as "pickAndPlace", + process: { + startPoint: null, + endPoint: null + }, + triggers: [] as TriggerSchema[] + }; + + addAction( + selectedProduct.productId, + selectedEventData.data.modelUuid, + selectedEventData.selectedPoint, + newAction + ); + + const updatedPoint = { + ...selectedPointData, + actions: [...selectedPointData.actions, newAction] + }; + setSelectedPointData(updatedPoint); + setSelectedAction(newAction.actionUuid, newAction.actionName); }; const handleDeleteAction = (actionUuid: string) => { + if (!selectedPointData) return; + removeAction(actionUuid); + const newActions = selectedPointData.actions.filter(a => a.actionUuid !== actionUuid); + + const updatedPoint = { + ...selectedPointData, + actions: newActions + }; + setSelectedPointData(updatedPoint); + + if (selectedAction.actionId === actionUuid) { + if (newActions.length > 0) { + setSelectedAction(newActions[0].actionUuid, newActions[0].actionName); + } else { + clearSelectedAction(); + } + } }; + const handleRenameAction = (newName: string) => { + if (!selectedAction.actionId) return; + updateAction( + selectedAction.actionId, + { actionName: newName } + ); + + if (selectedPointData) { + const updatedActions = selectedPointData.actions.map(action => + action.actionUuid === selectedAction.actionId + ? { ...action, actionName: newName } + : action + ); + setSelectedPointData({ + ...selectedPointData, + actions: updatedActions + }); + } + }; + + const handleSpeedChange = (value: string) => { + if (!selectedEventData) return; + updateEvent( + selectedProduct.productId, + selectedEventData.data.modelUuid, + { speed: parseFloat(value) } + ); + }; + + const handlePickPointChange = (value: string) => { + if (!selectedAction.actionId || !selectedPointData) return; + const [x, y, z] = value.split(',').map(Number); + + updateAction( + selectedAction.actionId, + { + process: { + startPoint: [x, y, z] as [number, number, number], + endPoint: selectedPointData.actions.find(a => a.actionUuid === selectedAction.actionId)?.process.endPoint || null + } + } + ); + }; + + const handlePlacePointChange = (value: string) => { + if (!selectedAction.actionId || !selectedPointData) return; + const [x, y, z] = value.split(',').map(Number); + + updateAction( + selectedAction.actionId, + { + process: { + startPoint: selectedPointData.actions.find(a => a.actionUuid === selectedAction.actionId)?.process.startPoint || null, + endPoint: [x, y, z] as [number, number, number] + } + } + ); + }; + + const availableActions = { + defaultOption: "pickAndPlace", + options: ["pickAndPlace"], + }; + + const currentSpeed = selectedEventData?.data.type === "roboticArm" + ? selectedEventData.data.speed.toString() + : "0.5"; + + const currentAction = selectedPointData?.actions.find(a => a.actionUuid === selectedAction.actionId); + const currentPickPoint = currentAction?.process.startPoint + ? `${currentAction.process.startPoint[0]},${currentAction.process.startPoint[1]},${currentAction.process.startPoint[2]}` + : ""; + const currentPlacePoint = currentAction?.process.endPoint + ? `${currentAction.process.endPoint[0]},${currentAction.process.endPoint[1]},${currentAction.process.endPoint[2]}` + : ""; + return ( <> -
-
-
- { }} - onChange={(value) => console.log(value)} - /> -
-
-
-
-
-
-
Actions
-
handleAddAction()}> - Add + {selectedEventData && selectedPointData && ( + <> +
+
+
+ { }} + onChange={handleSpeedChange} + /> +
-
-
- {actions.map((action) => ( -
-
handleActionToggle(action.uuid)} - > - -
- {actions.length > 1 && ( -
handleDeleteAction(action.uuid)} - > - -
- )} + +
+
+
+
Actions
+
+ Add
- ))} -
-
handleResize(e, actionsContainerRef)} - > - +
+
+
+ {selectedPointData.actions.map((action) => ( +
+
handleActionSelect(action.actionUuid, action.actionName)} + > + +
+ {selectedPointData.actions.length > 1 && ( +
handleDeleteAction(action.actionUuid)} + > + +
+ )} +
+ ))} +
+
handleResize(e, actionsContainerRef)} + > + +
+
-
-
-
-
- -
-
- setActiveOption(option)} - /> - {activeOption === "pickAndPlace" && } -
-
-
- -
+ + {selectedAction.actionId && currentAction && ( +
+
+ +
+
+ { }} + disabled={true} + /> + +
+
+ +
+
+ )} + + )} ) } diff --git a/app/src/components/ui/list/List.tsx b/app/src/components/ui/list/List.tsx index cac0b43..ac21c5a 100644 --- a/app/src/components/ui/list/List.tsx +++ b/app/src/components/ui/list/List.tsx @@ -142,9 +142,6 @@ const List: React.FC = ({ items = [], remove }) => { ) ); } - - console.log('newName: ', newName); - } const checkZoneNameDuplicate = (name: string) => { return zones.some( diff --git a/app/src/modules/simulation/roboticArm/roboticArm.tsx b/app/src/modules/simulation/roboticArm/roboticArm.tsx index 89f6b76..d403c6a 100644 --- a/app/src/modules/simulation/roboticArm/roboticArm.tsx +++ b/app/src/modules/simulation/roboticArm/roboticArm.tsx @@ -94,6 +94,8 @@ function RoboticArm() { + <> + ); } diff --git a/app/src/modules/simulation/simulation.tsx b/app/src/modules/simulation/simulation.tsx index 5ca0ec5..757a9ef 100644 --- a/app/src/modules/simulation/simulation.tsx +++ b/app/src/modules/simulation/simulation.tsx @@ -23,7 +23,7 @@ function Simulation() { }, [events]) useEffect(() => { - // console.log('products: ', products); + console.log('products: ', products); }, [products]) return ( diff --git a/app/src/store/simulation/useSimulationStore.ts b/app/src/store/simulation/useSimulationStore.ts index ae6ac81..5085688 100644 --- a/app/src/store/simulation/useSimulationStore.ts +++ b/app/src/store/simulation/useSimulationStore.ts @@ -90,4 +90,28 @@ export const useSelectedProduct = create()( }); }, })) +); + +interface SelectedActionState { + selectedAction: { actionId: string; actionName: string }; + setSelectedAction: (actionId: string, actionName: string) => void; + clearSelectedAction: () => void; +} + +export const useSelectedAction = create()( + immer((set) => ({ + selectedAction: { actionId: '', actionName: '' }, + setSelectedAction: (actionId, actionName) => { + set((state) => { + state.selectedAction.actionId = actionId; + state.selectedAction.actionName = actionName; + }); + }, + clearSelectedAction: () => { + set((state) => { + state.selectedAction.actionId = ''; + state.selectedAction.actionName = ''; + }); + }, + })) ); \ No newline at end of file From 70a99316ba3f4d1385f05f05fcd100bc1cb44c0e Mon Sep 17 00:00:00 2001 From: Poovizhi99 Date: Fri, 25 Apr 2025 17:57:38 +0530 Subject: [PATCH 09/13] added stationed-pickup and pickup to drop functionality added --- .../instances/animator/vehicleAnimator.tsx | 206 ++++++++++++++---- .../instances/instance/vehicleInstance.tsx | 139 ++++++++---- .../vehicle/instances/vehicleInstances.tsx | 6 +- .../modules/simulation/vehicle/vehicles.tsx | 68 +++--- 4 files changed, 288 insertions(+), 131 deletions(-) diff --git a/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx b/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx index 137d679..0d59f2b 100644 --- a/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx +++ b/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx @@ -1,61 +1,179 @@ import { useFrame, useThree } from '@react-three/fiber'; -import React, { useEffect, useState } from 'react' +import React, { useEffect, useRef, useState } from 'react'; +import { useFloorItems } from '../../../../../store/store'; +import * as THREE from 'three'; +import { Line } from '@react-three/drei'; +import { useAnimationPlaySpeed, usePauseButtonStore, useResetButtonStore } from '../../../../../store/usePlayButtonStore'; +import { useVehicleStore } from '../../../../../store/simulation/useVehicleStore'; interface VehicleAnimatorProps { - path: [number, number, number][]; - handleCallBack: () => void; - currentPhase: string; - agvUuid: number + path: [number, number, number][]; + handleCallBack: () => void; + currentPhase: string; + agvUuid: number; + agvDetail: any; } +function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetail }: VehicleAnimatorProps) { + const { updateVehicleLoad, vehicles } = useVehicleStore(); + const { isPaused } = usePauseButtonStore(); + const { speed } = useAnimationPlaySpeed(); + const { isReset } = useResetButtonStore(); + const [restRotation, setRestingRotation] = useState(true); + const [progress, setProgress] = useState(0); + const [currentPath, setCurrentPath] = useState<[number, number, number][]>([]); + const { scene } = useThree(); + const progressRef = useRef(0); + const movingForward = useRef(true); + const completedRef = useRef(false); + let startTime: number; + let pausedTime: number; + let fixedInterval: number; -function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid }: VehicleAnimatorProps) { - const [progress, setProgress] = useState(0) - const [currentPath, setCurrentPath] = useState<[number, number, number][]>([]); - const { scene } = useThree(); + useEffect(() => { + if (currentPhase === 'stationed-pickup' && path.length > 0) { + setCurrentPath(path); + } else if (currentPhase === 'pickup-drop' && path.length > 0) { + setCurrentPath(path); + } else if (currentPhase === 'drop-pickup' && path.length > 0) { + setCurrentPath(path); + } + }, [currentPhase, path]); - useEffect(() => { + useEffect(() => { + setProgress(0); + completedRef.current = false; + }, [currentPath]); - if (currentPhase === 'stationed-pickup' && path.length > 0) { - setCurrentPath(path); + useFrame((_, delta) => { + const object = scene.getObjectByProperty('uuid', agvUuid); + if (!object || currentPath.length < 2) return; + if (isPaused) return; + + let totalDistance = 0; + const distances = []; + + for (let i = 0; i < currentPath.length - 1; i++) { + const start = new THREE.Vector3(...currentPath[i]); + const end = new THREE.Vector3(...currentPath[i + 1]); + const segmentDistance = start.distanceTo(end); + distances.push(segmentDistance); + totalDistance += segmentDistance; + } + + let coveredDistance = progressRef.current; + let accumulatedDistance = 0; + let index = 0; + + while ( + index < distances.length && + coveredDistance > accumulatedDistance + distances[index] + ) { + accumulatedDistance += distances[index]; + index++; + } + + if (index < distances.length) { + const start = new THREE.Vector3(...currentPath[index]); + const end = new THREE.Vector3(...currentPath[index + 1]); + const segmentDistance = distances[index]; + + const currentDirection = new THREE.Vector3().subVectors(end, start).normalize(); + const targetAngle = Math.atan2(currentDirection.x, currentDirection.z); + const rotationSpeed = 2.0; + const currentAngle = object.rotation.y; + + let angleDifference = targetAngle - currentAngle; + if (angleDifference > Math.PI) angleDifference -= 2 * Math.PI; + if (angleDifference < -Math.PI) angleDifference += 2 * Math.PI; + + const maxRotationStep = rotationSpeed * delta; + object.rotation.y += Math.sign(angleDifference) * Math.min(Math.abs(angleDifference), maxRotationStep); + + const isAligned = Math.abs(angleDifference) < 0.01; + + if (isAligned) { + progressRef.current += delta * (speed * agvDetail.speed); + coveredDistance = progressRef.current; + + const t = (coveredDistance - accumulatedDistance) / segmentDistance; + const position = start.clone().lerp(end, t); + object.position.copy(position); + } + } + + if (progressRef.current >= totalDistance) { + if (restRotation) { + const targetQuaternion = new THREE.Quaternion().setFromEuler(new THREE.Euler(0, 0, 0)); + object.quaternion.slerp(targetQuaternion, delta * 2); + const angleDiff = object.quaternion.angleTo(targetQuaternion); + if (angleDiff < 0.01) { + let objectRotation = agvDetail.point.rotation + object.rotation.set(objectRotation[0], objectRotation[1], objectRotation[2]); + setRestingRotation(false); } + return; + } + } - }, [currentPhase, path]) - useFrame((_, delta) => { - if (!path || path.length < 2) return; + if (progressRef.current >= totalDistance) { + setRestingRotation(true); + progressRef.current = 0; + movingForward.current = !movingForward.current; + setCurrentPath([]); + handleCallBack(); + if (currentPhase === 'pickup-drop') { + requestAnimationFrame(firstFrame); + } + } + }); - const object = scene.getObjectByProperty("uuid", agvUuid) - if (!object) return; + function firstFrame() { + const unLoadDuration = agvDetail.point.action.unLoadDuration; + const droppedMaterial = agvDetail.currentLoad; + fixedInterval = (unLoadDuration / droppedMaterial) * 1000; + if (!isPaused) { + step(droppedMaterial); + } else { + pausedTime = performance.now(); + step(droppedMaterial); + } + } - setProgress(prev => { - const next = prev + delta * 0.1; // speed - return next >= 1 ? 1 : next; - }); + function step(droppedMaterial: number) { + if (!isPaused) { + startTime = performance.now(); + const elapsedTime = performance.now() - startTime - pausedTime; + if (elapsedTime >= fixedInterval) { + let droppedMat = droppedMaterial - 1; + updateVehicleLoad(agvDetail.modelUuid, droppedMat); + if (droppedMat === 0) return; + startTime = performance.now(); + pausedTime = 0; + requestAnimationFrame(() => step(droppedMat)); + } else { + requestAnimationFrame(() => step(droppedMaterial)); + } + } else { + requestAnimationFrame(() => firstFrame); + } + } - const totalSegments = path.length - 1; - const segmentIndex = Math.floor(progress * totalSegments); - const t = progress * totalSegments - segmentIndex; - - const start = path[segmentIndex]; - const end = path[segmentIndex + 1] || start; - - // Directly set position without creating a new Vector3 - object.position.x = start[0] + (end[0] - start[0]) * t; - object.position.y = start[1] + (end[1] - start[1]) * t; - object.position.z = start[2] + (end[2] - start[2]) * t; - }); - // useFrame(() => { - // if (currentPath.length === 0) return; - // const object = scene.getObjectByProperty("uuid", agvUuid); - // if (!object) return; - - - - // }) - return ( + return ( + <> + {currentPath.length > 0 && ( <> + + {currentPath.map((point, index) => ( + + + + + ))} - ) + )} + + ); } -export default VehicleAnimator \ No newline at end of file +export default VehicleAnimator; \ No newline at end of file diff --git a/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx b/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx index 646dabd..98d037c 100644 --- a/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx +++ b/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx @@ -1,67 +1,122 @@ -import React, { useCallback, useEffect, useState } from 'react' -import VehicleAnimator from '../animator/vehicleAnimator' -import * as THREE from "three"; +import React, { useCallback, useEffect, useState } from 'react'; +import VehicleAnimator from '../animator/vehicleAnimator'; +import * as THREE from 'three'; import { NavMeshQuery } from '@recast-navigation/core'; import { useNavMesh } from '../../../../../store/store'; import { usePlayButtonStore } from '../../../../../store/usePlayButtonStore'; import { useVehicleStore } from '../../../../../store/simulation/useVehicleStore'; -function VehicleInstance({ agvDetails }: any) { +function VehicleInstance({ agvDetail }: any) { const { navMesh } = useNavMesh(); const { isPlaying } = usePlayButtonStore(); - const { setVehicleActive, setVehicleState } = useVehicleStore(); - const [currentPhase, setCurrentPhase] = useState<(string)>("stationed"); + const { vehicles, setVehicleActive, setVehicleState, updateVehicleLoad } = useVehicleStore(); + const [currentPhase, setCurrentPhase] = useState('stationed'); const [path, setPath] = useState<[number, number, number][]>([]); - const computePath = useCallback((start: any, end: any) => { + const computePath = useCallback( + (start: any, end: any) => { + try { + const navMeshQuery = new NavMeshQuery(navMesh); + const { path: segmentPath } = navMeshQuery.computePath(start, end); + return ( + segmentPath?.map(({ x, y, z }) => [x, y + 0.1, z] as [number, number, number]) || [] + ); + } catch { + return []; + } + }, + [navMesh] + ); - - try { - const navMeshQuery = new NavMeshQuery(navMesh); - const { path: segmentPath } = navMeshQuery.computePath(start, end); - return ( - segmentPath?.map( - ({ x, y, z }) => [x, y + 0.1, z] as [number, number, number] - ) || [] - ); - } catch { - return []; - } - }, [navMesh]); + function vehicleStatus(modelid: string, status: string) { + // console.log(`AGV ${modelid}: ${status}`); + } useEffect(() => { - // const pickupToDropPath = computePath(pickup, drop); - // const dropToPickupPath = computePath(drop, pickup); - if (isPlaying) { - if (!agvDetails.isActive && agvDetails.state == "idle" && currentPhase == "stationed") { - const toPickupPath = computePath(new THREE.Vector3(agvDetails.position[0], agvDetails.position[1], agvDetails.position[2]), agvDetails.point.action.pickUpPoint); - setPath(toPickupPath) - setVehicleActive(agvDetails.modelUuid, true) - setVehicleState(agvDetails.modelUuid, "running") - setCurrentPhase("stationed-pickup") - // + if (!agvDetail.isActive && agvDetail.state === 'idle' && currentPhase === 'stationed') { + const toPickupPath = computePath( + new THREE.Vector3(agvDetail.position[0], agvDetail.position[1], agvDetail.position[2]), + agvDetail.point.action.pickUpPoint + ); + setPath(toPickupPath); + setVehicleActive(agvDetail.modelUuid, true); + setVehicleState(agvDetail.modelUuid, 'running'); + setCurrentPhase('stationed-pickup'); + vehicleStatus(agvDetail.modelUuid, 'Started from station, heading to pickup'); + return; + } else if ( + !agvDetail.isActive && + agvDetail.state === 'idle' && + currentPhase === 'picking' + ) { + setTimeout(() => { + updateVehicleLoad(agvDetail.modelUuid, 2); + }, 5000); + + if (agvDetail.currentLoad === agvDetail.point.action.loadCapacity) { + const toDrop = computePath( + agvDetail.point.action.pickUpPoint, + agvDetail.point.action.unLoadPoint + ); + setPath(toDrop); + setVehicleActive(agvDetail.modelUuid, true); + setVehicleState(agvDetail.modelUuid, 'running'); + setCurrentPhase('pickup-drop'); + vehicleStatus(agvDetail.modelUuid, 'Started from pickup point, heading to drop point'); + } + } else if ( + !agvDetail.isActive && + agvDetail.state === 'idle' && + currentPhase === 'dropping' && + agvDetail.currentLoad === 0 + ) { + const dropToPickup = computePath( + agvDetail.point.action.unLoadPoint, + agvDetail.point.action.pickUpPoint + ); + setPath(dropToPickup); + setVehicleActive(agvDetail.modelUuid, true); + setVehicleState(agvDetail.modelUuid, 'running'); + setCurrentPhase('drop-pickup'); + vehicleStatus(agvDetail.modelUuid, 'Started from dropping point, heading to pickup point'); } } - }, [agvDetails, currentPhase, path, isPlaying]) + }, [vehicles, currentPhase, path, isPlaying]); function handleCallBack() { - if (currentPhase === "stationed-pickup") { - setVehicleActive(agvDetails.modelUuid, false) - setVehicleState(agvDetails.modelUuid, "idle") - setCurrentPhase("picking") - setPath([]) + if (currentPhase === 'stationed-pickup') { + setVehicleActive(agvDetail.modelUuid, false); + setVehicleState(agvDetail.modelUuid, 'idle'); + setCurrentPhase('picking'); + vehicleStatus(agvDetail.modelUuid, 'Reached pickup point, waiting for material'); + setPath([]); + } else if (currentPhase === 'pickup-drop') { + setVehicleActive(agvDetail.modelUuid, false); + setVehicleState(agvDetail.modelUuid, 'idle'); + setCurrentPhase('dropping'); + vehicleStatus(agvDetail.modelUuid, 'Reached drop point'); + setPath([]); + } else if (currentPhase === 'drop-pickup') { + setVehicleActive(agvDetail.modelUuid, false); + setVehicleState(agvDetail.modelUuid, 'idle'); + setCurrentPhase('picking'); + setPath([]); + vehicleStatus(agvDetail.modelUuid, 'Reached pickup point again, cycle complete'); } } - return ( <> - - - + - ) + ); } -export default VehicleInstance \ No newline at end of file +export default VehicleInstance; \ No newline at end of file diff --git a/app/src/modules/simulation/vehicle/instances/vehicleInstances.tsx b/app/src/modules/simulation/vehicle/instances/vehicleInstances.tsx index f3f1435..2a0070b 100644 --- a/app/src/modules/simulation/vehicle/instances/vehicleInstances.tsx +++ b/app/src/modules/simulation/vehicle/instances/vehicleInstances.tsx @@ -1,12 +1,14 @@ import React from 'react' import VehicleInstance from './instance/vehicleInstance' +import { useVehicleStore } from '../../../../store/simulation/useVehicleStore' -function VehicleInstances({ vehicles }: any) { +function VehicleInstances() { + const { vehicles } = useVehicleStore(); return ( <> {vehicles.map((val: any, i: any) => - + )} diff --git a/app/src/modules/simulation/vehicle/vehicles.tsx b/app/src/modules/simulation/vehicle/vehicles.tsx index b9bc07b..6c5ea34 100644 --- a/app/src/modules/simulation/vehicle/vehicles.tsx +++ b/app/src/modules/simulation/vehicle/vehicles.tsx @@ -1,34 +1,36 @@ import React, { useEffect } from 'react' import VehicleInstances from './instances/vehicleInstances'; - import { useVehicleStore } from '../../../store/simulation/useVehicleStore'; +import { useFloorItems } from '../../../store/store'; function Vehicles() { const { vehicles, addVehicle } = useVehicleStore(); - const vehicleStatusSample: VehicleStatus[] = [ + const { floorItems } = useFloorItems(); + + const vehicleStatusSample: VehicleEventSchema[] = [ { - modelUuid: "2c01ed76-359a-485b-83d4-052cfcdb9d89", + modelUuid: "9356f710-4727-4b50-bdb2-9c1e747ecc74", modelName: "AGV", - position: [10, 0, 5], + position: [97.9252965204558, 0, 37.96138815638661], rotation: [0, 0, 0], state: "idle", type: "vehicle", speed: 2.5, point: { uuid: "point-789", - position: [93.42159216649789, 0, 23.790878603572857], + position: [0, 1, 0], rotation: [0, 0, 0], action: { actionUuid: "action-456", actionName: "Deliver to Zone A", actionType: "travel", material: "crate", - unLoadDuration: 15, - loadCapacity: 5, - pickUpPoint: { x: 5, y: 0, z: 3 }, - unLoadPoint: { x: 20, y: 0, z: 10 }, + unLoadDuration: 10, + loadCapacity: 2, + pickUpPoint: { x: 98.71483985219794, y: 0, z: 28.66321267938962 }, + unLoadPoint: { x: 105.71483985219794, y: 0, z: 28.66321267938962 }, triggers: [ { triggerUuid: "trig-001", @@ -50,18 +52,12 @@ function Vehicles() { } ] } - }, - productId: "prod-890", - isActive: false, - idleTime: 0, - activeTime: 0, - currentLoad: 0, - distanceTraveled: 0 + } }, { - modelUuid: "311130b9-4f2e-425a-b3b5-5039cb348806", + modelUuid: "b06960bb-3d2e-41f7-a646-335f389c68b4", modelName: "AGV", - position: [95.69567023145055, 0, 33.18042399595448], + position: [89.61609306554463, 0, 33.634136622267356], rotation: [0, 0, 0], state: "idle", type: "vehicle", @@ -75,9 +71,9 @@ function Vehicles() { actionName: "Deliver to Zone A", actionType: "travel", material: "crate", - unLoadDuration: 15, - loadCapacity: 5, - pickUpPoint: { x: 5, y: 0, z: 3 }, + unLoadDuration: 10, + loadCapacity: 2, + pickUpPoint: { x: 90, y: 0, z: 28 }, unLoadPoint: { x: 20, y: 0, z: 10 }, triggers: [ { @@ -100,17 +96,11 @@ function Vehicles() { } ] } - }, - productId: "prod-890", - isActive: false, - idleTime: 0, - activeTime: 0, - currentLoad: 0, - distanceTraveled: 0 + } }, { - modelUuid: "fa54132c-8333-4832-becb-5281f5e11549", - modelName: "AGV", - position: [102.71483985219794, 0, 23.66321267938962], + modelUuid: "e729a4f1-11d2-4778-8d6a-468f1b4f6b79", + modelName: "forklift", + position: [98.85729337188162, 0, 38.36616546567653], rotation: [0, 0, 0], state: "idle", type: "vehicle", @@ -126,7 +116,7 @@ function Vehicles() { material: "crate", unLoadDuration: 15, loadCapacity: 5, - pickUpPoint: { x: 5, y: 0, z: 3 }, + pickUpPoint: { x: 98.71483985219794, y: 0, z: 28.66321267938962 }, unLoadPoint: { x: 20, y: 0, z: 10 }, triggers: [ { @@ -149,13 +139,7 @@ function Vehicles() { } ] } - }, - productId: "prod-890", - isActive: false, - idleTime: 0, - activeTime: 0, - currentLoad: 0, - distanceTraveled: 0 + } } ]; @@ -163,7 +147,7 @@ function Vehicles() { useEffect(() => { addVehicle('123', vehicleStatusSample[0]); addVehicle('123', vehicleStatusSample[1]); - addVehicle('123', vehicleStatusSample[2]); + // addVehicle('123', vehicleStatusSample[2]); }, []) useEffect(() => { @@ -173,9 +157,7 @@ function Vehicles() { return ( <> - - - + ) } From 81b353307b01bee7c6f15ff3eb2d755a76e7c456 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Fri, 25 Apr 2025 18:29:01 +0530 Subject: [PATCH 10/13] feat: Integrate upsertProductOrEventApi in Simulations and Products components; adjust loadInitialFloorItems to accept renderDistance parameter; update material handling in addAssetModel and Vehicles components --- .../sidebarRight/simulation/Simulations.tsx | 6 ++++++ .../builder/IntialLoad/loadInitialFloorItems.ts | 4 ++-- .../builder/geomentries/assets/addAssetModel.ts | 15 +++++++-------- .../modules/builder/groups/floorItemsGroup.tsx | 4 ++-- app/src/modules/simulation/products/products.tsx | 14 ++++++++++++++ .../roboticArm/instances/roboticArmInstances.tsx | 1 - .../modules/simulation/roboticArm/roboticArm.tsx | 9 ++------- app/src/modules/simulation/vehicle/vehicles.tsx | 2 -- .../simulation/UpsertProductOrEventApi.ts | 2 +- app/src/types/simulationTypes.d.ts | 1 - 10 files changed, 34 insertions(+), 24 deletions(-) diff --git a/app/src/components/layout/sidebarRight/simulation/Simulations.tsx b/app/src/components/layout/sidebarRight/simulation/Simulations.tsx index d6b4ac8..926ce44 100644 --- a/app/src/components/layout/sidebarRight/simulation/Simulations.tsx +++ b/app/src/components/layout/sidebarRight/simulation/Simulations.tsx @@ -12,6 +12,7 @@ import { useProductStore } from "../../../../store/simulation/useProductStore"; import { generateUUID } from "three/src/math/MathUtils"; import RenderOverlay from "../../../templates/Overlay"; import EditWidgetOption from "../../../ui/menu/EditWidgetOption"; +import { upsertProductOrEventApi } from "../../../../services/simulation/UpsertProductOrEventApi"; interface Event { pathName: string; @@ -75,6 +76,11 @@ const Simulations: React.FC = () => { const handleAddEventToProduct = () => { if (selectedAsset) { addEvent(selectedProduct.productId, selectedAsset); + // upsertProductOrEventApi({ + // productName: selectedProduct.productName, + // productId: selectedProduct.productId, + // eventDatas: selectedAsset + // }); clearSelectedAsset(); } }; diff --git a/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts b/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts index 0359f1f..c46c0e7 100644 --- a/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts +++ b/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts @@ -14,6 +14,7 @@ async function loadInitialFloorItems( itemsGroup: Types.RefGroup, setFloorItems: Types.setFloorItemSetState, addEvent: (event: EventsSchema) => void, + renderDistance: number ): Promise { if (!itemsGroup.current) return; let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`; @@ -65,7 +66,7 @@ async function loadInitialFloorItems( const cameraPosition = new THREE.Vector3(storedPosition.x, storedPosition.y, storedPosition.z); - if (cameraPosition.distanceTo(itemPosition) < 50) { + if (cameraPosition.distanceTo(itemPosition) < renderDistance) { await new Promise(async (resolve) => { // Check Three.js Cache @@ -210,7 +211,6 @@ function processLoadedModel( actionUuid: THREE.MathUtils.generateUUID(), actionName: "Vehicle Action", actionType: "travel", - material: null, unLoadDuration: 5, loadCapacity: 10, pickUpPoint: null, diff --git a/app/src/modules/builder/geomentries/assets/addAssetModel.ts b/app/src/modules/builder/geomentries/assets/addAssetModel.ts index 670c7b5..d7c278c 100644 --- a/app/src/modules/builder/geomentries/assets/addAssetModel.ts +++ b/app/src/modules/builder/geomentries/assets/addAssetModel.ts @@ -202,7 +202,7 @@ async function handleModelLoad( actionUuid: THREE.MathUtils.generateUUID(), actionName: `Action ${index}`, actionType: 'default', - material: 'inherit', + material: 'Default Material', delay: 0, spawnInterval: 5, spawnCount: 1, @@ -226,9 +226,8 @@ async function handleModelLoad( rotation: [0, 0, 0], action: { actionUuid: THREE.MathUtils.generateUUID(), - actionName: "Vehicle Action", + actionName: "Action 1", actionType: "travel", - material: null, unLoadDuration: 5, loadCapacity: 10, pickUpPoint: null, @@ -254,11 +253,11 @@ async function handleModelLoad( actions: [ { actionUuid: THREE.MathUtils.generateUUID(), - actionName: "Pick and Place", + actionName: "Action 1", actionType: "pickAndPlace", process: { - startPoint: [0, 0, 0], - endPoint: [0, 0, 0] + startPoint: null, + endPoint: null }, triggers: [] } @@ -280,10 +279,10 @@ async function handleModelLoad( rotation: [0, 0, 0], action: { actionUuid: THREE.MathUtils.generateUUID(), - actionName: "Process Action", + actionName: "Action 1", actionType: "process", processTime: 10, - swapMaterial: "material-id", + swapMaterial: "Default Material", triggers: [] } } diff --git a/app/src/modules/builder/groups/floorItemsGroup.tsx b/app/src/modules/builder/groups/floorItemsGroup.tsx index 241f628..f3f5050 100644 --- a/app/src/modules/builder/groups/floorItemsGroup.tsx +++ b/app/src/modules/builder/groups/floorItemsGroup.tsx @@ -75,7 +75,7 @@ const FloorItemsGroup = ({ itemsGroup, hoveredDeletableFloorItem, AttachedObject gltfLoaderWorker.postMessage({ floorItems: data }); } else { gltfLoaderWorker.postMessage({ floorItems: [] }); - loadInitialFloorItems(itemsGroup, setFloorItems, addEvent); + loadInitialFloorItems(itemsGroup, setFloorItems, addEvent, renderDistance); updateLoadingProgress(100); } }); @@ -94,7 +94,7 @@ const FloorItemsGroup = ({ itemsGroup, hoveredDeletableFloorItem, AttachedObject updateLoadingProgress(progress); if (loadedAssets === totalAssets) { - loadInitialFloorItems(itemsGroup, setFloorItems, addEvent); + loadInitialFloorItems(itemsGroup, setFloorItems, addEvent, renderDistance); updateLoadingProgress(100); } }); diff --git a/app/src/modules/simulation/products/products.tsx b/app/src/modules/simulation/products/products.tsx index 2ddd7d1..b883824 100644 --- a/app/src/modules/simulation/products/products.tsx +++ b/app/src/modules/simulation/products/products.tsx @@ -2,6 +2,8 @@ import React, { useEffect } from 'react' import { useProductStore } from '../../../store/simulation/useProductStore' import * as THREE from 'three'; import { useSelectedProduct } from '../../../store/simulation/useSimulationStore'; +import { upsertProductOrEventApi } from '../../../services/simulation/UpsertProductOrEventApi'; +import { getAllProductsApi } from '../../../services/simulation/getallProductsApi'; function Products() { const { products, addProduct } = useProductStore(); @@ -12,10 +14,22 @@ function Products() { const id = THREE.MathUtils.generateUUID(); const name = 'Product 1'; addProduct(name, id); + // upsertProductOrEventApi({ productName: name, productId: id }).then((data) => { + // console.log('data: ', data); + // }); setSelectedProduct(id, name); } }, [products]) + useEffect(() => { + // const email = localStorage.getItem('email') + // const organization = (email!.split("@")[1]).split(".")[0]; + // console.log(organization); + // getAllProductsApi(organization).then((data) => { + // console.log('data: ', data); + // }) + }, []) + return ( <> diff --git a/app/src/modules/simulation/roboticArm/instances/roboticArmInstances.tsx b/app/src/modules/simulation/roboticArm/instances/roboticArmInstances.tsx index 415c1d3..46125db 100644 --- a/app/src/modules/simulation/roboticArm/instances/roboticArmInstances.tsx +++ b/app/src/modules/simulation/roboticArm/instances/roboticArmInstances.tsx @@ -5,7 +5,6 @@ import { useArmBotStore } from '../../../../store/simulation/useArmBotStore'; function RoboticArmInstances() { const { armBots } = useArmBotStore(); - return ( <> diff --git a/app/src/modules/simulation/roboticArm/roboticArm.tsx b/app/src/modules/simulation/roboticArm/roboticArm.tsx index d403c6a..52382db 100644 --- a/app/src/modules/simulation/roboticArm/roboticArm.tsx +++ b/app/src/modules/simulation/roboticArm/roboticArm.tsx @@ -3,15 +3,11 @@ import RoboticArmInstances from "./instances/roboticArmInstances"; import { useArmBotStore } from "../../../store/simulation/useArmBotStore"; function RoboticArm() { - const { armBots, addArmBot, addCurrentAction } = useArmBotStore(); + const { armBots, addArmBot, removeArmBot, addCurrentAction } = useArmBotStore(); const armBotStatusSample: RoboticArmEventSchema[] = [ { state: "idle", - // currentAction: { - // actionUuid: "action-001", - // actionName: "Pick Component", - // }, modelUuid: "armbot-xyz-001", modelName: "ArmBot-X200", position: [0, 0, 0], @@ -80,6 +76,7 @@ function RoboticArm() { ]; useEffect(() => { + removeArmBot(armBotStatusSample[0].modelUuid); addArmBot('123', armBotStatusSample[0]); // addCurrentAction('armbot-xyz-001', 'action-001'); }, []); @@ -94,8 +91,6 @@ function RoboticArm() { - <> - ); } diff --git a/app/src/modules/simulation/vehicle/vehicles.tsx b/app/src/modules/simulation/vehicle/vehicles.tsx index 3364717..1da7ced 100644 --- a/app/src/modules/simulation/vehicle/vehicles.tsx +++ b/app/src/modules/simulation/vehicle/vehicles.tsx @@ -24,7 +24,6 @@ function Vehicles() { actionUuid: "action-456", actionName: "Deliver to Zone A", actionType: "travel", - material: "crate", unLoadDuration: 15, loadCapacity: 5, pickUpPoint: { x: 5, y: 0, z: 3 }, @@ -68,7 +67,6 @@ function Vehicles() { actionUuid: "action-456", actionName: "Deliver to Zone A", actionType: "travel", - material: "crate", unLoadDuration: 15, loadCapacity: 5, pickUpPoint: { x: 5, y: 0, z: 3 }, diff --git a/app/src/services/simulation/UpsertProductOrEventApi.ts b/app/src/services/simulation/UpsertProductOrEventApi.ts index 27fa126..e2f45d1 100644 --- a/app/src/services/simulation/UpsertProductOrEventApi.ts +++ b/app/src/services/simulation/UpsertProductOrEventApi.ts @@ -1,6 +1,6 @@ let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; -export const addProductOrEventApi = async (body: any) => { +export const upsertProductOrEventApi = async (body: any) => { try { const response = await fetch(`${url_Backend_dwinzo}/api/v2/UpsertProductOrEvent`, { method: "POST", diff --git a/app/src/types/simulationTypes.d.ts b/app/src/types/simulationTypes.d.ts index eb49368..3293699 100644 --- a/app/src/types/simulationTypes.d.ts +++ b/app/src/types/simulationTypes.d.ts @@ -42,7 +42,6 @@ interface VehiclePointSchema { actionUuid: string; actionName: string; actionType: "travel"; - material: string | null; unLoadDuration: number; loadCapacity: number; pickUpPoint: { x: number; y: number, z: number } | null; From 1ad0243204a9741ac21ed8f1b5144a72135d57cb Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Fri, 25 Apr 2025 19:31:56 +0530 Subject: [PATCH 11/13] feat: Add AddOrRemoveEventsInProducts component for event management in products; refactor TriggerConnector and update PointsCreator to improve event handling and mesh identification --- .../events/points/creator/pointsCreator.tsx | 4 + .../events/addOrRemoveEventsInProducts.tsx | 124 ++++++++++++++++++ .../modules/simulation/products/products.tsx | 8 +- app/src/modules/simulation/simulation.tsx | 2 +- .../simulation/simulator/simulator.tsx | 11 +- .../triggers/connector/triggerConnector.tsx | 75 ++++------- 6 files changed, 170 insertions(+), 54 deletions(-) create mode 100644 app/src/modules/simulation/products/events/addOrRemoveEventsInProducts.tsx diff --git a/app/src/modules/simulation/events/points/creator/pointsCreator.tsx b/app/src/modules/simulation/events/points/creator/pointsCreator.tsx index 1b3defa..bc2f4db 100644 --- a/app/src/modules/simulation/events/points/creator/pointsCreator.tsx +++ b/app/src/modules/simulation/events/points/creator/pointsCreator.tsx @@ -66,6 +66,7 @@ function PointsCreator() { {event.points.map((point, j) => ( (sphereRefs.current[point.uuid] = el!)} onClick={(e) => { @@ -90,6 +91,7 @@ function PointsCreator() { return ( (sphereRefs.current[event.point.uuid] = el!)} onClick={(e) => { @@ -112,6 +114,7 @@ function PointsCreator() { return ( (sphereRefs.current[event.point.uuid] = el!)} onClick={(e) => { @@ -134,6 +137,7 @@ function PointsCreator() { return ( (sphereRefs.current[event.point.uuid] = el!)} onClick={(e) => { diff --git a/app/src/modules/simulation/products/events/addOrRemoveEventsInProducts.tsx b/app/src/modules/simulation/products/events/addOrRemoveEventsInProducts.tsx new file mode 100644 index 0000000..9eececc --- /dev/null +++ b/app/src/modules/simulation/products/events/addOrRemoveEventsInProducts.tsx @@ -0,0 +1,124 @@ +import { useThree } from '@react-three/fiber' +import { useEffect } from 'react' +import { Object3D } from 'three'; +import { useSubModuleStore } from '../../../../store/useModuleStore'; +import { useLeftData, useTopData } from '../../../../store/visualization/useZone3DWidgetStore'; +import { useEventsStore } from '../../../../store/simulation/useEventsStore'; +import { useProductStore } from '../../../../store/simulation/useProductStore'; +import { useSelectedProduct } from '../../../../store/simulation/useSimulationStore'; +import { useSelectedAsset } from '../../../../store/simulation/useSimulationStore'; + +function AddOrRemoveEventsInProducts() { + const { gl, raycaster, scene } = useThree(); + const { subModule } = useSubModuleStore(); + const { setTop } = useTopData(); + const { setLeft } = useLeftData(); + const { getIsEventInProduct } = useProductStore(); + const { getEventByModelUuid } = useEventsStore(); + const { selectedProduct } = useSelectedProduct(); + const { selectedAsset, setSelectedAsset, clearSelectedAsset } = useSelectedAsset(); + + useEffect(() => { + + const canvasElement = gl.domElement; + + let drag = false; + let isRightMouseDown = false; + + const onMouseDown = (evt: MouseEvent) => { + if (selectedAsset) { + clearSelectedAsset(); + } + if (evt.button === 2) { + isRightMouseDown = true; + drag = false; + } + }; + + const onMouseUp = (evt: MouseEvent) => { + if (evt.button === 2) { + isRightMouseDown = false; + } + } + + const onMouseMove = () => { + if (isRightMouseDown) { + drag = true; + } + }; + + const handleRightClick = (evt: MouseEvent) => { + if (drag) return; + evt.preventDefault(); + const canvasElement = gl.domElement; + if (!canvasElement) return; + + let intersects = raycaster.intersectObjects(scene.children, true); + if (intersects.length > 0 && intersects[0]?.object?.parent?.parent?.position && intersects[0]?.object?.parent?.parent?.scale && intersects[0]?.object?.parent?.parent?.rotation) { + let currentObject = intersects[0].object; + + while (currentObject) { + if (currentObject.name === "Scene") { + break; + } + currentObject = currentObject.parent as Object3D; + } + if (currentObject) { + const isInProduct = getIsEventInProduct(selectedProduct.productId, currentObject.uuid); + + if (isInProduct) { + const event = getEventByModelUuid(currentObject.uuid); + if (event) { + setSelectedAsset(event) + const canvasRect = canvasElement.getBoundingClientRect(); + const relativeX = evt.clientX - canvasRect.left; + const relativeY = evt.clientY - canvasRect.top; + + setTop(relativeY); + setLeft(relativeX); + } else { + clearSelectedAsset() + } + } else { + const event = getEventByModelUuid(currentObject.uuid); + if (event) { + setSelectedAsset(event) + const canvasRect = canvasElement.getBoundingClientRect(); + const relativeX = evt.clientX - canvasRect.left; + const relativeY = evt.clientY - canvasRect.top; + + setTop(relativeY); + setLeft(relativeX); + } else { + clearSelectedAsset() + } + } + + } + } else { + clearSelectedAsset() + } + + }; + + if (subModule === 'simulations') { + canvasElement.addEventListener("mousedown", onMouseDown); + canvasElement.addEventListener("mouseup", onMouseUp); + canvasElement.addEventListener("mousemove", onMouseMove); + canvasElement.addEventListener('contextmenu', handleRightClick); + } + + return () => { + canvasElement.removeEventListener("mousedown", onMouseDown); + canvasElement.removeEventListener("mouseup", onMouseUp); + canvasElement.removeEventListener("mousemove", onMouseMove); + canvasElement.removeEventListener('contextmenu', handleRightClick); + }; + + }, [gl, subModule, selectedProduct, selectedAsset]); + return ( + <> + ) +} + +export default AddOrRemoveEventsInProducts \ No newline at end of file diff --git a/app/src/modules/simulation/products/products.tsx b/app/src/modules/simulation/products/products.tsx index b883824..38175e2 100644 --- a/app/src/modules/simulation/products/products.tsx +++ b/app/src/modules/simulation/products/products.tsx @@ -1,7 +1,8 @@ -import React, { useEffect } from 'react' -import { useProductStore } from '../../../store/simulation/useProductStore' import * as THREE from 'three'; +import { useEffect } from 'react'; +import { useProductStore } from '../../../store/simulation/useProductStore'; import { useSelectedProduct } from '../../../store/simulation/useSimulationStore'; +import AddOrRemoveEventsInProducts from './events/addOrRemoveEventsInProducts'; import { upsertProductOrEventApi } from '../../../services/simulation/UpsertProductOrEventApi'; import { getAllProductsApi } from '../../../services/simulation/getallProductsApi'; @@ -32,6 +33,9 @@ function Products() { return ( <> + + + ) } diff --git a/app/src/modules/simulation/simulation.tsx b/app/src/modules/simulation/simulation.tsx index 757a9ef..5ca0ec5 100644 --- a/app/src/modules/simulation/simulation.tsx +++ b/app/src/modules/simulation/simulation.tsx @@ -23,7 +23,7 @@ function Simulation() { }, [events]) useEffect(() => { - console.log('products: ', products); + // console.log('products: ', products); }, [products]) return ( diff --git a/app/src/modules/simulation/simulator/simulator.tsx b/app/src/modules/simulation/simulator/simulator.tsx index 8cc22d6..c4f1c40 100644 --- a/app/src/modules/simulation/simulator/simulator.tsx +++ b/app/src/modules/simulation/simulator/simulator.tsx @@ -1,9 +1,16 @@ -import React from 'react' +import { useEffect } from 'react' +import { useProductStore } from '../../../store/simulation/useProductStore' function Simulator() { + const { products } = useProductStore(); + + useEffect(() => { + // console.log('products: ', products); + }, [products]) + return ( <> - + ) } diff --git a/app/src/modules/simulation/triggers/connector/triggerConnector.tsx b/app/src/modules/simulation/triggers/connector/triggerConnector.tsx index b38e6dd..f836ea4 100644 --- a/app/src/modules/simulation/triggers/connector/triggerConnector.tsx +++ b/app/src/modules/simulation/triggers/connector/triggerConnector.tsx @@ -1,22 +1,16 @@ -import { useThree } from '@react-three/fiber' -import React, { useEffect } from 'react' -import { Object3D } from 'three'; -import { useSubModuleStore } from '../../../../store/useModuleStore'; -import { useLeftData, useTopData } from '../../../../store/visualization/useZone3DWidgetStore'; -import { useEventsStore } from '../../../../store/simulation/useEventsStore'; -import { useProductStore } from '../../../../store/simulation/useProductStore'; -import { useSelectedProduct } from '../../../../store/simulation/useSimulationStore'; -import { useSelectedAsset } from '../../../../store/simulation/useSimulationStore'; +import { useEffect } from "react"; +import { useThree } from "@react-three/fiber"; +import { useSubModuleStore } from "../../../../store/useModuleStore"; +import { useSelectedAsset } from "../../../../store/simulation/useSimulationStore"; +import { useProductStore } from "../../../../store/simulation/useProductStore"; +import { useSelectedProduct } from "../../../../store/simulation/useSimulationStore"; function TriggerConnector() { const { gl, raycaster, scene } = useThree(); const { subModule } = useSubModuleStore(); - const { setTop } = useTopData(); - const { setLeft } = useLeftData(); - const { getIsEventInProduct } = useProductStore(); - const { getEventByModelUuid } = useEventsStore(); + const { getPointByUuid, getIsEventInProduct } = useProductStore(); + const { selectedAsset, clearSelectedAsset } = useSelectedAsset(); const { selectedProduct } = useSelectedProduct(); - const { selectedAsset, setSelectedAsset, clearSelectedAsset } = useSelectedAsset(); useEffect(() => { @@ -57,48 +51,31 @@ function TriggerConnector() { if (intersects.length > 0 && intersects[0]?.object?.parent?.parent?.position && intersects[0]?.object?.parent?.parent?.scale && intersects[0]?.object?.parent?.parent?.rotation) { let currentObject = intersects[0].object; - while (currentObject) { - if (currentObject.name === "Scene") { - break; - } - currentObject = currentObject.parent as Object3D; - } - if (currentObject) { - const isInProduct = getIsEventInProduct(selectedProduct.productId, currentObject.uuid); + if (currentObject && currentObject.name === 'Event-Sphere') { + + const isInProduct = getIsEventInProduct( + selectedProduct.productId, + currentObject.userData.modelUuid + ); + + // You left Here if (isInProduct) { - const event = getEventByModelUuid(currentObject.uuid); - if (event) { - setSelectedAsset(event) - const canvasRect = canvasElement.getBoundingClientRect(); - const relativeX = evt.clientX - canvasRect.left; - const relativeY = evt.clientY - canvasRect.top; - setTop(relativeY); - setLeft(relativeX); - } else { - clearSelectedAsset() - } + const event = getPointByUuid( + selectedProduct.productId, + currentObject.userData.modelUuid, + currentObject.userData.pointUuid + ); + console.log('event: ', event); } else { - const event = getEventByModelUuid(currentObject.uuid); - if (event) { - setSelectedAsset(event) - const canvasRect = canvasElement.getBoundingClientRect(); - const relativeX = evt.clientX - canvasRect.left; - const relativeY = evt.clientY - canvasRect.top; - setTop(relativeY); - setLeft(relativeX); - } else { - clearSelectedAsset() - } } - } - } else { - clearSelectedAsset() - } + } else { + + } }; if (subModule === 'simulations') { @@ -115,7 +92,7 @@ function TriggerConnector() { canvasElement.removeEventListener('contextmenu', handleRightClick); }; - }, [gl, subModule, selectedProduct, selectedAsset]); + }, [gl, subModule]); return ( <> From 05d8405188a9748994bf1a23c2b996cf1e9ef44d Mon Sep 17 00:00:00 2001 From: Gomathi9520 Date: Fri, 25 Apr 2025 19:40:15 +0530 Subject: [PATCH 12/13] armbot trigger --- .../instances/animator/roboticArmAnimator.tsx | 62 ++++++- .../armInstance/roboticArmInstance.tsx | 175 +++++++++++++++--- .../instances/ikInstance/ikInstance.tsx | 85 ++++++++- .../roboticArm/instances/ikInstances.tsx | 14 -- .../instances/roboticArmInstances.tsx | 12 +- .../simulation/roboticArm/roboticArm.tsx | 91 +++++++-- app/src/store/simulation/useArmBotStore.ts | 13 +- app/src/store/simulation/useVehicleStore.ts | 1 + 8 files changed, 382 insertions(+), 71 deletions(-) delete mode 100644 app/src/modules/simulation/roboticArm/instances/ikInstances.tsx diff --git a/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx b/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx index 6b35a43..fd7590e 100644 --- a/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx +++ b/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx @@ -1,6 +1,64 @@ -import React from 'react' +import React, { useEffect, useMemo, useRef, useState } from 'react' +import { useArmBotStore } from '../../../../../store/simulation/useArmBotStore'; +import { useFrame, useThree } from '@react-three/fiber'; +import * as THREE from "three" +import { usePlayButtonStore } from '../../../../../store/usePlayButtonStore'; + +function RoboticArmAnimator({ armUuid, HandleCallback, currentPhase, ikSolver, targetBone, robot, logStatus, groupRef, processes, armBotCurveRef, path }: any) { + const { armBots } = useArmBotStore(); + const { scene } = useThree(); + const restSpeed = 0.1; + const restPosition = new THREE.Vector3(0, 2, 1.6); + const initialCurveRef = useRef(null); + const initialStartPositionRef = useRef(null); + const [initialProgress, setInitialProgress] = useState(0); + const [progress, setProgress] = useState(0); + const [needsInitialMovement, setNeedsInitialMovement] = useState(true); + const [isInitializing, setIsInitializing] = useState(true); + const { isPlaying } = usePlayButtonStore(); + const statusRef = useRef("idle"); + // Create a ref for initialProgress + const initialProgressRef = useRef(0); + const [currentPath, setCurrentPath] = useState<[number, number, number][]>([]); + + useEffect(() => { + setCurrentPath(path) + }, [path]) + + useEffect(() => { + + }, [currentPath]) + + useFrame((_, delta) => { + if (!ikSolver || !currentPath || currentPath.length === 0) return; + + const bone = ikSolver.mesh.skeleton.bones.find( + (b: any) => b.name === targetBone + ); + if (!bone) return; + + // Ensure currentPath is a valid array of 3D points, create a CatmullRomCurve3 from it + const curve = new THREE.CatmullRomCurve3( + currentPath.map(point => new THREE.Vector3(point[0], point[1], point[2])) + ); + + const next = initialProgressRef.current + delta * 0.5; + if (next >= 1) { + bone.position.copy(restPosition); + HandleCallback(); // Call the callback when the path is completed + initialProgressRef.current = 0; // Set ref to 1 when done + } else { + + const point = curve.getPoint(next); // Get the interpolated point from the curve + bone.position.copy(point); // Update the bone position along the curve + initialProgressRef.current = next; // Update progress + } + + ikSolver.update(); + }); + + -function RoboticArmAnimator({ armUuid, HandleCallback, currentPhase }: any) { return ( <> ) diff --git a/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx index 42b775a..86eee6a 100644 --- a/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx +++ b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx @@ -1,58 +1,179 @@ -import React, { useEffect, useState } from 'react' +import React, { useEffect, useRef, useState } from 'react' import IKInstance from '../ikInstance/ikInstance'; import RoboticArmAnimator from '../animator/roboticArmAnimator'; import { usePlayButtonStore } from '../../../../../store/usePlayButtonStore'; import { useArmBotStore } from '../../../../../store/simulation/useArmBotStore'; +import armModel from "../../../../../assets/gltf-glb/rigged/ik_arm_4.glb"; +import { useThree } from "@react-three/fiber"; +import { useFloorItems } from '../../../../../store/store'; +import useModuleStore from '../../../../../store/useModuleStore'; +import { Vector3 } from "three"; +import * as THREE from "three"; + +interface Process { + triggerId: string; + startPoint?: Vector3; + endPoint?: Vector3; + speed: number; +} +function RoboticArmInstance({ robot }: { robot: ArmBotStatus }) { -function RoboticArmInstance({ armBot }: any) { const { isPlaying } = usePlayButtonStore(); const [currentPhase, setCurrentPhase] = useState<(string)>("init"); - console.log('currentPhase: ', currentPhase); - const { armBots, addArmBot, addCurrentAction } = useArmBotStore(); + const { scene } = useThree(); + const targetBone = "Target"; + const { activeModule } = useModuleStore(); + const [ikSolver, setIkSolver] = useState(null); + const { addCurrentAction, setArmBotActive, setArmBotState, removeCurrentAction } = useArmBotStore(); + const { floorItems } = useFloorItems(); + const groupRef = useRef(null); + const [processes, setProcesses] = useState([]); + const [armBotCurvePoints, setArmBotCurvePoints] = useState({ start: [], end: [] }) + const restPosition = new THREE.Vector3(0, 2, 1.6); + let armBotCurveRef = useRef(null) + const [path, setPath] = useState<[number, number, number][]>([]); useEffect(() => { + let armItems = floorItems?.filter((val: any) => + val.modeluuid === "3abf5d46-b59e-4e6b-9c02-a4634b64b82d" + ); + // Get the first matching item + let armItem = armItems?.[0]; + if (armItem) { + const targetMesh = scene?.getObjectByProperty("uuid", armItem.modeluuid); + if (targetMesh) { + targetMesh.visible = activeModule !== "simulation" + } + } + const targetBones = ikSolver?.mesh.skeleton.bones.find( + (b: any) => b.name === targetBone + ); - console.log('isPlaying: ', isPlaying); if (isPlaying) { //Moving armBot from initial point to rest position. - - if (armBot?.isActive && armBot?.state == "idle" && currentPhase == "init") { - addCurrentAction(armBot.modelUuid, 'action-001'); - setCurrentPhase("moving-to-rest"); - + if (!robot?.isActive && robot?.state == "idle" && currentPhase == "init") { + + setArmBotActive(robot.modelUuid, true) + setArmBotState(robot.modelUuid, "running") + setCurrentPhase("init-to-rest"); + if (targetBones) { + let curve = createCurveBetweenTwoPoints(targetBones.position, restPosition) + if (curve) { + setPath(curve.points.map(point => [point.x, point.y, point.z])); + } + } + logStatus(robot.modelUuid, "Starting from init to rest") } //Waiting for trigger. - if (!armBot?.isActive && armBot?.state == "idle" && currentPhase == "moving-to-rest") { - setCurrentPhase("rest"); + else if (robot && !robot.isActive && robot.state === "idle" && currentPhase === "rest" && !robot.currentAction) { + console.log("trigger"); + setTimeout(() => { + addCurrentAction(robot.modelUuid, 'action-003'); + }, 3000); } - // Moving armBot from rest position to pick up point. - if (!armBot?.isActive && armBot?.state == "idle" && currentPhase == "rest") { - + else if (robot && !robot.isActive && robot.state === "idle" && currentPhase === "rest" && robot.currentAction) { + if (robot.currentAction) { + setArmBotActive(robot.modelUuid, true); + setArmBotState(robot.modelUuid, "running"); + setCurrentPhase("rest-to-start"); + const startPoint = robot.point.actions[0].process.startPoint; + if (startPoint) { + let curve = createCurveBetweenTwoPoints(restPosition, new THREE.Vector3(startPoint[0], startPoint[1], startPoint[2])); + if (curve) { + setPath(curve.points.map(point => [point.x, point.y, point.z])); + } + } + } + logStatus(robot.modelUuid, "Starting from rest to start") } - //Moving arm from start point to end point. - if (armBot?.isActive && armBot?.state == "running " && currentPhase == "rest-to-start ") { - + else if (robot && !robot.isActive && robot.state === "idle" && currentPhase === "picking" && robot.currentAction) { + setArmBotActive(robot.modelUuid, true); + setArmBotState(robot.modelUuid, "running"); + setCurrentPhase("start-to-end"); + const startPoint = robot.point.actions[0].process.startPoint; + const endPoint = robot.point.actions[0].process.endPoint; + if (startPoint && endPoint) { + let curve = createCurveBetweenTwoPoints( + new THREE.Vector3(startPoint[0], startPoint[1], startPoint[2]), + new THREE.Vector3(endPoint[0], endPoint[1], endPoint[2]) + ); + if (curve) { + setPath(curve.points.map(point => [point.x, point.y, point.z])); + } + } + logStatus(robot.modelUuid, "Starting from start to end") } - //Moving arm from end point to idle. - if (armBot?.isActive && armBot?.state == "running" && currentPhase == "end-to-start") { - + else if (robot && !robot.isActive && robot.state === "idle" && currentPhase === "dropping" && robot.currentAction) { + setArmBotActive(robot.modelUuid, true); + setArmBotState(robot.modelUuid, "running"); + setCurrentPhase("end-to-rest"); + const endPoint = robot.point.actions[0].process.endPoint; + if (endPoint) { + let curve = createCurveBetweenTwoPoints(new THREE.Vector3(endPoint[0], endPoint[1], endPoint[2]), restPosition + ); + if (curve) { + setPath(curve.points.map(point => [point.x, point.y, point.z])); + } + } + logStatus(robot.modelUuid, "Starting from end to rest") } - } - }, [currentPhase, armBot, isPlaying]) + }, [currentPhase, robot, isPlaying, ikSolver]) + + + function createCurveBetweenTwoPoints(p1: any, p2: any) { + const mid = new THREE.Vector3().addVectors(p1, p2).multiplyScalar(0.5); + mid.y += 0.5; + + const points = [p1, mid, p2]; + return new THREE.CatmullRomCurve3(points); + } + const HandleCallback = () => { - if (armBot.isActive && armBot.state == "idle" && currentPhase == "init") { - addCurrentAction('armbot-xyz-001', 'action-001'); + if (robot.isActive && robot.state == "running" && currentPhase == "init-to-rest") { + console.log("Callback triggered: rest"); + setArmBotActive(robot.modelUuid, false) + setArmBotState(robot.modelUuid, "idle") + setCurrentPhase("rest"); + setPath([]) } + else if (robot.isActive && robot.state == "running" && currentPhase == "rest-to-start") { + console.log("Callback triggered: pick."); + setArmBotActive(robot.modelUuid, false) + setArmBotState(robot.modelUuid, "idle") + setCurrentPhase("picking"); + setPath([]) + } + else if (robot.isActive && robot.state == "running" && currentPhase == "start-to-end") { + console.log("Callback triggered: drop."); + setArmBotActive(robot.modelUuid, false) + setArmBotState(robot.modelUuid, "idle") + setCurrentPhase("dropping"); + setPath([]) + } + else if (robot.isActive && robot.state == "running" && currentPhase == "end-to-rest") { + console.log("Callback triggered: rest, cycle completed."); + setArmBotActive(robot.modelUuid, false) + setArmBotState(robot.modelUuid, "idle") + setCurrentPhase("rest"); + setPath([]) + removeCurrentAction(robot.modelUuid) + } + } + const logStatus = (id: string, status: string) => { + console.log(id +","+ status); } return ( <> - - + + ) diff --git a/app/src/modules/simulation/roboticArm/instances/ikInstance/ikInstance.tsx b/app/src/modules/simulation/roboticArm/instances/ikInstance/ikInstance.tsx index 52a8610..a8d8782 100644 --- a/app/src/modules/simulation/roboticArm/instances/ikInstance/ikInstance.tsx +++ b/app/src/modules/simulation/roboticArm/instances/ikInstance/ikInstance.tsx @@ -1,8 +1,87 @@ -import React from 'react' +import React, { useEffect, useMemo, useRef, useState } from 'react' +import * as THREE from "three"; +import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader"; +import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader"; +import { clone } from "three/examples/jsm/utils/SkeletonUtils"; +import { useFrame, useLoader, useThree } from "@react-three/fiber"; +import { CCDIKSolver, CCDIKHelper, } from "three/examples/jsm/animation/CCDIKSolver"; +type IKInstanceProps = { + modelUrl: string; + ikSolver: any; + setIkSolver: any + robot: any; + groupRef: React.RefObject; + processes: any; + setArmBotCurvePoints: any +}; +function IKInstance({ modelUrl, setIkSolver, ikSolver, robot, groupRef, processes, setArmBotCurvePoints }: IKInstanceProps) { + const { scene } = useThree(); + const gltf = useLoader(GLTFLoader, modelUrl, (loader) => { + const draco = new DRACOLoader(); + draco.setDecoderPath("https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/"); + loader.setDRACOLoader(draco); + }); + const cloned = useMemo(() => clone(gltf?.scene), [gltf]); + const targetBoneName = "Target"; + const skinnedMeshName = "link_0"; + useEffect(() => { + if (!gltf) return; + const OOI: any = {}; + cloned.traverse((n: any) => { + if (n.name === targetBoneName) OOI.Target_Bone = n; + if (n.name === skinnedMeshName) OOI.Skinned_Mesh = n; + }); + if (!OOI.Target_Bone || !OOI.Skinned_Mesh) return; + const iks = [ + { + target: 7, + effector: 6, + links: [ + { + index: 5, + enabled: true, + rotationMin: new THREE.Vector3(-Math.PI / 2, 0, 0), + rotationMax: new THREE.Vector3(Math.PI / 2, 0, 0), + }, + { + index: 4, + enabled: true, + rotationMin: new THREE.Vector3(-Math.PI / 2, 0, 0), + rotationMax: new THREE.Vector3(0, 0, 0), + }, + { + index: 3, + enabled: true, + rotationMin: new THREE.Vector3(0, 0, 0), + rotationMax: new THREE.Vector3(2, 0, 0), + }, + { index: 1, enabled: true, limitation: new THREE.Vector3(0, 1, 0) }, + { index: 0, enabled: false, limitation: new THREE.Vector3(0, 0, 0) }, + ], + }, + ]; + + const solver = new CCDIKSolver(OOI.Skinned_Mesh, iks); + setIkSolver(solver); + + const helper = new CCDIKHelper(OOI.Skinned_Mesh, iks, 0.05); + + // scene.add(groupRef.current) + + + }, [gltf]); -function IKInstance() { return ( - <> + <> + + + + ) } diff --git a/app/src/modules/simulation/roboticArm/instances/ikInstances.tsx b/app/src/modules/simulation/roboticArm/instances/ikInstances.tsx deleted file mode 100644 index d44ddd2..0000000 --- a/app/src/modules/simulation/roboticArm/instances/ikInstances.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import React from 'react' -import IKInstance from './ikInstance/ikInstance'; - -function IkInstances() { - return ( - <> - - - - - ) -} - -export default IkInstances; \ No newline at end of file diff --git a/app/src/modules/simulation/roboticArm/instances/roboticArmInstances.tsx b/app/src/modules/simulation/roboticArm/instances/roboticArmInstances.tsx index 1f963c8..1089fa5 100644 --- a/app/src/modules/simulation/roboticArm/instances/roboticArmInstances.tsx +++ b/app/src/modules/simulation/roboticArm/instances/roboticArmInstances.tsx @@ -5,17 +5,11 @@ import { useArmBotStore } from '../../../../store/simulation/useArmBotStore'; function RoboticArmInstances() { const { armBots } = useArmBotStore(); - return ( <> - { - armBots?.map((robot: any) => ( - - - ) - ) - - } + {armBots?.map((robot: ArmBotStatus) => ( + + ))} ) diff --git a/app/src/modules/simulation/roboticArm/roboticArm.tsx b/app/src/modules/simulation/roboticArm/roboticArm.tsx index 4295ac7..dcf01da 100644 --- a/app/src/modules/simulation/roboticArm/roboticArm.tsx +++ b/app/src/modules/simulation/roboticArm/roboticArm.tsx @@ -1,21 +1,86 @@ import { useEffect } from "react"; import RoboticArmInstances from "./instances/roboticArmInstances"; import { useArmBotStore } from "../../../store/simulation/useArmBotStore"; +import { useFloorItems } from "../../../store/store"; function RoboticArm() { - const { armBots, addArmBot, addCurrentAction } = useArmBotStore(); + const { armBots, addArmBot, removeArmBot } = useArmBotStore(); + const { floorItems } = useFloorItems(); const armBotStatusSample: RoboticArmEventSchema[] = [ { state: "idle", - // currentAction: { - // actionUuid: "action-001", - // actionName: "Pick Component", - // }, modelUuid: "armbot-xyz-001", modelName: "ArmBot-X200", - position: [0, 0, 0], - rotation: [91.94347308985614, 0, 6.742905194869091], + position: [91.94347308985614, 0, 6.742905194869091], + rotation: [0, 0, 0], + type: "roboticArm", + speed: 1.5, + point: { + uuid: "point-123", + position: [0, 1.5, 0], + rotation: [0, 0, 0], + actions: [ + { + actionUuid: "action-003", + actionName: "Pick Component", + actionType: "pickAndPlace", + process: { + startPoint: [5.52543010919071, 1, -8.433681161200905], + endPoint: [10.52543010919071, 1, -12.433681161200905], + }, + triggers: [ + { + triggerUuid: "trigger-001", + triggerName: "Start Trigger", + triggerType: "onStart", + delay: 0, + triggeredAsset: { + triggeredModel: { + modelName: "Conveyor A1", + modelUuid: "conveyor-01", + }, + triggeredPoint: { + pointName: "Start Point", + pointUuid: "conveyor-01-point-001", + }, + triggeredAction: { + actionName: "Move Forward", + actionUuid: "conveyor-action-01", + }, + }, + }, + { + triggerUuid: "trigger-002", + triggerName: "Complete Trigger", + triggerType: "onComplete", + delay: 0, + triggeredAsset: { + triggeredModel: { + modelName: "StaticMachine B2", + modelUuid: "machine-02", + }, + triggeredPoint: { + pointName: "Receive Point", + pointUuid: "machine-02-point-001", + }, + triggeredAction: { + actionName: "Process Part", + actionUuid: "machine-action-01", + }, + }, + }, + ], + }, + ], + }, + }, + { + state: "idle", + modelUuid: "armbot-xyz-002", + modelName: "ArmBot-X200", + position: [95.94347308985614, 0, 6.742905194869091], + rotation: [0, 0, 0], type: "roboticArm", speed: 1.5, point: { @@ -28,8 +93,8 @@ function RoboticArm() { actionName: "Pick Component", actionType: "pickAndPlace", process: { - startPoint: [1.2, 0.3, 0.5], - endPoint: [-0.8, 1.1, 0.7], + startPoint: [2.52543010919071, 0, 8.433681161200905], + endPoint: [95.3438373267953, 0, 9.0279187421610025], }, triggers: [ { @@ -80,20 +145,20 @@ function RoboticArm() { ]; useEffect(() => { + + removeArmBot(armBotStatusSample[0].modelUuid); addArmBot('123', armBotStatusSample[0]); + // addArmBot('123', armBotStatusSample[1]); // addCurrentAction('armbot-xyz-001', 'action-001'); }, []); - useEffect(() => { - console.log('armBots: ', armBots); + // }, [armBots]); return ( <> - - ); } diff --git a/app/src/store/simulation/useArmBotStore.ts b/app/src/store/simulation/useArmBotStore.ts index d907f21..642762f 100644 --- a/app/src/store/simulation/useArmBotStore.ts +++ b/app/src/store/simulation/useArmBotStore.ts @@ -21,7 +21,7 @@ interface ArmBotStore { updateEndPoint: (modelUuid: string, actionUuid: string, endPoint: [number, number, number] | null) => void; setArmBotActive: (modelUuid: string, isActive: boolean) => void; - + setArmBotState: (modelUuid: string, newState: ArmBotStatus['state']) => void; incrementActiveTime: (modelUuid: string, incrementBy: number) => void; incrementIdleTime: (modelUuid: string, incrementBy: number) => void; @@ -75,7 +75,6 @@ export const useArmBotStore = create()( actionUuid: action.actionUuid, actionName: action.actionName, }; - armBot.isActive = true; } } }); @@ -86,7 +85,6 @@ export const useArmBotStore = create()( const armBot = state.armBots.find(a => a.modelUuid === modelUuid); if (armBot) { armBot.currentAction = undefined; - armBot.isActive = false; } }); }, @@ -142,6 +140,15 @@ export const useArmBotStore = create()( }); }, + setArmBotState: (modelUuid, newState) => { + set((state) => { + const armBot = state.armBots.find(a => a.modelUuid === modelUuid); + if (armBot) { + armBot.state = newState; + } + }); + }, + incrementActiveTime: (modelUuid, incrementBy) => { set((state) => { const armBot = state.armBots.find(a => a.modelUuid === modelUuid); diff --git a/app/src/store/simulation/useVehicleStore.ts b/app/src/store/simulation/useVehicleStore.ts index ce28916..874a74c 100644 --- a/app/src/store/simulation/useVehicleStore.ts +++ b/app/src/store/simulation/useVehicleStore.ts @@ -1,3 +1,4 @@ + import { create } from 'zustand'; import { immer } from 'zustand/middleware/immer'; From 2424fa2e154f406f44dc70796b1092b664231764 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Fri, 25 Apr 2025 19:41:05 +0530 Subject: [PATCH 13/13] fix: Remove unused material property from vehicle action definition --- app/src/modules/simulation/vehicle/vehicles.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/modules/simulation/vehicle/vehicles.tsx b/app/src/modules/simulation/vehicle/vehicles.tsx index 3bb16d9..f0b4d17 100644 --- a/app/src/modules/simulation/vehicle/vehicles.tsx +++ b/app/src/modules/simulation/vehicle/vehicles.tsx @@ -69,7 +69,6 @@ function Vehicles() { actionUuid: "action-456", actionName: "Deliver to Zone A", actionType: "travel", - material: "crate", unLoadDuration: 10, loadCapacity: 2, pickUpPoint: { x: 90, y: 0, z: 28 },