diff --git a/app/src/components/layout/3D-cards/cards/StateWorking.tsx b/app/src/components/layout/3D-cards/cards/StateWorking.tsx index 287bc15..9adf77f 100644 --- a/app/src/components/layout/3D-cards/cards/StateWorking.tsx +++ b/app/src/components/layout/3D-cards/cards/StateWorking.tsx @@ -46,7 +46,7 @@ const StateWorking: React.FC = ({ id, type, position, rotatio socket.on("connect", startStream); socket.on("lastOutput", (response) => { const responseData = response; - console.log("responceeeeeeeeeee", response); + setDatas(responseData); }); @@ -76,7 +76,7 @@ const StateWorking: React.FC = ({ id, type, position, rotatio } } - console.log("dataaaaa", datas); + useEffect(() => { diff --git a/app/src/components/layout/sidebarRight/mechanics/ConveyorMechanics.tsx b/app/src/components/layout/sidebarRight/mechanics/ConveyorMechanics.tsx index 8ad0886..fd64db9 100644 --- a/app/src/components/layout/sidebarRight/mechanics/ConveyorMechanics.tsx +++ b/app/src/components/layout/sidebarRight/mechanics/ConveyorMechanics.tsx @@ -13,7 +13,7 @@ import { useFloorItems, useSelectedActionSphere, useSelectedPath, - useSimulationPaths, + useSimulationStates, useSocketStore, } from "../../../../store/store"; import * as THREE from "three"; @@ -25,7 +25,7 @@ import { setEventApi } from "../../../../services/factoryBuilder/assest/floorAss const ConveyorMechanics: React.FC = () => { const { selectedActionSphere } = useSelectedActionSphere(); const { selectedPath, setSelectedPath } = useSelectedPath(); - const { simulationPaths, setSimulationPaths } = useSimulationPaths(); + const { simulationStates, setSimulationStates } = useSimulationStates(); const { floorItems, setFloorItems } = useFloorItems(); const { socket } = useSocketStore(); @@ -34,13 +34,13 @@ const ConveyorMechanics: React.FC = () => { const selectedPoint = useMemo(() => { if (!selectedActionSphere) return null; - return simulationPaths + return simulationStates .filter( (path): path is Types.ConveyorEventsSchema => path.type === "Conveyor" ) .flatMap((path) => path.points) .find((point) => point.uuid === selectedActionSphere.points.uuid); - }, [selectedActionSphere, simulationPaths]); + }, [selectedActionSphere, simulationStates]); const updateBackend = async (updatedPath: Types.ConveyorEventsSchema | undefined) => { if (!updatedPath) return; @@ -66,7 +66,7 @@ const ConveyorMechanics: React.FC = () => { const handleAddAction = () => { if (!selectedActionSphere) return; - const updatedPaths = simulationPaths.map((path) => { + const updatedPaths = simulationStates.map((path) => { if (path.type === "Conveyor") { return { ...path, @@ -101,13 +101,13 @@ const ConveyorMechanics: React.FC = () => { ); updateBackend(updatedPath); - setSimulationPaths(updatedPaths); + setSimulationStates(updatedPaths); }; const handleDeleteAction = (uuid: string) => { if (!selectedActionSphere) return; - const updatedPaths = simulationPaths.map((path) => + const updatedPaths = simulationStates.map((path) => path.type === "Conveyor" ? { ...path, @@ -134,13 +134,13 @@ const ConveyorMechanics: React.FC = () => { ); updateBackend(updatedPath); - setSimulationPaths(updatedPaths); + setSimulationStates(updatedPaths); }; const handleActionSelect = (uuid: string, actionType: string) => { if (!selectedActionSphere) return; - const updatedPaths = simulationPaths.map((path) => + const updatedPaths = simulationStates.map((path) => path.type === "Conveyor" ? { ...path, @@ -182,7 +182,7 @@ const ConveyorMechanics: React.FC = () => { ); updateBackend(updatedPath); - setSimulationPaths(updatedPaths); + setSimulationStates(updatedPaths); // Update the selected item to reflect changes if (selectedItem?.type === "action" && selectedItem.item.uuid === uuid) { @@ -207,7 +207,7 @@ const ConveyorMechanics: React.FC = () => { const handleMaterialSelect = (uuid: string, material: string) => { if (!selectedActionSphere) return; - const updatedPaths = simulationPaths.map((path) => + const updatedPaths = simulationStates.map((path) => path.type === "Conveyor" ? { ...path, @@ -237,7 +237,7 @@ const ConveyorMechanics: React.FC = () => { ); updateBackend(updatedPath); - setSimulationPaths(updatedPaths); + setSimulationStates(updatedPaths); // Update selected item if it's the current action if (selectedItem?.type === "action" && selectedItem.item.uuid === uuid) { @@ -254,7 +254,7 @@ const ConveyorMechanics: React.FC = () => { const handleDelayChange = (uuid: string, delay: number | string) => { if (!selectedActionSphere) return; - const updatedPaths = simulationPaths.map((path) => + const updatedPaths = simulationStates.map((path) => path.type === "Conveyor" ? { ...path, @@ -281,7 +281,7 @@ const ConveyorMechanics: React.FC = () => { ); updateBackend(updatedPath); - setSimulationPaths(updatedPaths); + setSimulationStates(updatedPaths); }; const handleSpawnIntervalChange = ( @@ -290,7 +290,7 @@ const ConveyorMechanics: React.FC = () => { ) => { if (!selectedActionSphere) return; - const updatedPaths = simulationPaths.map((path) => + const updatedPaths = simulationStates.map((path) => path.type === "Conveyor" ? { ...path, @@ -319,13 +319,13 @@ const ConveyorMechanics: React.FC = () => { ); updateBackend(updatedPath); - setSimulationPaths(updatedPaths); + setSimulationStates(updatedPaths); }; const handleSpeedChange = (speed: number | string) => { if (!selectedPath) return; - const updatedPaths = simulationPaths.map((path) => + const updatedPaths = simulationStates.map((path) => path.modeluuid === selectedPath.path.modeluuid ? { ...path, speed } : path ); @@ -338,14 +338,14 @@ const ConveyorMechanics: React.FC = () => { ); updateBackend(updatedPath); - setSimulationPaths(updatedPaths); + setSimulationStates(updatedPaths); setSelectedPath({ ...selectedPath, path: { ...selectedPath.path, speed } }); }; const handleAddTrigger = () => { if (!selectedActionSphere) return; - const updatedPaths = simulationPaths.map((path) => + const updatedPaths = simulationStates.map((path) => path.type === "Conveyor" ? { ...path, @@ -377,13 +377,13 @@ const ConveyorMechanics: React.FC = () => { ); updateBackend(updatedPath); - setSimulationPaths(updatedPaths); + setSimulationStates(updatedPaths); }; const handleDeleteTrigger = (uuid: string) => { if (!selectedActionSphere) return; - const updatedPaths = simulationPaths.map((path) => + const updatedPaths = simulationStates.map((path) => path.type === "Conveyor" ? { ...path, @@ -410,13 +410,13 @@ const ConveyorMechanics: React.FC = () => { ); updateBackend(updatedPath); - setSimulationPaths(updatedPaths); + setSimulationStates(updatedPaths); }; const handleTriggerSelect = (uuid: string, triggerType: string) => { if (!selectedActionSphere) return; - const updatedPaths = simulationPaths.map((path) => + const updatedPaths = simulationStates.map((path) => path.type === "Conveyor" ? { ...path, @@ -445,7 +445,7 @@ const ConveyorMechanics: React.FC = () => { ); updateBackend(updatedPath); - setSimulationPaths(updatedPaths); + setSimulationStates(updatedPaths); // Ensure the selectedItem is updated immediately const updatedTrigger = updatedPaths @@ -461,7 +461,7 @@ const ConveyorMechanics: React.FC = () => { // Update the toggle handlers to immediately update the selected item const handleActionToggle = (uuid: string) => { if (!selectedActionSphere) return; - const updatedPaths = simulationPaths.map((path) => + const updatedPaths = simulationStates.map((path) => path.type === "Conveyor" ? { ...path, @@ -489,7 +489,7 @@ const ConveyorMechanics: React.FC = () => { ); updateBackend(updatedPath); - setSimulationPaths(updatedPaths); + setSimulationStates(updatedPaths); // Immediately update the selected item if it's the one being toggled if (selectedItem?.type === "action" && selectedItem.item.uuid === uuid) { @@ -507,7 +507,7 @@ const ConveyorMechanics: React.FC = () => { const handleTriggerToggle = (uuid: string) => { if (!selectedActionSphere) return; - const updatedPaths = simulationPaths.map((path) => + const updatedPaths = simulationStates.map((path) => path.type === "Conveyor" ? { ...path, @@ -535,7 +535,7 @@ const ConveyorMechanics: React.FC = () => { ); updateBackend(updatedPath); - setSimulationPaths(updatedPaths); + setSimulationStates(updatedPaths); // Immediately update the selected item if it's the one being toggled if (selectedItem?.type === "trigger" && selectedItem.item.uuid === uuid) { @@ -552,7 +552,7 @@ const ConveyorMechanics: React.FC = () => { const handleTriggerBufferTimeChange = (uuid: string, bufferTime: number) => { if (!selectedActionSphere) return; - const updatedPaths = simulationPaths.map((path) => + const updatedPaths = simulationStates.map((path) => path.type === "Conveyor" ? { ...path, @@ -581,7 +581,7 @@ const ConveyorMechanics: React.FC = () => { ); updateBackend(updatedPath); - setSimulationPaths(updatedPaths); + setSimulationStates(updatedPaths); // Immediately update selectedItem if it's the currently selected trigger if (selectedItem?.type === "trigger" && selectedItem.item.uuid === uuid) { diff --git a/app/src/components/layout/sidebarRight/mechanics/VehicleMechanics.tsx b/app/src/components/layout/sidebarRight/mechanics/VehicleMechanics.tsx index e9bd6a2..4db77fe 100644 --- a/app/src/components/layout/sidebarRight/mechanics/VehicleMechanics.tsx +++ b/app/src/components/layout/sidebarRight/mechanics/VehicleMechanics.tsx @@ -1,14 +1,14 @@ import React, { useRef, useMemo } from "react"; import { InfoIcon } from "../../../icons/ExportCommonIcons"; import InputWithDropDown from "../../../ui/inputs/InputWithDropDown"; -import { useEditingPoint, useEyeDropMode, usePreviewPosition, useSelectedActionSphere, useSimulationPaths, useSocketStore } from "../../../../store/store"; +import { useEditingPoint, useEyeDropMode, usePreviewPosition, useSelectedActionSphere, useSimulationStates, useSocketStore } from "../../../../store/store"; import * as Types from '../../../../types/world/worldTypes'; import PositionInput from "../customInput/PositionInputs"; import { setEventApi } from "../../../../services/factoryBuilder/assest/floorAsset/setEventsApt"; const VehicleMechanics: React.FC = () => { const { selectedActionSphere } = useSelectedActionSphere(); - const { simulationPaths, setSimulationPaths } = useSimulationPaths(); + const { simulationStates, setSimulationStates } = useSimulationStates(); const { eyeDropMode, setEyeDropMode } = useEyeDropMode(); const { editingPoint, setEditingPoint } = useEditingPoint(); const { previewPosition, setPreviewPosition } = usePreviewPosition(); @@ -19,7 +19,7 @@ const VehicleMechanics: React.FC = () => { const { selectedPoint, connectedPointUuids } = useMemo(() => { if (!selectedActionSphere?.points?.uuid) return { selectedPoint: null, connectedPointUuids: [] }; - const vehiclePaths = simulationPaths.filter( + const vehiclePaths = simulationStates.filter( (path): path is Types.VehicleEventsSchema => path.type === "Vehicle" ); @@ -40,7 +40,7 @@ const VehicleMechanics: React.FC = () => { selectedPoint: points, connectedPointUuids: connectedUuids }; - }, [selectedActionSphere, simulationPaths]); + }, [selectedActionSphere, simulationStates]); const updateBackend = async (updatedPath: Types.VehicleEventsSchema | undefined) => { if (!updatedPath) return; @@ -66,7 +66,7 @@ const VehicleMechanics: React.FC = () => { const handleActionUpdate = React.useCallback((updatedAction: Partial) => { if (!selectedActionSphere?.points?.uuid) return; - const updatedPaths = simulationPaths.map((path) => { + const updatedPaths = simulationStates.map((path) => { if (path.type === "Vehicle" && path.points.uuid === selectedActionSphere.points.uuid) { return { ...path, @@ -89,8 +89,8 @@ const VehicleMechanics: React.FC = () => { ); updateBackend(updatedPath); - setSimulationPaths(updatedPaths); - }, [selectedActionSphere?.points?.uuid, simulationPaths, setSimulationPaths]); + setSimulationStates(updatedPaths); + }, [selectedActionSphere?.points?.uuid, simulationStates, setSimulationStates]); const handleHitCountChange = React.useCallback((hitCount: number) => { handleActionUpdate({ hitCount }); @@ -103,7 +103,7 @@ const VehicleMechanics: React.FC = () => { const handleSpeedChange = React.useCallback((speed: number) => { if (!selectedActionSphere?.points?.uuid) return; - const updatedPaths = simulationPaths.map((path) => { + const updatedPaths = simulationStates.map((path) => { if (path.type === "Vehicle" && path.points.uuid === selectedActionSphere.points.uuid) { return { ...path, @@ -123,8 +123,8 @@ const VehicleMechanics: React.FC = () => { ); updateBackend(updatedPath); - setSimulationPaths(updatedPaths); - }, [selectedActionSphere?.points?.uuid, simulationPaths, setSimulationPaths]); + setSimulationStates(updatedPaths); + }, [selectedActionSphere?.points?.uuid, simulationStates, setSimulationStates]); const handleStartEyeDropClick = () => { setEditingPoint('start'); diff --git a/app/src/components/ui/componets/Dropped3dWidget.tsx b/app/src/components/ui/componets/Dropped3dWidget.tsx index 567aa7a..d870195 100644 --- a/app/src/components/ui/componets/Dropped3dWidget.tsx +++ b/app/src/components/ui/componets/Dropped3dWidget.tsx @@ -50,6 +50,7 @@ export default function Dropped3dWidgets() { const rotationStartRef = useRef<[number, number, number]>([0, 0, 0]); const mouseStartRef = useRef<{ x: number; y: number }>({ x: 0, y: 0 }); + useEffect(() => { if (activeModule !== "visualization") return; if (!selectedZone.zoneId) return; @@ -139,8 +140,6 @@ export default function Dropped3dWidgets() { if (rightSelect === "Duplicate") { async function duplicateWidget() { - - const widgetToDuplicate = activeZoneWidgets.find((w: WidgetData) => w.id === rightClickSelected); if (!widgetToDuplicate) return; const newWidget: WidgetData = { @@ -154,12 +153,15 @@ export default function Dropped3dWidgets() { rotation: widgetToDuplicate.rotation || [0, 0, 0], }; const adding3dWidget = { - organization, + organization: organization, widget: newWidget, zoneId: selectedZone.zoneId }; - let response = await adding3dWidgets(selectedZone.zoneId, organization, newWidget) - console.log('response: ', response); + if (visualizationSocket) { + visualizationSocket.emit("v2:viz-3D-widget:add", adding3dWidget); + } + // let response = await adding3dWidgets(selectedZone.zoneId, organization, newWidget) + // console.log('response: ', response); addWidget(selectedZone.zoneId, newWidget); setRightSelect(null); @@ -173,23 +175,20 @@ export default function Dropped3dWidgets() { try { const deleteWidget = { organization, - widgetId: rightClickSelected, + id: rightClickSelected, zoneId: selectedZone.zoneId, }; + console.log('deleteWidget: ', deleteWidget); + if (visualizationSocket) { + visualizationSocket.emit("v2:viz-3D-widget:delete", deleteWidget); + } // Call the API to delete the widget - const response = await delete3dWidgetApi(selectedZone.zoneId, organization, rightClickSelected); - - - // if (response?.success) { - // Remove from state only if API call succeeds + // const response = await delete3dWidgetApi(selectedZone.zoneId, organization, rightClickSelected); setZoneWidgetData( selectedZone.zoneId, activeZoneWidgets.filter((w: WidgetData) => w.id !== rightClickSelected) ); - // } else { - // console.error("Failed to delete widget:", response?.message); - // } } catch (error) { console.error("Error deleting widget:", error); } finally { @@ -298,44 +297,60 @@ export default function Dropped3dWidgets() { const handleMouseUp = () => { if (!rightClickSelected || !rightSelect) return; - const selectedZone = Object.keys(zoneWidgetData).find(zoneId => zoneWidgetData[zoneId].some(widget => widget.id === rightClickSelected) ); - if (!selectedZone) return; const selectedWidget = zoneWidgetData[selectedZone].find(widget => widget.id === rightClickSelected); if (!selectedWidget) return; + + // Format values to 2 decimal places const formatValues = (vals: number[]) => vals.map(val => parseFloat(val.toFixed(2))); if (rightSelect === "Horizontal Move" || rightSelect === "Vertical Move") { console.log(`${rightSelect} Completed - Full Position:`, formatValues(selectedWidget.position)); let lastPosition = formatValues(selectedWidget.position) as [number, number, number]; + // (async () => { + // let response = await update3dWidget(selectedZone, organization, rightClickSelected, lastPosition); + // console.log('response: ', response); + // if (response) { + // console.log("Widget position updated in API:", response); + // } + // })(); + let updatingPosition = { + organization: organization, + zoneId: selectedZone, + id: rightClickSelected, + position: lastPosition, + } + if (visualizationSocket) { + visualizationSocket.emit("v2:viz-3D-widget:modifyPositionRotation", updatingPosition); + } - (async () => { - let response = await update3dWidget(selectedZone, organization, rightClickSelected, lastPosition); - console.log('response: ', response); - if (response) { - console.log("Widget position updated in API:", response); - } - })(); } else if (rightSelect.includes("Rotate")) { const rotation = selectedWidget.rotation || [0, 0, 0]; console.log(`${rightSelect} Completed - Full Rotation:`, formatValues(rotation)); - let lastPosition = formatValues(rotation) as [number, number, number]; - console.log('lastPosition: ', lastPosition); - - (async () => { - let response = await update3dWidgetRotation(selectedZone, organization, rightClickSelected, lastPosition); - console.log('response: ', response); - if (response) { - console.log("Widget position updated in API:", response); - } - })(); + let lastRotation = formatValues(rotation) as [number, number, number]; + // (async () => { + // let response = await update3dWidgetRotation(selectedZone, organization, rightClickSelected, lastRotation); + // console.log('response: ', response); + // if (response) { + // console.log("Widget position updated in API:", response); + // } + // })(); + let updatingRotation = { + organization: organization, + zoneId: selectedZone, + id: rightClickSelected, + rotation: lastRotation, + } + if (visualizationSocket) { + visualizationSocket.emit("v2:viz-3D-widget:modifyPositionRotation", updatingRotation); + } } // Reset selection diff --git a/app/src/components/ui/list/List.tsx b/app/src/components/ui/list/List.tsx index 7629730..000bc20 100644 --- a/app/src/components/ui/list/List.tsx +++ b/app/src/components/ui/list/List.tsx @@ -31,7 +31,6 @@ interface ListProps { } const List: React.FC = ({ items = [], remove }) => { - console.log("items: ", items); const { activeModule, setActiveModule } = useModuleStore(); const { selectedZone, setSelectedZone } = useSelectedZoneStore(); const { setSubModule } = useSubModuleStore(); diff --git a/app/src/modules/builder/agv/agv.tsx b/app/src/modules/builder/agv/agv.tsx index 24003ea..48f4306 100644 --- a/app/src/modules/builder/agv/agv.tsx +++ b/app/src/modules/builder/agv/agv.tsx @@ -1,163 +1,68 @@ -import PolygonGenerator from "./polygonGenerator"; -import { useThree } from "@react-three/fiber"; -import { useEffect, useMemo, useRef, useState } from "react"; -import * as THREE from "three"; -import * as Types from "../../../types/world/worldTypes"; +import { useEffect, useState } from "react"; +import { Line } from "@react-three/drei"; +import { useNavMesh, useSimulationStates } from "../../../store/store"; import PathNavigator from "./pathNavigator"; -import NavMeshDetails from "./navMeshDetails"; -import { - useSelectedActionSphere, - useSimulationPaths, -} from "../../../store/store"; -import * as CONSTANTS from "../../../types/world/worldConstants"; +import { usePlayButtonStore } from "../../../store/usePlayButtonStore"; -const Agv = ({ - lines, -}: { - lines: Types.RefLines; -}) => { - const [pathPoints, setPathPoints] = useState< - { - modelUuid: string; - modelSpeed: number; - bufferTime: number; - points: { x: number; y: number; z: number }[]; - hitCount: number; - }[] - >([]); - const { simulationPaths } = useSimulationPaths(); - const { selectedActionSphere } = useSelectedActionSphere(); - useEffect(() => { - if (!Array.isArray(simulationPaths)) { - } else { - let agvModels = simulationPaths.filter( - (val: any) => val.modelName === "agv" - ); +type PathPoints = { + modelUuid: string; + modelSpeed: number; + bufferTime: number; + points: { x: number; y: number; z: number }[]; + hitCount: number; +}; - - let findMesh = agvModels.filter( - (val: any) => - val.modeluuid === selectedActionSphere?.path?.modeluuid && - val.type === "Vehicle" - ); +const Agv = () => { + const [pathPoints, setPathPoints] = useState([]); + const { simulationStates } = useSimulationStates(); + const { navMesh } = useNavMesh(); + const { isPlaying } = usePlayButtonStore(); - const result = - findMesh.length > 0 && - findMesh[0].type === "Vehicle" && - typeof findMesh[0].points?.actions.start === "object" && - typeof findMesh[0].points?.actions.end === "object" && - "x" in findMesh[0].points.actions.start && - "y" in findMesh[0].points.actions.start && - "x" in findMesh[0].points.actions.end && - "y" in findMesh[0].points.actions.end - ? [ - { - modelUuid: findMesh[0].modeluuid, // Ensure it's a number - modelSpeed: findMesh[0].points.speed, - bufferTime: findMesh[0].points.actions.buffer, - hitCount: findMesh[0].points.actions.hitCount, - points: [ - { - x: findMesh[0].position[0], - y: findMesh[0].position[1], - z: findMesh[0].position[2], - }, - { - x: findMesh[0].points.actions.start.x, - y: 0, - z: findMesh[0].points.actions.start.y, - }, - { - x: findMesh[0].points.actions.end.x, - y: 0, - z: findMesh[0].points.actions.end.y, - }, - ], - }, - ] - : []; - if (result.length > 0) { - // setPathPoints((prev) => [...prev, ...result]); - setPathPoints((prev) => { - const existingIndex = prev.findIndex( - (item) => item.modelUuid === result[0].modelUuid - ); + useEffect(() => { + if (simulationStates.length > 0) { - if (existingIndex !== -1) { - const updatedPathPoints = [...prev]; - updatedPathPoints[existingIndex] = result[0]; - return updatedPathPoints; - } else { - return [...prev, ...result]; - } - }); - } - } - // setPathPoints((prev) => { - // const existingUUIDs = new Set(prev.map((item) => item.uuid)); - // const newItems = result.filter( - // (item) => !existingUUIDs.has(item.uuid) - // ); - // return [...prev, ...newItems]; - // }); - }, [simulationPaths, selectedActionSphere]); + const agvModels = simulationStates.filter((val) => val.modelName === "agv" && val.type === "Vehicle"); - let groupRef = useRef() as Types.RefGroup; - const [navMesh, setNavMesh] = useState(); + const newPathPoints = agvModels.filter((model: any) => model.points && model.points.actions && typeof model.points.actions.start === "object" && typeof model.points.actions.end === "object" && "x" in model.points.actions.start && "y" in model.points.actions.start && "x" in model.points.actions.end && "y" in model.points.actions.end) + .map((model: any) => ({ + modelUuid: model.modeluuid, + modelSpeed: model.points.speed, + bufferTime: model.points.actions.buffer, + hitCount: model.points.actions.hitCount, + points: [ + { x: model.position[0], y: model.position[1], z: model.position[2] }, + { x: model.points.actions.start.x, y: 0, z: model.points.actions.start.y }, + { x: model.points.actions.end.x, y: 0, z: model.points.actions.end.y }, + ], + })); - return ( - <> - - - {pathPoints.map((pair, i) => ( - <> - - {/* {pair.points.length > 2 && ( - <> - - - - - - - - - - )} */} - - ))} - - - - - - - - ); + setPathPoints(newPathPoints); + } + }, [simulationStates]); + + return ( + <> + {pathPoints.map((pair, i) => ( + + + + {pair.points.slice(1).map((point, idx) => ( + + + + + ))} + + ))} + + ); }; export default Agv; diff --git a/app/src/modules/builder/agv/navMeshCreator.tsx b/app/src/modules/builder/agv/navMeshCreator.tsx new file mode 100644 index 0000000..cdbca45 --- /dev/null +++ b/app/src/modules/builder/agv/navMeshCreator.tsx @@ -0,0 +1,31 @@ +import { useRef } from "react"; +import { useNavMesh } from "../../../store/store"; +import PolygonGenerator from "./polygonGenerator"; +import NavMeshDetails from "./navMeshDetails"; +import * as CONSTANTS from "../../../types/world/worldConstants"; +import * as Types from "../../../types/world/worldTypes"; + +type NavMeshCreatorProps = { + lines: Types.RefLines +}; + +function NavMeshCreator({ lines }: NavMeshCreatorProps) { + let groupRef = useRef() as Types.RefGroup; + const { setNavMesh } = useNavMesh(); + + return ( + <> + + + + + + + + + + + ) +} + +export default NavMeshCreator \ No newline at end of file diff --git a/app/src/modules/builder/agv/pathNavigator.tsx b/app/src/modules/builder/agv/pathNavigator.tsx index 65a299b..7d7984c 100644 --- a/app/src/modules/builder/agv/pathNavigator.tsx +++ b/app/src/modules/builder/agv/pathNavigator.tsx @@ -3,179 +3,207 @@ import * as THREE from "three"; import { useFrame, useThree } from "@react-three/fiber"; import { NavMeshQuery } from "@recast-navigation/core"; import { Line } from "@react-three/drei"; -import { useActiveTool } from "../../../store/store"; import { usePlayButtonStore } from "../../../store/usePlayButtonStore"; interface PathNavigatorProps { - navMesh: any; - selectedPoints: any; - id: string; - speed: number; - bufferTime: number; - hitCount: number; + navMesh: any; + pathPoints: any; + id: string; + speed: number; + bufferTime: number; + hitCount: number; } export default function PathNavigator({ - navMesh, - selectedPoints, - id, - speed, - bufferTime, - hitCount, + navMesh, + pathPoints, + id, + speed, + bufferTime, + hitCount }: PathNavigatorProps) { - const [path, setPath] = useState<[number, number, number][]>([]); - const progressRef = useRef(0); - const distancesRef = useRef([]); - const totalDistanceRef = useRef(0); - const currentSegmentIndex = useRef(0); - const [stop, setStop] = useState(true); - const { scene } = useThree(); - const { isPlaying, setIsPlaying } = usePlayButtonStore(); - const [startPoint, setStartPoint] = useState(new THREE.Vector3()); - const isWaiting = useRef(false); // Flag to track waiting state - const delayTime = bufferTime; + const [path, setPath] = useState<[number, number, number][]>([]); + const [currentPhase, setCurrentPhase] = useState<'initial' | 'loop'>('initial'); + const [toPickupPath, setToPickupPath] = useState<[number, number, number][]>([]); + const [pickupDropPath, setPickupDropPath] = useState<[number, number, number][]>([]); + const [dropPickupPath, setDropPickupPath] = useState<[number, number, number][]>([]); + const [initialPosition, setInitialPosition] = useState(null); + const [initialRotation, setInitialRotation] = useState(null); - const movingForward = useRef(true); // Tracks whether the object is moving forward - // Compute distances and total distance when the path changes - useEffect(() => { - if (!scene || !id || path.length < 2) return; + const distancesRef = useRef([]); + const totalDistanceRef = useRef(0); + const progressRef = useRef(0); + const isWaiting = useRef(false); + const timeoutRef = useRef(null); - let totalDistance = 0; - const distances: number[] = []; - for (let i = 0; i < path.length - 1; i++) { - const start = new THREE.Vector3(...path[i]); - const end = new THREE.Vector3(...path[i + 1]); - const segmentDistance = start.distanceTo(end); - distances.push(segmentDistance); - totalDistance += segmentDistance; - } - distancesRef.current = distances; - totalDistanceRef.current = totalDistance; - progressRef.current = 0; - }, [path]); + const { scene } = useThree(); + const { isPlaying } = usePlayButtonStore(); - // Compute the path using NavMeshQuery - useEffect(() => { - if (!navMesh || selectedPoints.length === 0) return; + useEffect(() => { + const object = scene.getObjectByProperty("uuid", id); + if (object) { + setInitialPosition(object.position.clone()); + setInitialRotation(object.rotation.clone()); + } + }, [scene, id]); - const allPoints = selectedPoints.flat(); - const computedPath: [number, number, number][] = []; + const computePath = (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 []; + } + }; - for (let i = 0; i < allPoints.length - 1; i++) { - const start = allPoints[i]; - setStartPoint( - new THREE.Vector3(allPoints[0].x, allPoints[0].y, allPoints[0].z) - ); + const resetState = () => { + if (timeoutRef.current) { + clearTimeout(timeoutRef.current); + timeoutRef.current = null; + } - const end = allPoints[i + 1]; + setPath([]); + setCurrentPhase('initial'); + setPickupDropPath([]); + setDropPickupPath([]); + distancesRef.current = []; + totalDistanceRef.current = 0; + progressRef.current = 0; + isWaiting.current = false; - try { - const navMeshQuery = new NavMeshQuery(navMesh); - const { path: segmentPath } = navMeshQuery.computePath(start, end); + if (initialPosition && initialRotation) { + const object = scene.getObjectByProperty("uuid", id); + if (object) { + object.position.copy(initialPosition); + object.rotation.copy(initialRotation); + } + } + }; - if (!segmentPath || segmentPath.length === 0) { - continue; - } + useEffect(() => { + if (!isPlaying) { + resetState(); + } - computedPath.push( - ...segmentPath.map(({ x, y, z }): [number, number, number] => [ - x, - y + 0.1, - z, - ]) - ); - } catch (error) {} - } + if (!navMesh || pathPoints.length < 2) return; - if (computedPath.length > 0) { - setPath(computedPath); - currentSegmentIndex.current = 0; - } - }, [selectedPoints, navMesh]); - useFrame((_, delta) => { - if (!scene || !id || path.length < 2) return; + const [pickup, drop] = pathPoints.slice(-2); + const object = scene.getObjectByProperty("uuid", id); + if (!object) return; - // Find the object in the scene by its UUID - const findObject = scene.getObjectByProperty("uuid", id); - if (!findObject) return; + const currentPosition = { x: object.position.x, y: object.position.y, z: object.position.z }; - if (isPlaying) { - const fast = speed; - progressRef.current += delta * fast; + const toPickupPath = computePath(currentPosition, pickup); + const pickupToDropPath = computePath(pickup, drop); + const dropToPickupPath = computePath(drop, pickup); - let coveredDistance = progressRef.current; - let accumulatedDistance = 0; - let index = 0; + if (toPickupPath.length && pickupToDropPath.length && dropToPickupPath.length) { + setPickupDropPath(pickupToDropPath); + setDropPickupPath(dropToPickupPath); + setToPickupPath(toPickupPath); + setPath(toPickupPath); + setCurrentPhase('initial'); + } + }, [navMesh, pathPoints, hitCount, isPlaying]); - // Determine the current segment of the path - while ( - index < distancesRef.current.length && - coveredDistance > accumulatedDistance + distancesRef.current[index] - ) { - accumulatedDistance += distancesRef.current[index]; - index++; - } + useEffect(() => { + if (path.length < 2) return; - if (index >= distancesRef.current.length) { - progressRef.current = totalDistanceRef.current; + let total = 0; + const segmentDistances = path.slice(0, -1).map((point, i) => { + const dist = new THREE.Vector3(...point).distanceTo(new THREE.Vector3(...path[i + 1])); + total += dist; + return dist; + }); - if (!isWaiting.current) { - isWaiting.current = true; // Set waiting flag + distancesRef.current = segmentDistances; + totalDistanceRef.current = total; + progressRef.current = 0; + isWaiting.current = false; + }, [path]); - if (movingForward.current) { - // Moving forward: reached the end, wait for `delay` - // console.log( - // "Reached end position. Waiting for delay:", - // delayTime, - // "seconds" - // ); - setTimeout(() => { - // After delay, reverse direction - movingForward.current = false; - progressRef.current = 0; // Reset progress - path.reverse(); // Reverse the path - distancesRef.current.reverse(); - isWaiting.current = false; // Reset waiting flag - }, delayTime * 1000); // Wait for `delay` seconds - } - } - return; - } + useFrame((_, delta) => { + if (!isPlaying || path.length < 2 || !scene || !id) return; - // Interpolate position within the current segment - const start = new THREE.Vector3(...path[index]); - const end = new THREE.Vector3(...path[index + 1]); - const segmentDistance = distancesRef.current[index]; + const object = scene.getObjectByProperty("uuid", id); + if (!object) return; - const t = Math.min( - (coveredDistance - accumulatedDistance) / segmentDistance, - 1 - ); // Clamp t to avoid overshooting - const position = start.clone().lerp(end, t); - findObject.position.copy(position); + const speedFactor = speed; + progressRef.current += delta * speedFactor; - // Rotate the object to face the direction of movement - const direction = new THREE.Vector3().subVectors(end, start).normalize(); - const targetYRotation = Math.atan2(direction.x, direction.z); - findObject.rotation.y += (targetYRotation - findObject.rotation.y) * 0.1; - } else { - findObject.position.copy(startPoint); - } - }); + let covered = progressRef.current; + let accumulated = 0; + let index = 0; - return ( - <> - {path.length > 0 && ( - <> - - {selectedPoints.map((val: any, i: any) => ( - - - - - ))} - - )} - - ); -} + while ( + index < distancesRef.current.length && + covered > accumulated + distancesRef.current[index] + ) { + accumulated += distancesRef.current[index]; + index++; + } + + if (index >= distancesRef.current.length) { + progressRef.current = totalDistanceRef.current; + + if (!isWaiting.current) { + isWaiting.current = true; + + timeoutRef.current = setTimeout(() => { + if (currentPhase === 'initial') { + setPath(pickupDropPath); + setCurrentPhase('loop'); + } else { + setPath(prevPath => + prevPath === pickupDropPath ? dropPickupPath : pickupDropPath + ); + } + + progressRef.current = 0; + isWaiting.current = false; + }, bufferTime * 1000); + } + return; + } + + const start = new THREE.Vector3(...path[index]); + const end = new THREE.Vector3(...path[index + 1]); + const dist = distancesRef.current[index]; + const t = THREE.MathUtils.clamp((covered - accumulated) / dist, 0, 1); + const position = start.clone().lerp(end, t); + + object.position.copy(position); + + const direction = new THREE.Vector3().subVectors(end, start).normalize(); + const targetRotationY = Math.atan2(direction.x, direction.z); + + let angleDifference = targetRotationY - object.rotation.y; + angleDifference = ((angleDifference + Math.PI) % (Math.PI * 2)) - Math.PI; + object.rotation.y += angleDifference * 0.1; + }); + + useEffect(() => { + return () => { + if (timeoutRef.current) { + clearTimeout(timeoutRef.current); + } + }; + }, []); + + return ( + + {toPickupPath.length > 0 && ( + + )} + + {pickupDropPath.length > 0 && ( + + )} + + {dropPickupPath.length > 0 && ( + + )} + + ); +} \ No newline at end of file diff --git a/app/src/modules/builder/geomentries/assets/addAssetModel.ts b/app/src/modules/builder/geomentries/assets/addAssetModel.ts index 91c1f12..9fc6199 100644 --- a/app/src/modules/builder/geomentries/assets/addAssetModel.ts +++ b/app/src/modules/builder/geomentries/assets/addAssetModel.ts @@ -24,7 +24,7 @@ async function addAssetModel( socket: Socket, selectedItem: any, setSelectedItem: any, - setSimulationPaths: any, + setSimulationStates: any, plane: Types.RefMesh, ): Promise { @@ -65,7 +65,7 @@ async function addAssetModel( const cachedModel = THREE.Cache.get(selectedItem.id); if (cachedModel) { // console.log(`[Cache] Fetching ${selectedItem.name}`); - handleModelLoad(cachedModel, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, setSimulationPaths, socket); + handleModelLoad(cachedModel, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, setSimulationStates, socket); return; } else { const cachedModelBlob = await retrieveGLTF(selectedItem.id); @@ -78,7 +78,7 @@ async function addAssetModel( URL.revokeObjectURL(blobUrl); THREE.Cache.remove(blobUrl); THREE.Cache.add(selectedItem.id, gltf); - handleModelLoad(gltf, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, setSimulationPaths, socket); + handleModelLoad(gltf, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, setSimulationStates, socket); }, () => { TempLoader(intersectPoint!, isTempLoader, tempLoader, itemsGroup); @@ -90,7 +90,7 @@ async function addAssetModel( const modelBlob = await fetch(`${url_Backend_dwinzo}/api/v1/AssetFile/${selectedItem.id}`).then((res) => res.blob()); await storeGLTF(selectedItem.id, modelBlob); THREE.Cache.add(selectedItem.id, gltf); - await handleModelLoad(gltf, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, setSimulationPaths, socket); + await handleModelLoad(gltf, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, setSimulationStates, socket); }, () => { TempLoader(intersectPoint!, isTempLoader, tempLoader, itemsGroup); @@ -113,7 +113,7 @@ async function handleModelLoad( tempLoader: Types.RefMesh, isTempLoader: Types.RefBoolean, setFloorItems: Types.setFloorItemSetState, - setSimulationPaths: any, + setSimulationStates: any, socket: Socket ) { const model = gltf.scene.clone(); @@ -171,7 +171,7 @@ async function handleModelLoad( }], triggers: [], connections: { - source: { pathUUID: model.uuid, pointUUID: pointUUIDs[index] }, + source: { modelUUID: model.uuid, pointUUID: pointUUIDs[index] }, targets: [] } })), @@ -219,7 +219,7 @@ async function handleModelLoad( eventData.position = newFloorItem.position; eventData.rotation = [model.rotation.x, model.rotation.y, model.rotation.z]; - setSimulationPaths((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => [ + setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => [ ...(prevEvents || []), eventData as Types.ConveyorEventsSchema ]); @@ -235,7 +235,7 @@ async function handleModelLoad( points: { uuid: pointUUID, position: res.points.position as [number, number, number], - actions: { uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', type: 'Start', start: {}, hitCount: 1, end: {}, buffer: 0 }, + actions: { uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', type: '', start: {}, hitCount: 1, end: {}, buffer: 0 }, connections: { source: { modelUUID: model.uuid, pointUUID: pointUUID }, targets: [] }, speed: 2, } @@ -281,13 +281,50 @@ async function handleModelLoad( return updatedItems; }); - setSimulationPaths((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => [ + setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => [ ...(prevEvents || []), eventData as Types.VehicleEventsSchema ]); socket.emit("v2:model-asset:add", data); + } else { + + // API + + // await setFloorItemApi( + // organization, + // newFloorItem.modeluuid, + // newFloorItem.modelname, + // newFloorItem.modelfileID, + // newFloorItem.position, + // { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z }, + // false, + // true, + // ); + + // SOCKET + + const data = { + organization, + modeluuid: newFloorItem.modeluuid, + modelname: newFloorItem.modelname, + modelfileID: newFloorItem.modelfileID, + position: newFloorItem.position, + rotation: { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z }, + isLocked: false, + isVisible: true, + socketId: socket.id + }; + + + setFloorItems((prevItems) => { + const updatedItems = [...(prevItems || []), newFloorItem]; + localStorage.setItem("FloorItems", JSON.stringify(updatedItems)); + return updatedItems; + }); + + socket.emit("v2:model-asset:add", data); } gsap.to(model.position, { y: newFloorItem.position[1], duration: 1.5, ease: "power2.out" }); diff --git a/app/src/modules/builder/geomentries/assets/deleteFloorItems.ts b/app/src/modules/builder/geomentries/assets/deleteFloorItems.ts index a71aaea..028863c 100644 --- a/app/src/modules/builder/geomentries/assets/deleteFloorItems.ts +++ b/app/src/modules/builder/geomentries/assets/deleteFloorItems.ts @@ -10,7 +10,7 @@ async function DeleteFloorItems( itemsGroup: Types.RefGroup, hoveredDeletableFloorItem: Types.RefMesh, setFloorItems: Types.setFloorItemSetState, - setSimulationPaths: any, + setSimulationStates: any, socket: Socket ): Promise { @@ -76,7 +76,7 @@ async function DeleteFloorItems( } setFloorItems(updatedItems); - setSimulationPaths((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => { + setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => { const updatedEvents = (prevEvents || []).filter(event => event.modeluuid !== removedItem.modeluuid); return updatedEvents; }); diff --git a/app/src/modules/builder/groups/floorItemsGroup.tsx b/app/src/modules/builder/groups/floorItemsGroup.tsx index cef7d74..96f4fad 100644 --- a/app/src/modules/builder/groups/floorItemsGroup.tsx +++ b/app/src/modules/builder/groups/floorItemsGroup.tsx @@ -10,7 +10,7 @@ import { useRenderDistance, useselectedFloorItem, useSelectedItem, - useSimulationPaths, + useSimulationStates, useSocketStore, useToggleView, useTransformMode, @@ -65,7 +65,7 @@ const FloorItemsGroup = ({ const { setselectedFloorItem } = useselectedFloorItem(); const { activeTool } = useActiveTool(); const { selectedItem, setSelectedItem } = useSelectedItem(); - const { simulationPaths, setSimulationPaths } = useSimulationPaths(); + const { simulationStates, setSimulationStates } = useSimulationStates(); const { setLoadingProgress } = useLoadingProgress(); const { activeModule } = useModuleStore(); const { socket } = useSocketStore(); @@ -111,7 +111,7 @@ const FloorItemsGroup = ({ gltfLoaderWorker.postMessage({ floorItems: data }); } else { gltfLoaderWorker.postMessage({ floorItems: [] }); - loadInitialFloorItems(itemsGroup, setFloorItems, setSimulationPaths); + loadInitialFloorItems(itemsGroup, setFloorItems, setSimulationStates); updateLoadingProgress(100); } }); @@ -130,7 +130,7 @@ const FloorItemsGroup = ({ updateLoadingProgress(progress); if (loadedAssets === totalAssets) { - loadInitialFloorItems(itemsGroup, setFloorItems, setSimulationPaths); + loadInitialFloorItems(itemsGroup, setFloorItems, setSimulationStates); updateLoadingProgress(100); } }); @@ -248,7 +248,7 @@ const FloorItemsGroup = ({ itemsGroup, hoveredDeletableFloorItem, setFloorItems, - setSimulationPaths, + setSimulationStates, socket ); } @@ -374,7 +374,7 @@ const FloorItemsGroup = ({ socket, selectedItem, setSelectedItem, - setSimulationPaths, + setSimulationStates, plane ); } diff --git a/app/src/modules/collaboration/collabCams.tsx b/app/src/modules/collaboration/collabCams.tsx index 20d983e..a1383f2 100644 --- a/app/src/modules/collaboration/collabCams.tsx +++ b/app/src/modules/collaboration/collabCams.tsx @@ -12,203 +12,189 @@ import CollabUserIcon from "./collabUserIcon"; import { getAvatarColor } from "./users/functions/getAvatarColor"; const CamModelsGroup = () => { - let navigate = useNavigate(); - const groupRef = useRef(null); - const email = localStorage.getItem("email"); - const { activeUsers, setActiveUsers } = useActiveUsers(); - const { socket } = useSocketStore(); - const loader = new GLTFLoader(); - const dracoLoader = new DRACOLoader(); - const [cams, setCams] = useState([]); - const [models, setModels] = useState>({}); + const navigate = useNavigate(); + const groupRef = useRef(null); + const email = localStorage.getItem("email"); + const { activeUsers, setActiveUsers } = useActiveUsers(); + const { socket } = useSocketStore(); - dracoLoader.setDecoderPath("three/examples/jsm/libs/draco/gltf/"); - loader.setDRACOLoader(dracoLoader); + const loader = new GLTFLoader(); + const dracoLoader = new DRACOLoader(); + dracoLoader.setDecoderPath("three/examples/jsm/libs/draco/gltf/"); + loader.setDRACOLoader(dracoLoader); - useEffect(() => { - if (!email) { - navigate("/"); - } - if (!socket) return; - const organization = email!.split("@")[1].split(".")[0]; + const [cams, setCams] = useState([]); + const [models, setModels] = useState>({}); - socket.on("userConnectResponse", (data: any) => { - if (!groupRef.current) return; - if (data.data.userData.email === email) return; - if (socket.id === data.socketId || organization !== data.organization) - return; + const dedupeCams = (cams: any[]) => { + const seen = new Set(); + return cams.filter((cam) => { + if (seen.has(cam.uuid)) return false; + seen.add(cam.uuid); + return true; + }); + }; - const model = groupRef.current.getObjectByProperty( - "uuid", - data.data.userData._id - ); - if (model) { - groupRef.current.remove(model); - } - loader.load(camModel, (gltf) => { - const newModel = gltf.scene.clone(); - newModel.uuid = data.data.userData._id; - newModel.position.set( - data.data.position.x, - data.data.position.y, - data.data.position.z - ); - newModel.rotation.set( - data.data.rotation.x, - data.data.rotation.y, - data.data.rotation.z - ); - newModel.userData = data.data.userData; - setCams((prev) => [...prev, newModel]); - setActiveUsers([...activeUsers, data.data.userData]); - }); - }); + const dedupeUsers = (users: any[]) => { + const seen = new Set(); + return users.filter((user) => { + if (seen.has(user._id)) return false; + seen.add(user._id); + return true; + }); + }; - // socket.on("users:online", (data: any) => { - // console.log('users online: ', data); - // }) + useEffect(() => { + if (!email) navigate("/"); - socket.on("userDisConnectResponse", (data: any) => { - if (!groupRef.current) return; - if (socket.id === data.socketId || organization !== data.organization) - return; + if (!socket) return; + const organization = email!.split("@")[1].split(".")[0]; - setCams((prev) => - prev.filter((cam) => cam.uuid !== data.data.userData._id) - ); - setActiveUsers( - activeUsers.filter((user: any) => user._id !== data.data.userData._id) - ); - }); + socket.on("userConnectResponse", (data: any) => { + if (!groupRef.current) return; + if (data.data.userData.email === email) return; + if (socket.id === data.socketId || organization !== data.organization) return; - socket.on("cameraUpdateResponse", (data: any) => { - if ( - !groupRef.current || - socket.id === data.socketId || - organization !== data.organization - ) - return; + const model = groupRef.current.getObjectByProperty("uuid", data.data.userData._id); + if (model) { + groupRef.current.remove(model); + } - setModels((prev) => ({ - ...prev, - [data.data.userId]: { - targetPosition: new THREE.Vector3( - data.data.position.x, - data.data.position.y, - data.data.position.z - ), - targetRotation: new THREE.Euler( - data.data.rotation.x, - data.data.rotation.y, - data.data.rotation.z - ), - }, - })); - }); + loader.load(camModel, (gltf) => { + const newModel = gltf.scene.clone(); + newModel.uuid = data.data.userData._id; + newModel.position.set( + data.data.position.x, + data.data.position.y, + data.data.position.z + ); + newModel.rotation.set( + data.data.rotation.x, + data.data.rotation.y, + data.data.rotation.z + ); + newModel.userData = data.data.userData; - return () => { - socket.off("userConnectRespones"); - socket.off("userDisConnectRespones"); - socket.off("cameraUpdateResponse"); - }; - }, [socket]); + setCams((prev) => dedupeCams([...prev, newModel])); + setActiveUsers((prev: any) => + dedupeUsers([...prev, data.data.userData]) + ); + }); + }); + socket.on("userDisConnectResponse", (data: any) => { + if (!groupRef.current) return; + if (socket.id === data.socketId || organization !== data.organization) return; - // useEffect(() => { - // console.log(activeUsers); - // }, [activeUsers]) + setCams((prev) => + prev.filter((cam) => cam.uuid !== data.data.userData._id) + ); + setActiveUsers((prev: any) => + prev.filter((user: any) => user._id !== data.data.userData._id) + ); + }); - // useEffect(() => { - // console.log(models); - // }, [models]) + socket.on("cameraUpdateResponse", (data: any) => { + if ( + !groupRef.current || + socket.id === data.socketId || + organization !== data.organization + ) + return; - useFrame(() => { - if (!groupRef.current) return; - Object.keys(models).forEach((uuid) => { - const model = groupRef.current!.getObjectByProperty("uuid", uuid); - if (!model) return; + setModels((prev) => ({ + ...prev, + [data.data.userId]: { + targetPosition: new THREE.Vector3( + data.data.position.x, + data.data.position.y, + data.data.position.z + ), + targetRotation: new THREE.Euler( + data.data.rotation.x, + data.data.rotation.y, + data.data.rotation.z + ), + }, + })); + }); - const { targetPosition, targetRotation } = models[uuid]; - model.position.lerp(targetPosition, 0.1); - model.rotation.x = THREE.MathUtils.lerp( - model.rotation.x, - targetRotation.x, - 0.1 - ); - model.rotation.y = THREE.MathUtils.lerp( - model.rotation.y, - targetRotation.y, - 0.1 - ); - model.rotation.z = THREE.MathUtils.lerp( - model.rotation.z, - targetRotation.z, - 0.1 - ); - }); - }); + return () => { + socket.off("userConnectResponse"); + socket.off("userDisConnectResponse"); + socket.off("cameraUpdateResponse"); + }; + }, [socket]); - useEffect(() => { - if (!groupRef.current) return; - const organization = email!.split("@")[1].split(".")[0]; - getActiveUsersData(organization).then((data) => { - const filteredData = data.cameraDatas.filter( - (camera: any) => camera.userData.email !== email - ); - let a: any = []; - if (filteredData.length > 0) { - loader.load(camModel, (gltf) => { - const newCams = filteredData.map((cam: any) => { - const newModel = gltf.scene.clone(); - newModel.uuid = cam.userData._id; - newModel.position.set( - cam.position.x, - cam.position.y, - cam.position.z - ); - newModel.rotation.set( - cam.rotation.x, - cam.rotation.y, - cam.rotation.z - ); - newModel.userData = cam.userData; - a.push(cam.userData); - return newModel; - }); - setActiveUsers(a); - setCams((prev) => [...prev, ...newCams]); - }); - } - }); - }, []); + useFrame(() => { + if (!groupRef.current) return; + Object.keys(models).forEach((uuid) => { + const model = groupRef.current!.getObjectByProperty("uuid", uuid); + if (!model) return; - return ( - - {cams.map((cam, index) => ( - - - - - - ))} - - ); + const { targetPosition, targetRotation } = models[uuid]; + model.position.lerp(targetPosition, 0.1); + model.rotation.x = THREE.MathUtils.lerp(model.rotation.x, targetRotation.x, 0.1); + model.rotation.y = THREE.MathUtils.lerp(model.rotation.y, targetRotation.y, 0.1); + model.rotation.z = THREE.MathUtils.lerp(model.rotation.z, targetRotation.z, 0.1); + }); + }); + + useEffect(() => { + if (!groupRef.current) return; + const organization = email!.split("@")[1].split(".")[0]; + + getActiveUsersData(organization).then((data) => { + const filteredData = data.cameraDatas.filter( + (camera: any) => camera.userData.email !== email + ); + + if (filteredData.length > 0) { + loader.load(camModel, (gltf) => { + const newCams = filteredData.map((cam: any) => { + const newModel = gltf.scene.clone(); + newModel.uuid = cam.userData._id; + newModel.position.set(cam.position.x, cam.position.y, cam.position.z); + newModel.rotation.set(cam.rotation.x, cam.rotation.y, cam.rotation.z); + newModel.userData = cam.userData; + return newModel; + }); + + const users = filteredData.map((cam: any) => cam.userData); + setActiveUsers((prev: any) => dedupeUsers([...prev, ...users])); + setCams((prev) => dedupeCams([...prev, ...newCams])); + }); + } + }); + }, []); + + return ( + + {cams.map((cam, index) => ( + + + + + + ))} + + ); }; export default CamModelsGroup; diff --git a/app/src/modules/collaboration/collabUserIcon.tsx b/app/src/modules/collaboration/collabUserIcon.tsx index acc3fa0..4cea436 100644 --- a/app/src/modules/collaboration/collabUserIcon.tsx +++ b/app/src/modules/collaboration/collabUserIcon.tsx @@ -20,7 +20,24 @@ const CollabUserIcon: React.FC = ({ {userImage ? ( {userName} ) : ( - + + //
+ // {userName[0]} + //
)}
diff --git a/app/src/modules/collaboration/socketResponses.dev.tsx b/app/src/modules/collaboration/socketResponses.dev.tsx index 8771303..ceef567 100644 --- a/app/src/modules/collaboration/socketResponses.dev.tsx +++ b/app/src/modules/collaboration/socketResponses.dev.tsx @@ -233,7 +233,7 @@ export default function SocketResponses({ } } else if (data.message === "Model updated successfully") { - itemsGroup.current.children.forEach((item: THREE.Group) => { + itemsGroup.current?.children.forEach((item: THREE.Group) => { if (item.uuid === data.data.modeluuid) { item.position.set(...data.data.position as [number, number, number]); item.rotation.set(data.data.rotation.x, data.data.rotation.y, data.data.rotation.z); diff --git a/app/src/modules/collaboration/users/Avatar.tsx b/app/src/modules/collaboration/users/Avatar.tsx index f08a545..b04ff7d 100644 --- a/app/src/modules/collaboration/users/Avatar.tsx +++ b/app/src/modules/collaboration/users/Avatar.tsx @@ -7,6 +7,7 @@ interface AvatarProps { size?: number; index?: number; textColor?: string; + color?: string; // Optional color prop for future use } const CustomAvatar: React.FC = ({ @@ -14,6 +15,7 @@ const CustomAvatar: React.FC = ({ size = 100, index = 0, textColor = "#ffffff", + color, // Optional color prop for future use }) => { const [imageSrc, setImageSrc] = useState(null); @@ -26,7 +28,7 @@ const CustomAvatar: React.FC = ({ const initials = getInitials(name); // Convert name to initials if needed // Draw background - ctx.fillStyle = getAvatarColor(index); + ctx.fillStyle = color || getAvatarColor(index); // Use color prop or generate color based on index ctx.fillRect(0, 0, size, size); // Draw initials @@ -40,7 +42,7 @@ const CustomAvatar: React.FC = ({ const dataURL = canvas.toDataURL("image/png"); setImageSrc(dataURL); } - }, [name, size, textColor]); + }, [name, size, textColor, index]); if (!imageSrc) { return null; // Return null while the image is being generated @@ -53,6 +55,18 @@ const CustomAvatar: React.FC = ({ alt="User Avatar" style={{ width: "100%", height: "100%" }} /> + //
+ // {name[0]} + //
); }; diff --git a/app/src/modules/scene/IntialLoad/loadInitialFloorItems.ts b/app/src/modules/scene/IntialLoad/loadInitialFloorItems.ts index 5dd41de..ec6033b 100644 --- a/app/src/modules/scene/IntialLoad/loadInitialFloorItems.ts +++ b/app/src/modules/scene/IntialLoad/loadInitialFloorItems.ts @@ -12,7 +12,7 @@ import { getFloorAssets } from '../../../services/factoryBuilder/assest/floorAss async function loadInitialFloorItems( itemsGroup: Types.RefGroup, setFloorItems: Types.setFloorItemSetState, - setSimulationPaths: (paths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => void + setSimulationStates: (paths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => void ): Promise { if (!itemsGroup.current) return; let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`; @@ -71,7 +71,7 @@ async function loadInitialFloorItems( const cachedModel = THREE.Cache.get(item.modelfileID!); if (cachedModel) { // console.log(`[Cache] Fetching ${item.modelname}`); - processLoadedModel(cachedModel.scene.clone(), item, itemsGroup, setFloorItems, setSimulationPaths); + processLoadedModel(cachedModel.scene.clone(), item, itemsGroup, setFloorItems, setSimulationStates); modelsLoaded++; checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve); return; @@ -88,7 +88,7 @@ async function loadInitialFloorItems( URL.revokeObjectURL(blobUrl); THREE.Cache.remove(blobUrl); THREE.Cache.add(item.modelfileID!, gltf); - processLoadedModel(gltf.scene.clone(), item, itemsGroup, setFloorItems, setSimulationPaths); + processLoadedModel(gltf.scene.clone(), item, itemsGroup, setFloorItems, setSimulationStates); modelsLoaded++; checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve); }, @@ -111,7 +111,7 @@ async function loadInitialFloorItems( const modelBlob = await fetch(modelUrl).then((res) => res.blob()); await storeGLTF(item.modelfileID!, modelBlob); THREE.Cache.add(item.modelfileID!, gltf); - processLoadedModel(gltf.scene.clone(), item, itemsGroup, setFloorItems, setSimulationPaths); + processLoadedModel(gltf.scene.clone(), item, itemsGroup, setFloorItems, setSimulationStates); modelsLoaded++; checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve); }, @@ -137,8 +137,8 @@ async function loadInitialFloorItems( }, ]); - if (item.eventData) { - processEventData(item, setSimulationPaths); + if (item.eventData || item.modelfileID === '67e3db95c2e8f37134526fb2') { + processEventData(item, setSimulationStates); } modelsLoaded++; @@ -157,7 +157,7 @@ function processLoadedModel( item: Types.EventData, itemsGroup: Types.RefGroup, setFloorItems: Types.setFloorItemSetState, - setSimulationPaths: (paths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => void + setSimulationStates: (paths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => void ) { const model = gltf; model.uuid = item.modeluuid; @@ -192,15 +192,15 @@ function processLoadedModel( }, ]); - if (item.eventData) { - processEventData(item, setSimulationPaths); + if (item.eventData || item.modelfileID === '67e3db95c2e8f37134526fb2') { + processEventData(item, setSimulationStates); } gsap.to(model.position, { y: item.position[1], duration: 1.5, ease: 'power2.out' }); gsap.to(model.scale, { x: 1, y: 1, z: 1, duration: 1.5, ease: 'power2.out' }); } -function processEventData(item: Types.EventData, setSimulationPaths: any) { +function processEventData(item: Types.EventData, setSimulationStates: any) { if (item.eventData?.type === 'Conveyor') { @@ -210,23 +210,46 @@ function processEventData(item: Types.EventData, setSimulationPaths: any) { data.position = item.position; data.rotation = [item.rotation.x, item.rotation.y, item.rotation.z]; - setSimulationPaths((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => [ + setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => [ ...(prevEvents || []), data as Types.ConveyorEventsSchema ]); - } else { + } else if (item.eventData?.type === 'Vehicle') { const data: any = item.eventData; data.modeluuid = item.modeluuid; data.modelName = item.modelname; data.position = item.position; - setSimulationPaths((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => [ + setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => [ ...(prevEvents || []), data as Types.VehicleEventsSchema ]); + } else if (item.modelfileID === '67e3db95c2e8f37134526fb2') { + + const pointUUID = THREE.MathUtils.generateUUID(); + const pointPosition = new THREE.Vector3(0, 1.75, 0); + + const staticMachine: Types.StaticMachineEventsSchema = { + modeluuid: item.modeluuid, + modelName: item.modelname, + type: "StaticMachine", + points: { + uuid: pointUUID, + position: [pointPosition.x, pointPosition.y, pointPosition.z], + actions: { uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', buffer: 'Inherit', material: 'Inherit', isUsed: false }, + triggers: { uuid: THREE.MathUtils.generateUUID(), name: 'Trigger 1', type: 'OnComplete' }, + connections: { source: { modelUUID: item.modeluuid, pointUUID: pointUUID }, targets: [] }, + }, + position: item.position + }; + + setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => [ + ...(prevEvents || []), + staticMachine as Types.StaticMachineEventsSchema + ]); } } diff --git a/app/src/modules/scene/controls/selection/copyPasteControls.tsx b/app/src/modules/scene/controls/selection/copyPasteControls.tsx index abcc1b0..44dc2bf 100644 --- a/app/src/modules/scene/controls/selection/copyPasteControls.tsx +++ b/app/src/modules/scene/controls/selection/copyPasteControls.tsx @@ -1,7 +1,7 @@ import * as THREE from "three"; import { useEffect, useMemo } from "react"; import { useFrame, useThree } from "@react-three/fiber"; -import { useFloorItems, useSelectedAssets, useSimulationPaths, useSocketStore, useToggleView } from "../../../../store/store"; +import { useFloorItems, useSelectedAssets, useSimulationStates, useSocketStore, useToggleView } from "../../../../store/store"; import { toast } from "react-toastify"; // import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi'; import * as Types from "../../../../types/world/worldTypes"; @@ -10,7 +10,7 @@ const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pas const { camera, controls, gl, scene, pointer, raycaster } = useThree(); const { toggleView } = useToggleView(); const { selectedAssets, setSelectedAssets } = useSelectedAssets(); - const { simulationPaths, setSimulationPaths } = useSimulationPaths(); + const { simulationStates, setSimulationStates } = useSimulationStates(); const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []); const { floorItems, setFloorItems } = useFloorItems(); const { socket } = useSocketStore() @@ -151,7 +151,7 @@ const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pas return updatedItems; }); - let eventData: Types.ConveyorEventsSchema | Types.VehicleEventsSchema | undefined = simulationPaths.find((events) => events.modeluuid === obj.userData.modeluuid); + let eventData: Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | undefined = simulationStates.find((events) => events.modeluuid === obj.userData.modeluuid); const email = localStorage.getItem("email"); const organization = email ? email.split("@")[1].split(".")[0] : "default"; @@ -183,7 +183,7 @@ const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pas : [defaultAction], triggers: (eventData as Types.ConveyorEventsSchema)?.points[index].triggers, connections: { - source: { pathUUID: obj.uuid, pointUUID }, + source: { modelUUID: obj.uuid, pointUUID }, targets: [] } }; @@ -224,17 +224,17 @@ const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pas rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z }, isLocked: false, isVisible: true, - eventData: backendEventData, + eventData: { type: backendEventData.type, points: backendEventData.points, speed: backendEventData.speed }, socketId: socket.id, }; - const newEventData: any = backendEventData; + const newEventData: any = { type: backendEventData.type, points: backendEventData.points, speed: backendEventData.speed }; newEventData.modeluuid = newFloorItem.modeluuid; newEventData.modelName = newFloorItem.modelname; newEventData.position = newFloorItem.position; newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z]; - setSimulationPaths((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => [ + setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => [ ...(prevEvents || []), newEventData as Types.ConveyorEventsSchema ]); @@ -277,7 +277,6 @@ const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pas const backendEventData = { type: 'Vehicle', points: createVehiclePoint(), - speed: (eventData as Types.VehicleEventsSchema)?.points.speed }; // API @@ -305,16 +304,16 @@ const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pas rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z }, isLocked: false, isVisible: true, - eventData: backendEventData, + eventData: { type: backendEventData.type, points: backendEventData.points }, socketId: socket.id, }; - const newEventData: any = backendEventData; + const newEventData: any = { type: backendEventData.type, points: backendEventData.points }; newEventData.modeluuid = newFloorItem.modeluuid; newEventData.modelName = newFloorItem.modelname; newEventData.position = newFloorItem.position; - setSimulationPaths((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => [ + setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => [ ...(prevEvents || []), newEventData as Types.VehicleEventsSchema ]); diff --git a/app/src/modules/scene/controls/selection/duplicationControls.tsx b/app/src/modules/scene/controls/selection/duplicationControls.tsx index c28c401..0c22f60 100644 --- a/app/src/modules/scene/controls/selection/duplicationControls.tsx +++ b/app/src/modules/scene/controls/selection/duplicationControls.tsx @@ -1,7 +1,7 @@ import * as THREE from "three"; import { useEffect, useMemo } from "react"; import { useFrame, useThree } from "@react-three/fiber"; -import { useFloorItems, useSelectedAssets, useSimulationPaths, useSocketStore, useToggleView } from "../../../../store/store"; +import { useFloorItems, useSelectedAssets, useSimulationStates, useSocketStore, useToggleView } from "../../../../store/store"; import { toast } from "react-toastify"; // import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi'; import * as Types from "../../../../types/world/worldTypes"; @@ -11,7 +11,7 @@ const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedOb const { camera, controls, gl, scene, pointer, raycaster } = useThree(); const { toggleView } = useToggleView(); const { selectedAssets, setSelectedAssets } = useSelectedAssets(); - const { simulationPaths, setSimulationPaths } = useSimulationPaths(); + const { simulationStates, setSimulationStates } = useSimulationStates(); const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []); const { floorItems, setFloorItems } = useFloorItems(); const { socket } = useSocketStore(); @@ -132,7 +132,7 @@ const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedOb return updatedItems; }); - let eventData: Types.ConveyorEventsSchema | Types.VehicleEventsSchema | undefined = simulationPaths.find((events) => events.modeluuid === obj.userData.modeluuid); + let eventData: Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | undefined = simulationStates.find((events) => events.modeluuid === obj.userData.modeluuid); const email = localStorage.getItem("email"); const organization = email ? email.split("@")[1].split(".")[0] : "default"; @@ -165,7 +165,7 @@ const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedOb : [defaultAction], triggers: (eventData as Types.ConveyorEventsSchema)?.points[index].triggers, connections: { - source: { pathUUID: obj.uuid, pointUUID }, + source: { modelUUID: newFloorItem.modeluuid, pointUUID }, targets: [] } }; @@ -206,17 +206,17 @@ const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedOb rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z }, isLocked: false, isVisible: true, - eventData: backendEventData, + eventData: { type: backendEventData.type, points: backendEventData.points, speed: backendEventData.speed }, socketId: socket.id, }; - const newEventData: any = backendEventData; + const newEventData: any = { type: backendEventData.type, points: backendEventData.points, speed: backendEventData.speed }; newEventData.modeluuid = newFloorItem.modeluuid; newEventData.modelName = newFloorItem.modelname; newEventData.position = newFloorItem.position; newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z]; - setSimulationPaths((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => [ + setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => [ ...(prevEvents || []), newEventData as Types.ConveyorEventsSchema ]); @@ -286,16 +286,16 @@ const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedOb rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z }, isLocked: false, isVisible: true, - eventData: backendEventData, + eventData: { type: backendEventData.type, points: backendEventData.points }, socketId: socket.id, }; - const newEventData: any = backendEventData; + const newEventData: any = { type: backendEventData.type, points: backendEventData.points }; newEventData.modeluuid = newFloorItem.modeluuid; newEventData.modelName = newFloorItem.modelname; newEventData.position = newFloorItem.position; - setSimulationPaths((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => [ + setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => [ ...(prevEvents || []), newEventData as Types.VehicleEventsSchema ]); diff --git a/app/src/modules/scene/controls/selection/moveControls.tsx b/app/src/modules/scene/controls/selection/moveControls.tsx index a4340b5..2693531 100644 --- a/app/src/modules/scene/controls/selection/moveControls.tsx +++ b/app/src/modules/scene/controls/selection/moveControls.tsx @@ -1,7 +1,7 @@ import * as THREE from "three"; import { useEffect, useMemo, useRef, useState } from "react"; import { useFrame, useThree } from "@react-three/fiber"; -import { useFloorItems, useSelectedAssets, useSimulationPaths, useSocketStore, useToggleView } from "../../../../store/store"; +import { useFloorItems, useSelectedAssets, useSimulationStates, useSocketStore, useToggleView } from "../../../../store/store"; // import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi'; import { toast } from "react-toastify"; import * as Types from "../../../../types/world/worldTypes"; @@ -12,7 +12,7 @@ function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObje const { toggleView } = useToggleView(); const { selectedAssets, setSelectedAssets } = useSelectedAssets(); - const { simulationPaths, setSimulationPaths } = useSimulationPaths(); + const { simulationStates, setSimulationStates } = useSimulationStates(); const { floorItems, setFloorItems } = useFloorItems(); const { socket } = useSocketStore(); const itemsData = useRef([]); @@ -180,12 +180,12 @@ function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObje return updatedItems; }); - let eventData: Types.ConveyorEventsSchema | Types.VehicleEventsSchema | undefined = simulationPaths.find((events) => events.modeluuid === obj.userData.modeluuid); + let eventData: Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | undefined = simulationStates.find((events) => events.modeluuid === obj.userData.modeluuid); const email = localStorage.getItem("email"); const organization = email ? email.split("@")[1].split(".")[0] : "default"; - if (eventData) { + if (eventData && eventData.type !== 'StaticMachine') { if (eventData.type === 'Conveyor' && eventData) { const backendEventData = { @@ -205,7 +205,7 @@ function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObje // obj.userData.modelId, // false, // true, - // backendEventData + // { type: backendEventData.type, points: backendEventData.points, speed: backendEventData.speed } // ); //SOCKET @@ -219,17 +219,17 @@ function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObje rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z }, isLocked: false, isVisible: true, - eventData: backendEventData, + eventData: { type: backendEventData.type, points: backendEventData.points, speed: backendEventData.speed }, socketId: socket.id, }; - const newEventData: any = backendEventData; + const newEventData: any = { type: backendEventData.type, points: backendEventData.points, speed: backendEventData.speed }; newEventData.modeluuid = newFloorItem.modeluuid; newEventData.modelName = newFloorItem.modelname; newEventData.position = newFloorItem.position; newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z]; - setSimulationPaths((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => { + setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => { const updatedEvents = (prevEvents || []).map(event => event.modeluuid === newFloorItem.modeluuid ? { ...event, ...newEventData } @@ -257,7 +257,7 @@ function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObje // { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z }, // false, // true, - // backendEventData + // { type: backendEventData.type, points: backendEventData.points } // ); //SOCKET @@ -271,16 +271,16 @@ function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObje rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z }, isLocked: false, isVisible: true, - eventData: backendEventData, + eventData: { type: backendEventData.type, points: backendEventData.points }, socketId: socket.id, }; - const newEventData: any = backendEventData; + const newEventData: any = { type: backendEventData.type, points: backendEventData.points }; newEventData.modeluuid = newFloorItem.modeluuid; newEventData.modelName = newFloorItem.modelname; newEventData.position = newFloorItem.position; - setSimulationPaths((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => { + setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => { const updatedEvents = (prevEvents || []).map(event => event.modeluuid === newFloorItem.modeluuid ? { ...event, ...newEventData } diff --git a/app/src/modules/scene/controls/selection/rotateControls.tsx b/app/src/modules/scene/controls/selection/rotateControls.tsx index 708a00a..bff9fd6 100644 --- a/app/src/modules/scene/controls/selection/rotateControls.tsx +++ b/app/src/modules/scene/controls/selection/rotateControls.tsx @@ -1,7 +1,7 @@ import * as THREE from "three"; import { useEffect, useMemo, useRef, useState } from "react"; import { useFrame, useThree } from "@react-three/fiber"; -import { useFloorItems, useSelectedAssets, useSimulationPaths, useSocketStore, useToggleView } from "../../../../store/store"; +import { useFloorItems, useSelectedAssets, useSimulationStates, useSocketStore, useToggleView } from "../../../../store/store"; // import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi'; import { toast } from "react-toastify"; import * as Types from "../../../../types/world/worldTypes"; @@ -13,7 +13,7 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo const { toggleView } = useToggleView(); const { selectedAssets, setSelectedAssets } = useSelectedAssets(); - const { simulationPaths, setSimulationPaths } = useSimulationPaths(); + const { simulationStates, setSimulationStates } = useSimulationStates(); const { floorItems, setFloorItems } = useFloorItems(); const { socket } = useSocketStore(); const itemsData = useRef([]); @@ -184,12 +184,12 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo return updatedItems; }); - let eventData: Types.ConveyorEventsSchema | Types.VehicleEventsSchema | undefined = simulationPaths.find((events) => events.modeluuid === obj.userData.modeluuid); + let eventData: Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | undefined = simulationStates.find((events) => events.modeluuid === obj.userData.modeluuid); const email = localStorage.getItem("email"); const organization = email ? email.split("@")[1].split(".")[0] : "default"; - if (eventData) { + if (eventData && eventData.type !== 'StaticMachine') { if (eventData.type === 'Conveyor' && eventData) { const backendEventData = { @@ -209,7 +209,7 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo // { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z }, // false, // true, - // backendEventData + // { type: backendEventData.type, points: backendEventData.points, speed: backendEventData.speed } // ); //SOCKET @@ -223,17 +223,17 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z }, isLocked: false, isVisible: true, - eventData: backendEventData, + eventData: { type: backendEventData.type, points: backendEventData.points, speed: backendEventData.speed }, socketId: socket.id, }; - const newEventData: any = backendEventData; + const newEventData: any = { type: backendEventData.type, points: backendEventData.points, speed: backendEventData.speed }; newEventData.modeluuid = newFloorItem.modeluuid; newEventData.modelName = newFloorItem.modelname; newEventData.position = newFloorItem.position; newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z]; - setSimulationPaths((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => { + setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => { const updatedEvents = (prevEvents || []).map(event => event.modeluuid === newFloorItem.modeluuid ? { ...event, ...newEventData } @@ -262,7 +262,7 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo // { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z }, // false, // true, - // backendEventData + // { type: backendEventData.type, points: backendEventData.points } // ); //SOCKET @@ -276,16 +276,16 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z }, isLocked: false, isVisible: true, - eventData: backendEventData, + eventData: { type: backendEventData.type, points: backendEventData.points }, socketId: socket.id, }; - const newEventData: any = backendEventData; + const newEventData: any = { type: backendEventData.type, points: backendEventData.points }; newEventData.modeluuid = newFloorItem.modeluuid; newEventData.modelName = newFloorItem.modelname; newEventData.position = newFloorItem.position; - setSimulationPaths((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => { + setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => { const updatedEvents = (prevEvents || []).map(event => event.modeluuid === newFloorItem.modeluuid ? { ...event, ...newEventData } @@ -299,7 +299,6 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo } } else { - //REST // await setFloorItemApi( diff --git a/app/src/modules/scene/controls/selection/selectionControls.tsx b/app/src/modules/scene/controls/selection/selectionControls.tsx index fd7e19e..8a464d5 100644 --- a/app/src/modules/scene/controls/selection/selectionControls.tsx +++ b/app/src/modules/scene/controls/selection/selectionControls.tsx @@ -3,7 +3,7 @@ import { useEffect, useMemo, useRef, useState } from "react"; import { SelectionBox } from "three/examples/jsm/interactive/SelectionBox"; import { SelectionHelper } from "./selectionHelper"; import { useFrame, useThree } from "@react-three/fiber"; -import { useFloorItems, useSelectedAssets, useSimulationPaths, useSocketStore, useToggleView } from "../../../../store/store"; +import { useFloorItems, useSelectedAssets, useSimulationStates, useSocketStore, useToggleView } from "../../../../store/store"; import BoundingBox from "./boundingBoxHelper"; import { toast } from "react-toastify"; // import { deleteFloorItem } from '../../../../services/factoryBuilder/assest/floorAsset/deleteFloorItemApi'; @@ -20,7 +20,7 @@ const SelectionControls: React.FC = () => { const itemsGroupRef = useRef(undefined); const selectionGroup = useRef() as Types.RefGroup; const { toggleView } = useToggleView(); - const { setSimulationPaths } = useSimulationPaths(); + const { setSimulationStates } = useSimulationStates(); const { selectedAssets, setSelectedAssets } = useSelectedAssets(); const [movedObjects, setMovedObjects] = useState([]); const [rotatedObjects, setRotatedObjects] = useState([]); @@ -240,7 +240,7 @@ const SelectionControls: React.FC = () => { } }); - setSimulationPaths((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => { + setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => { const updatedEvents = (prevEvents || []).filter(event => event.modeluuid !== selectedMesh.uuid); return updatedEvents; }); diff --git a/app/src/modules/scene/world/world.tsx b/app/src/modules/scene/world/world.tsx index 1b4f71f..678d1a4 100644 --- a/app/src/modules/scene/world/world.tsx +++ b/app/src/modules/scene/world/world.tsx @@ -53,8 +53,8 @@ import { findEnvironment } from "../../../services/factoryBuilder/environment/fi import Layer2DVisibility from "../../builder/geomentries/layers/layer2DVisibility"; import DrieHtmlTemp from "../mqttTemp/drieHtmlTemp"; import ZoneGroup from "../../builder/groups/zoneGroup"; -import Agv from "../../builder/agv/agv"; import useModuleStore from "../../../store/useModuleStore"; +import NavMeshCreator from "../../builder/agv/navMeshCreator"; export default function World() { const state = useThree(); // Importing the state from the useThree hook, which contains the scene, camera, and other Three.js elements. @@ -368,7 +368,7 @@ export default function World() { {/* */} - {activeModule === "simulation" && } + ); diff --git a/app/src/modules/simulation/behaviour/behaviour.tsx b/app/src/modules/simulation/behaviour/behaviour.tsx index 27c791f..0ddc3aa 100644 --- a/app/src/modules/simulation/behaviour/behaviour.tsx +++ b/app/src/modules/simulation/behaviour/behaviour.tsx @@ -1,14 +1,14 @@ -import { useFloorItems, useSimulationPaths } from '../../../store/store'; +import { useFloorItems, useSimulationStates } from '../../../store/store'; import * as THREE from 'three'; import * as Types from '../../../types/world/worldTypes'; import { useEffect } from 'react'; function Behaviour() { - const { setSimulationPaths } = useSimulationPaths(); + const { setSimulationStates } = useSimulationStates(); const { floorItems } = useFloorItems(); useEffect(() => { - const newPaths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[] = []; + const newPaths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[] = []; // floorItems.forEach((item: Types.FloorItemType) => { // if (item.modelfileID === "672a090f80d91ac979f4d0bd") { @@ -31,7 +31,7 @@ function Behaviour() { // rotation: [0, 0, 0], // actions: [{ uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', type: 'Inherit', material: 'Inherit', delay: 'Inherit', spawnInterval: 'Inherit', isUsed: true }], // triggers: [], - // connections: { source: { pathUUID: item.modeluuid, pointUUID: point1UUID }, targets: [] }, + // connections: { source: { modelUUID: item.modeluuid, pointUUID: point1UUID }, targets: [] }, // }, // { // uuid: middlePointUUID, @@ -39,7 +39,7 @@ function Behaviour() { // rotation: [0, 0, 0], // actions: [{ uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', type: 'Inherit', material: 'Inherit', delay: 'Inherit', spawnInterval: 'Inherit', isUsed: true }], // triggers: [], - // connections: { source: { pathUUID: item.modeluuid, pointUUID: middlePointUUID }, targets: [] }, + // connections: { source: { modelUUID: item.modeluuid, pointUUID: middlePointUUID }, targets: [] }, // }, // { // uuid: point2UUID, @@ -47,7 +47,7 @@ function Behaviour() { // rotation: [0, 0, 0], // actions: [{ uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', type: 'Inherit', material: 'Inherit', delay: 'Inherit', spawnInterval: 'Inherit', isUsed: true }], // triggers: [], - // connections: { source: { pathUUID: item.modeluuid, pointUUID: point2UUID }, targets: [] }, + // connections: { source: { modelUUID: item.modeluuid, pointUUID: point2UUID }, targets: [] }, // }, // ], // position: [...item.position], @@ -68,7 +68,7 @@ function Behaviour() { // uuid: pointUUID, // position: [pointPosition.x, pointPosition.y, pointPosition.z], // actions: { uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', type: 'Start', start: {}, hitCount: 1, end: {}, buffer: 0 }, - // connections: { source: { pathUUID: item.modeluuid, pointUUID: pointUUID }, targets: [] }, + // connections: { source: { modelUUID: item.modeluuid, pointUUID: pointUUID }, targets: [] }, // speed: 2, // }, // position: [...item.position], @@ -78,7 +78,7 @@ function Behaviour() { // } // }); - // setSimulationPaths(newPaths); + // setSimulationStates(newPaths); // console.log('floorItems: ', floorItems); }, [floorItems]); diff --git a/app/src/modules/simulation/path/pathConnector.tsx b/app/src/modules/simulation/path/pathConnector.tsx index 3866a10..8a295be 100644 --- a/app/src/modules/simulation/path/pathConnector.tsx +++ b/app/src/modules/simulation/path/pathConnector.tsx @@ -3,19 +3,21 @@ import React, { useEffect, useState } from 'react'; import * as THREE from 'three'; import * as Types from '../../../types/world/worldTypes'; import { QuadraticBezierLine } from '@react-three/drei'; -import { useIsConnecting, useSimulationPaths } from '../../../store/store'; +import { useIsConnecting, useSimulationStates, useSocketStore } from '../../../store/store'; import useModuleStore from '../../../store/useModuleStore'; import { usePlayButtonStore } from '../../../store/usePlayButtonStore'; +import { setEventApi } from '../../../services/factoryBuilder/assest/floorAsset/setEventsApt'; function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObject }) { const { activeModule } = useModuleStore(); const { gl, raycaster, scene, pointer, camera } = useThree(); const { setIsConnecting } = useIsConnecting(); - const { simulationPaths, setSimulationPaths } = useSimulationPaths(); + const { simulationStates, setSimulationStates } = useSimulationStates(); const { isPlaying } = usePlayButtonStore(); + const { socket } = useSocketStore(); const [firstSelected, setFirstSelected] = useState<{ - pathUUID: string; + modelUUID: string; sphereUUID: string; position: THREE.Vector3; isCorner: boolean; @@ -24,26 +26,26 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec const [helperlineColor, setHelperLineColor] = useState('red'); const updatePathConnections = ( - fromPathUUID: string, + fromModelUUID: string, fromPointUUID: string, - toPathUUID: string, + toModelUUID: string, toPointUUID: string ) => { - const updatedPaths = simulationPaths.map(path => { + const updatedPaths = simulationStates.map(path => { if (path.type === 'Conveyor') { - if (path.modeluuid === fromPathUUID) { + if (path.modeluuid === fromModelUUID) { return { ...path, points: path.points.map(point => { if (point.uuid === fromPointUUID) { const newTarget = { - pathUUID: toPathUUID, + modelUUID: toModelUUID, pointUUID: toPointUUID }; const existingTargets = point.connections.targets || []; if (!existingTargets.some(target => - target.pathUUID === newTarget.pathUUID && + target.modelUUID === newTarget.modelUUID && target.pointUUID === newTarget.pointUUID )) { return { @@ -59,19 +61,19 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec }) }; } - else if (path.modeluuid === toPathUUID) { + else if (path.modeluuid === toModelUUID) { return { ...path, points: path.points.map(point => { if (point.uuid === toPointUUID) { const reverseTarget = { - pathUUID: fromPathUUID, + modelUUID: fromModelUUID, pointUUID: fromPointUUID }; const existingTargets = point.connections.targets || []; if (!existingTargets.some(target => - target.pathUUID === reverseTarget.pathUUID && + target.modelUUID === reverseTarget.modelUUID && target.pointUUID === reverseTarget.pointUUID )) { return { @@ -88,18 +90,17 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec }; } } - // In the updatePathConnections function, modify the Vehicle handling section: else if (path.type === 'Vehicle') { // Handle outgoing connections from Vehicle - if (path.modeluuid === fromPathUUID && path.points.uuid === fromPointUUID) { + if (path.modeluuid === fromModelUUID && path.points.uuid === fromPointUUID) { const newTarget = { - pathUUID: toPathUUID, + modelUUID: toModelUUID, pointUUID: toPointUUID }; const existingTargets = path.points.connections.targets || []; // Check if target is a Conveyor - const toPath = simulationPaths.find(p => p.modeluuid === toPathUUID); + const toPath = simulationStates.find(p => p.modeluuid === toModelUUID); if (toPath?.type !== 'Conveyor') { console.log("Vehicle can only connect to Conveyors"); return path; @@ -112,7 +113,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec } if (!existingTargets.some(target => - target.pathUUID === newTarget.pathUUID && + target.modelUUID === newTarget.modelUUID && target.pointUUID === newTarget.pointUUID )) { return { @@ -128,15 +129,15 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec } } // Handle incoming connections to Vehicle - else if (path.modeluuid === toPathUUID && path.points.uuid === toPointUUID) { + else if (path.modeluuid === toModelUUID && path.points.uuid === toPointUUID) { const reverseTarget = { - pathUUID: fromPathUUID, + modelUUID: fromModelUUID, pointUUID: fromPointUUID }; const existingTargets = path.points.connections.targets || []; // Check if source is a Conveyor - const fromPath = simulationPaths.find(p => p.modeluuid === fromPathUUID); + const fromPath = simulationStates.find(p => p.modeluuid === fromModelUUID); if (fromPath?.type !== 'Conveyor') { console.log("Vehicle can only connect to Conveyors"); return path; @@ -149,7 +150,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec } if (!existingTargets.some(target => - target.pathUUID === reverseTarget.pathUUID && + target.modelUUID === reverseTarget.modelUUID && target.pointUUID === reverseTarget.pointUUID )) { return { @@ -166,14 +167,139 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec } return path; } + // else if (path.type === 'StaticMachine') { + // if (path.modeluuid === fromModelUUID && path.points.uuid === fromPointUUID) { + // const newTarget = { + // modelUUID: toModelUUID, + // pointUUID: toPointUUID + // }; + // const existingTargets = path.points.connections.targets || []; + + // // Check if target is an ArmBot + // const toPath = simulationStates.find(p => p.modeluuid === toModelUUID); + // if (toPath?.type !== 'ArmBot') { + // console.log("StaticMachine can only connect to ArmBot"); + // return path; + // } + + // // Check if already has a connection + // if (existingTargets.length >= 1) { + // console.log("StaticMachine can have only one connection"); + // return path; + // } + + // if (!existingTargets.some(target => + // target.modelUUID === newTarget.modelUUID && + // target.pointUUID === newTarget.pointUUID + // )) { + // return { + // ...path, + // points: { + // ...path.points, + // connections: { + // ...path.points.connections, + // targets: [...existingTargets, newTarget] + // } + // } + // }; + // } + // } + // // Handle incoming connections to StaticMachine + // else if (path.modeluuid === toModelUUID && path.points.uuid === toPointUUID) { + // const reverseTarget = { + // modelUUID: fromModelUUID, + // pointUUID: fromPointUUID + // }; + // const existingTargets = path.points.connections.targets || []; + + // // Check if source is an ArmBot + // const fromPath = simulationStates.find(p => p.modeluuid === fromModelUUID); + // if (fromPath?.type !== 'ArmBot') { + // console.log("StaticMachine can only connect to ArmBot"); + // return path; + // } + + // // Check if already has a connection + // if (existingTargets.length >= 1) { + // console.log("StaticMachine can have only one connection"); + // return path; + // } + + // if (!existingTargets.some(target => + // target.modelUUID === reverseTarget.modelUUID && + // target.pointUUID === reverseTarget.pointUUID + // )) { + // return { + // ...path, + // points: { + // ...path.points, + // connections: { + // ...path.points.connections, + // targets: [...existingTargets, reverseTarget] + // } + // } + // }; + // } + // } + // return path; + // } return path; }); - setSimulationPaths(updatedPaths); + setSimulationStates(updatedPaths); + + const updatedPathDetails = updatedPaths.filter(path => + path.modeluuid === fromModelUUID || path.modeluuid === toModelUUID + ); + + updateBackend(updatedPathDetails); }; - const handleAddConnection = (fromPathUUID: string, fromUUID: string, toPathUUID: string, toUUID: string) => { - updatePathConnections(fromPathUUID, fromUUID, toPathUUID, toUUID); + const updateBackend = async (updatedPaths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => { + if (updatedPaths.length === 0) return; + const email = localStorage.getItem("email"); + const organization = email ? email.split("@")[1].split(".")[0] : ""; + + updatedPaths.forEach(async (updatedPath) => { + if (updatedPath.type === 'Conveyor') { + + // await setEventApi( + // organization, + // updatedPath.modeluuid, + // { type: "Conveyor", points: updatedPath.points, speed: updatedPath.speed } + // ); + + const data = { + organization: organization, + modeluuid: updatedPath.modeluuid, + eventData: { type: "Conveyor", points: updatedPath.points, speed: updatedPath.speed } + } + + socket.emit('v2:model-asset:updateEventData', data); + + } else if (updatedPath.type === 'Vehicle') { + + // await setEventApi( + // organization, + // updatedPath.modeluuid, + // { type: "Vehicle", points: updatedPath.points } + // ); + + const data = { + organization: organization, + modeluuid: updatedPath.modeluuid, + eventData: { type: "Vehicle", points: updatedPath.points } + } + + socket.emit('v2:model-asset:updateEventData', data); + + } + }) + + } + + const handleAddConnection = (fromModelUUID: string, fromUUID: string, toModelUUID: string, toUUID: string) => { + updatePathConnections(fromModelUUID, fromUUID, toModelUUID, toUUID); setFirstSelected(null); setCurrentLine(null); setIsConnecting(false); @@ -210,7 +336,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec const intersected = intersects[0].object; if (intersected.name.includes("events-sphere")) { - const pathUUID = intersected.userData.path.modeluuid; + const modelUUID = intersected.userData.path.modeluuid; const sphereUUID = intersected.uuid; const worldPosition = new THREE.Vector3(); intersected.getWorldPosition(worldPosition); @@ -226,9 +352,9 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec isStartOrEnd = sphereUUID === intersected.userData.path.points.uuid; } - if (pathUUID) { - const firstPath = simulationPaths.find(p => p.modeluuid === firstSelected?.pathUUID); - const secondPath = simulationPaths.find(p => p.modeluuid === pathUUID); + if (modelUUID) { + const firstPath = simulationStates.find(p => p.modeluuid === firstSelected?.modelUUID); + const secondPath = simulationStates.find(p => p.modeluuid === modelUUID); // Prevent vehicle-to-vehicle connections if (firstPath && secondPath && firstPath.type === 'Vehicle' && secondPath.type === 'Vehicle') { @@ -240,23 +366,23 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec if (firstPath && secondPath && firstPath.type === 'Conveyor' && secondPath.type === 'Conveyor' && - !firstSelected?.isCorner) { - console.log("Conveyor middle points can only connect to non-conveyor paths"); + (!firstSelected?.isCorner || !isStartOrEnd)) { + console.log("Conveyor connections must be between start/end points"); return; } // Check if this specific connection already exists const isDuplicateConnection = firstSelected - ? simulationPaths.some(path => { - if (path.modeluuid === firstSelected.pathUUID) { + ? simulationStates.some(path => { + if (path.modeluuid === firstSelected.modelUUID) { if (path.type === 'Conveyor') { const point = path.points.find(p => p.uuid === firstSelected.sphereUUID); return point?.connections.targets.some(t => - t.pathUUID === pathUUID && t.pointUUID === sphereUUID + t.modelUUID === modelUUID && t.pointUUID === sphereUUID ); } else if (path.type === 'Vehicle') { return path.points.connections.targets.some(t => - t.pathUUID === pathUUID && t.pointUUID === sphereUUID + t.modelUUID === modelUUID && t.pointUUID === sphereUUID ); } } @@ -281,7 +407,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec // For non-Vehicle paths, check if already connected if (intersected.userData.path.type !== 'Vehicle') { - const isAlreadyConnected = simulationPaths.some(path => { + const isAlreadyConnected = simulationStates.some(path => { if (path.type === 'Conveyor') { return path.points.some(point => point.uuid === sphereUUID && @@ -306,7 +432,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec } // Prevent same-path connections - if (firstSelected.pathUUID === pathUUID) { + if (firstSelected.modelUUID === modelUUID) { console.log("Cannot connect spheres on the same path."); return; } @@ -319,15 +445,15 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec // All checks passed - make the connection handleAddConnection( - firstSelected.pathUUID, + firstSelected.modelUUID, firstSelected.sphereUUID, - pathUUID, + modelUUID, sphereUUID ); } else { // First selection - just store it setFirstSelected({ - pathUUID, + modelUUID, sphereUUID, position: worldPosition, isCorner: isStartOrEnd @@ -361,7 +487,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec canvasElement.removeEventListener("mousemove", onMouseMove); canvasElement.removeEventListener("contextmenu", onContextMenu); }; - }, [camera, scene, raycaster, firstSelected, simulationPaths]); + }, [camera, scene, raycaster, firstSelected, simulationStates]); useFrame(() => { if (firstSelected) { @@ -375,7 +501,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec ); let point: THREE.Vector3 | null = null; - let snappedSphere: { sphereUUID: string, position: THREE.Vector3, pathUUID: string, isCorner: boolean } | null = null; + let snappedSphere: { sphereUUID: string, position: THREE.Vector3, modelUUID: string, isCorner: boolean } | null = null; let isInvalidConnection = false; if (intersects.length > 0) { @@ -395,10 +521,10 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec const spherePosition = new THREE.Vector3(); sphere.getWorldPosition(spherePosition); const pathData = sphere.userData.path; - const pathUUID = pathData.modeluuid; + const modelUUID = pathData.modeluuid; - const firstPath = simulationPaths.find(p => p.modeluuid === firstSelected.pathUUID); - const secondPath = simulationPaths.find(p => p.modeluuid === pathUUID); + const firstPath = simulationStates.find(p => p.modeluuid === firstSelected.modelUUID); + const secondPath = simulationStates.find(p => p.modeluuid === modelUUID); const isVehicleToVehicle = firstPath?.type === 'Vehicle' && secondPath?.type === 'Vehicle'; // Inside the useFrame hook, where we check for snapped spheres: @@ -413,16 +539,16 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec !firstSelected.isCorner); // Check for duplicate connection (regardless of path type) - const isDuplicateConnection = simulationPaths.some(path => { - if (path.modeluuid === firstSelected.pathUUID) { + const isDuplicateConnection = simulationStates.some(path => { + if (path.modeluuid === firstSelected.modelUUID) { if (path.type === 'Conveyor') { const point = path.points.find(p => p.uuid === firstSelected.sphereUUID); return point?.connections.targets.some(t => - t.pathUUID === pathUUID && t.pointUUID === sphereUUID + t.modelUUID === modelUUID && t.pointUUID === sphereUUID ); } else if (path.type === 'Vehicle') { return path.points.connections.targets.some(t => - t.pathUUID === pathUUID && t.pointUUID === sphereUUID + t.modelUUID === modelUUID && t.pointUUID === sphereUUID ); } } @@ -431,7 +557,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec // For non-Vehicle paths, check if already connected const isNonVehicleAlreadyConnected = pathData.type !== 'Vehicle' && - simulationPaths.some(path => { + simulationStates.some(path => { if (path.type === 'Conveyor') { return path.points.some(point => point.uuid === sphereUUID && @@ -455,13 +581,16 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec !isVehicleAtMaxConnections && !isVehicleConnectingToNonConveyor && firstSelected.sphereUUID !== sphereUUID && - firstSelected.pathUUID !== pathUUID && - (firstSelected.isCorner || isConnectable) + firstSelected.modelUUID !== modelUUID && + (firstSelected.isCorner || isConnectable) && + !(firstPath?.type === 'Conveyor' && + pathData.type === 'Conveyor' && + !(firstSelected.isCorner && isConnectable)) ) { snappedSphere = { sphereUUID, position: spherePosition, - pathUUID, + modelUUID, isCorner: isConnectable }; } else { @@ -505,11 +634,11 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec return ( - {simulationPaths.flatMap(path => { + {simulationStates.flatMap(path => { if (path.type === 'Conveyor') { return path.points.flatMap(point => point.connections.targets.map((target, index) => { - const targetPath = simulationPaths.find(p => p.modeluuid === target.pathUUID); + const targetPath = simulationStates.find(p => p.modeluuid === target.modelUUID); if (targetPath?.type === 'Vehicle') return null; const fromSphere = pathsGroupRef.current?.getObjectByProperty('uuid', point.uuid); diff --git a/app/src/modules/simulation/path/pathCreation.tsx b/app/src/modules/simulation/path/pathCreation.tsx index 619a011..62bb79e 100644 --- a/app/src/modules/simulation/path/pathCreation.tsx +++ b/app/src/modules/simulation/path/pathCreation.tsx @@ -3,375 +3,340 @@ import * as Types from "../../../types/world/worldTypes"; import { useRef, useState, useEffect, useMemo } from "react"; import { Sphere, TransformControls } from "@react-three/drei"; import { - useEditingPoint, - useEyeDropMode, - useIsConnecting, - usePreviewPosition, - useRenderDistance, - useSelectedActionSphere, - useSelectedPath, - useSimulationPaths, + useEditingPoint, + useEyeDropMode, + useIsConnecting, + usePreviewPosition, + useRenderDistance, + useSelectedActionSphere, + useSelectedPath, + useSimulationStates, } from "../../../store/store"; import { useFrame, useThree } from "@react-three/fiber"; import { useSubModuleStore } from "../../../store/useModuleStore"; import { usePlayButtonStore } from "../../../store/usePlayButtonStore"; import { setEventApi } from "../../../services/factoryBuilder/assest/floorAsset/setEventsApt"; -function PathCreation({ - pathsGroupRef, -}: { - pathsGroupRef: React.MutableRefObject; -}) { - const { isPlaying } = usePlayButtonStore(); - const { renderDistance } = useRenderDistance(); - const { setSubModule } = useSubModuleStore(); - const { setSelectedActionSphere, selectedActionSphere } = useSelectedActionSphere(); - const { eyeDropMode, setEyeDropMode } = useEyeDropMode(); - const { editingPoint, setEditingPoint } = useEditingPoint(); - const { previewPosition, setPreviewPosition } = usePreviewPosition(); - const { raycaster, camera, pointer, gl } = useThree(); - const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []); - const { setSelectedPath } = useSelectedPath(); - const { simulationPaths, setSimulationPaths } = useSimulationPaths(); - const { isConnecting } = useIsConnecting(); +function PathCreation({ pathsGroupRef, }: { pathsGroupRef: React.MutableRefObject; }) { + const { isPlaying } = usePlayButtonStore(); + const { renderDistance } = useRenderDistance(); + const { setSubModule } = useSubModuleStore(); + const { setSelectedActionSphere, selectedActionSphere } = useSelectedActionSphere(); + const { eyeDropMode, setEyeDropMode } = useEyeDropMode(); + const { editingPoint, setEditingPoint } = useEditingPoint(); + const { previewPosition, setPreviewPosition } = usePreviewPosition(); + const { raycaster, camera, pointer, gl } = useThree(); + const { setSelectedPath } = useSelectedPath(); + const { simulationStates, setSimulationStates } = useSimulationStates(); + const { isConnecting } = useIsConnecting(); + const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []); - const groupRefs = useRef<{ [key: string]: THREE.Group }>({}); - const sphereRefs = useRef<{ [key: string]: THREE.Mesh }>({}); - const isMovingRef = useRef(false); - const transformRef = useRef(null); - const [transformMode, setTransformMode] = useState<"translate" | "rotate" | null>(null); + const groupRefs = useRef<{ [key: string]: THREE.Group }>({}); + const sphereRefs = useRef<{ [key: string]: THREE.Mesh }>({}); + const isMovingRef = useRef(false); + const transformRef = useRef(null); + const [transformMode, setTransformMode] = useState<"translate" | "rotate" | null>(null); - useEffect(() => { - setTransformMode(null); - const handleKeyDown = (e: KeyboardEvent) => { - if (!selectedActionSphere) return; - if (e.key === "g") { - setTransformMode((prev) => (prev === "translate" ? null : "translate")); - } - if (e.key === "r") { - setTransformMode((prev) => (prev === "rotate" ? null : "rotate")); - } - }; + useEffect(() => { + setTransformMode(null); + const handleKeyDown = (e: KeyboardEvent) => { + if (!selectedActionSphere) return; + if (e.key === "g") { + setTransformMode((prev) => (prev === "translate" ? null : "translate")); + } + if (e.key === "r") { + setTransformMode((prev) => (prev === "rotate" ? null : "rotate")); + } + }; - window.addEventListener("keydown", handleKeyDown); - return () => window.removeEventListener("keydown", handleKeyDown); - }, [selectedActionSphere]); + window.addEventListener("keydown", handleKeyDown); + return () => window.removeEventListener("keydown", handleKeyDown); + }, [selectedActionSphere]); - useFrame(() => { - Object.values(groupRefs.current).forEach((group) => { - if (group) { - const distance = new THREE.Vector3( - ...group.position.toArray() - ).distanceTo(camera.position); - group.visible = ((distance <= renderDistance) && !isPlaying); - } - }); - }); + useFrame(() => { + Object.values(groupRefs.current).forEach((group) => { + if (group) { + const distance = new THREE.Vector3( + ...group.position.toArray() + ).distanceTo(camera.position); + group.visible = ((distance <= renderDistance) && !isPlaying); + } + }); + }); - const updateSimulationPaths = () => { - if (!selectedActionSphere) return; + const updateSimulationPaths = () => { + if (!selectedActionSphere) return; - const updatedPaths = simulationPaths.map((path) => { - if (path.type === "Conveyor") { - return { - ...path, - points: path.points.map((point) => - point.uuid === selectedActionSphere.points.uuid - ? { - ...point, - position: [ - selectedActionSphere.points.position.x, - selectedActionSphere.points.position.y, - selectedActionSphere.points.position.z, - ], - rotation: [ - selectedActionSphere.points.rotation.x, - selectedActionSphere.points.rotation.y, - selectedActionSphere.points.rotation.z, - ], - } - : point - ), - }; - } - return path; - }) as Types.ConveyorEventsSchema[]; + const updatedPaths = simulationStates.map((path) => { + if (path.type === "Conveyor") { + return { + ...path, + points: path.points.map((point) => + point.uuid === selectedActionSphere.points.uuid + ? { + ...point, + position: [ + selectedActionSphere.points.position.x, + selectedActionSphere.points.position.y, + selectedActionSphere.points.position.z, + ], + rotation: [ + selectedActionSphere.points.rotation.x, + selectedActionSphere.points.rotation.y, + selectedActionSphere.points.rotation.z, + ], + } + : point + ), + }; + } else { + return path; + } + }) as Types.ConveyorEventsSchema[]; - setSimulationPaths(updatedPaths); - }; + const updatedPath = updatedPaths.find( + (path) => path.type === "Conveyor" && path.points.some((point) => point.uuid === selectedActionSphere.points.uuid) + ); - useFrame(() => { - if (eyeDropMode) { - raycaster.setFromCamera(pointer, camera); - const intersectionPoint = new THREE.Vector3(); - const point = raycaster.ray.intersectPlane(plane, intersectionPoint); + // console.log("Updated Path:", updatedPath); - if (point) { - setPreviewPosition({ x: point.x, y: point.z }); - } - } else { - setPreviewPosition(null); - } - }); + setSimulationStates(updatedPaths); + }; - useEffect(() => { - if (!camera) return; - const canvasElement = gl.domElement; - canvasElement.tabIndex = 0; + useFrame(() => { + if (eyeDropMode) { + raycaster.setFromCamera(pointer, camera); + const intersectionPoint = new THREE.Vector3(); + const point = raycaster.ray.intersectPlane(plane, intersectionPoint); - const onPointerDown = () => { - isMovingRef.current = false; - }; + if (point) { + setPreviewPosition({ x: point.x, y: point.z }); + } + } else { + setPreviewPosition(null); + } + }); - const onPointerMove = () => { - isMovingRef.current = true; - }; + useEffect(() => { + if (!camera) return; + const canvasElement = gl.domElement; + canvasElement.tabIndex = 0; - const onPointerUp = (event: PointerEvent) => { - if ( - !isMovingRef.current && - eyeDropMode && - event.button === 0 && - previewPosition - ) { - event.preventDefault(); - if (editingPoint) { - handlePointUpdate(editingPoint, previewPosition.x, previewPosition.y); - setEditingPoint(null); - setEyeDropMode(false); - } - } - }; + const onPointerDown = () => { + isMovingRef.current = false; + }; - if (eyeDropMode) { - canvasElement.addEventListener("pointerdown", onPointerDown); - canvasElement.addEventListener("pointermove", onPointerMove); - canvasElement.addEventListener("pointerup", onPointerUp); - } + const onPointerMove = () => { + isMovingRef.current = true; + }; - return () => { - canvasElement.removeEventListener("pointerdown", onPointerDown); - canvasElement.removeEventListener("pointermove", onPointerMove); - canvasElement.removeEventListener("pointerup", onPointerUp); - }; - }, [eyeDropMode, editingPoint, previewPosition]); + const onPointerUp = (event: PointerEvent) => { + if ( + !isMovingRef.current && + eyeDropMode && + event.button === 0 && + previewPosition + ) { + event.preventDefault(); + if (editingPoint) { + handlePointUpdate(editingPoint, previewPosition.x, previewPosition.y); + setEditingPoint(null); + setEyeDropMode(false); + } + } + }; - const updateBackend = async (updatedPath: Types.VehicleEventsSchema | undefined) => { - if (!updatedPath) return; - const email = localStorage.getItem("email"); - const organization = email ? email.split("@")[1].split(".")[0] : ""; - await setEventApi( - organization, - updatedPath.modeluuid, - { type: "Vehicle", points: updatedPath.points } - ); - } + if (eyeDropMode) { + canvasElement.addEventListener("pointerdown", onPointerDown); + canvasElement.addEventListener("pointermove", onPointerMove); + canvasElement.addEventListener("pointerup", onPointerUp); + } - const handlePointUpdate = ( - pointType: "start" | "end", - x: number, - z: number - ) => { - if (!selectedActionSphere?.points?.uuid) return; - const updatedPaths = simulationPaths.map((path) => { + return () => { + canvasElement.removeEventListener("pointerdown", onPointerDown); + canvasElement.removeEventListener("pointermove", onPointerMove); + canvasElement.removeEventListener("pointerup", onPointerUp); + }; + }, [eyeDropMode, editingPoint, previewPosition]); - if ( - path.type === "Vehicle" && - path.points.uuid === selectedActionSphere.points.uuid - ) { - return { - ...path, - points: { - ...path.points, - actions: { - ...path.points.actions, - [pointType]: { - ...path.points.actions[pointType], - x: x, - y: z, - }, - }, - }, - }; - } - return path; - }); + const updateBackend = async (updatedPath: Types.VehicleEventsSchema | undefined) => { + if (!updatedPath) return; + const email = localStorage.getItem("email"); + const organization = email ? email.split("@")[1].split(".")[0] : ""; + await setEventApi( + organization, + updatedPath.modeluuid, + { type: "Vehicle", points: updatedPath.points } + ); + } - const updatedPath = updatedPaths.find( - (path): path is Types.VehicleEventsSchema => - path.type === "Vehicle" && - path.points.uuid === selectedActionSphere.points.uuid - ); - updateBackend(updatedPath); + const handlePointUpdate = (pointType: "start" | "end", x: number, z: number) => { + if (!selectedActionSphere?.points?.uuid) return; + const updatedPaths = simulationStates.map((path) => { - setSimulationPaths(updatedPaths); - }; + if (path.type === "Vehicle" && path.points.uuid === selectedActionSphere.points.uuid) { + return { + ...path, + points: { + ...path.points, + actions: { + ...path.points.actions, + [pointType]: { ...path.points.actions[pointType], x: x, y: z, }, + }, + }, + }; + } + return path; + }); - return ( - - {simulationPaths.map((path) => { - if (path.type === "Conveyor") { - const points = path.points.map( - (point) => new THREE.Vector3(...point.position) - ); + const updatedPath = updatedPaths.find((path): path is Types.VehicleEventsSchema => path.type === "Vehicle" && path.points.uuid === selectedActionSphere.points.uuid); + updateBackend(updatedPath); - return ( - (groupRefs.current[path.modeluuid] = el!)} - position={path.position} - rotation={path.rotation} - onClick={(e) => { - if (isConnecting || eyeDropMode) return; - e.stopPropagation(); - setSelectedPath({ - path, - group: groupRefs.current[path.modeluuid], - }); - setSelectedActionSphere(null); - setTransformMode(null); - setSubModule("mechanics"); - }} - onPointerMissed={() => { - if (eyeDropMode) return; - setSelectedPath(null); - setSubModule("properties"); - }} - > - {path.points.map((point, index) => ( - (sphereRefs.current[point.uuid] = el!)} - onClick={(e) => { - if (isConnecting || eyeDropMode) return; - e.stopPropagation(); - setSelectedActionSphere({ - path, - points: sphereRefs.current[point.uuid], - }); - setSubModule("mechanics"); - setSelectedPath(null); - }} - userData={{ points, path }} - onPointerMissed={() => { - if (eyeDropMode) return; - setSubModule("properties"); - setSelectedActionSphere(null); - }} - > - - - ))} + setSimulationStates(updatedPaths); + }; - {points.slice(0, -1).map((point, index) => { - const nextPoint = points[index + 1]; - const segmentCurve = new THREE.CatmullRomCurve3([ - point, - nextPoint, - ]); - const tubeGeometry = new THREE.TubeGeometry( - segmentCurve, - 20, - 0.1, - 16, - false - ); + return ( + + {simulationStates.map((path) => { + if (path.type === "Conveyor") { + const points = path.points.map( + (point) => new THREE.Vector3(...point.position) + ); - return ( - - - - ); - })} - - ); - } else if (path.type === "Vehicle") { - return ( - (groupRefs.current[path.modeluuid] = el!)} - position={path.position} - onClick={(e) => { - if (isConnecting || eyeDropMode) return; - e.stopPropagation(); - setSelectedPath({ - path, - group: groupRefs.current[path.modeluuid], - }); - setSelectedActionSphere(null); - setTransformMode(null); - setSubModule("mechanics"); - }} - onPointerMissed={() => { - if (eyeDropMode) return; - setSelectedPath(null); - setSubModule("properties"); - }} - > - (sphereRefs.current[path.points.uuid] = el!)} - onClick={(e) => { - if (isConnecting || eyeDropMode) return; - e.stopPropagation(); - setSelectedActionSphere({ - path, - points: sphereRefs.current[path.points.uuid], - }); - setSubModule("mechanics"); - setSelectedPath(null); - }} - userData={{ points: path.points, path }} - onPointerMissed={() => { - if (eyeDropMode) return; - setSubModule("properties"); - setSelectedActionSphere(null); - }} - > - - - - ); - } - return null; - })} + return ( + (groupRefs.current[path.modeluuid] = el!)} + position={path.position} + rotation={path.rotation} + onClick={(e) => { + if (isConnecting || eyeDropMode) return; + e.stopPropagation(); + setSelectedPath({ + path, + group: groupRefs.current[path.modeluuid], + }); + setSelectedActionSphere(null); + setTransformMode(null); + setSubModule("mechanics"); + }} + onPointerMissed={() => { + if (eyeDropMode) return; + setSelectedPath(null); + setSubModule("properties"); + }} + > + {path.points.map((point, index) => ( + (sphereRefs.current[point.uuid] = el!)} + onClick={(e) => { + if (isConnecting || eyeDropMode) return; + e.stopPropagation(); + setSelectedActionSphere({ + path, + points: sphereRefs.current[point.uuid], + }); + setSubModule("mechanics"); + setSelectedPath(null); + }} + userData={{ points, path }} + onPointerMissed={() => { + if (eyeDropMode) return; + setSubModule("properties"); + setSelectedActionSphere(null); + }} + > + + + ))} - {selectedActionSphere && transformMode && ( - - )} - - ); + {points.slice(0, -1).map((point, index) => { + const nextPoint = points[index + 1]; + const segmentCurve = new THREE.CatmullRomCurve3([point, nextPoint,]); + const tubeGeometry = new THREE.TubeGeometry(segmentCurve, 20, 0.1, 16, false); + + return ( + + + + ); + })} + + ); + } else if (path.type === "Vehicle" || path.type === "StaticMachine") { + return ( + (groupRefs.current[path.modeluuid] = el!)} + position={path.position} + onClick={(e) => { + if (isConnecting || eyeDropMode) return; + e.stopPropagation(); + setSelectedPath({ + path, + group: groupRefs.current[path.modeluuid], + }); + setSelectedActionSphere(null); + setTransformMode(null); + setSubModule("mechanics"); + }} + onPointerMissed={() => { + if (eyeDropMode) return; + setSelectedPath(null); + setSubModule("properties"); + }} + > + (sphereRefs.current[path.points.uuid] = el!)} + onClick={(e) => { + if (isConnecting || eyeDropMode) return; + e.stopPropagation(); + setSelectedActionSphere({ + path, + points: sphereRefs.current[path.points.uuid], + }); + setSubModule("mechanics"); + setSelectedPath(null); + }} + userData={{ points: path.points, path }} + onPointerMissed={() => { + if (eyeDropMode) return; + setSubModule("properties"); + setSelectedActionSphere(null); + }} + > + + + + ); + } + return null; + })} + + {selectedActionSphere && transformMode && ( + + )} + + ); } export default PathCreation; diff --git a/app/src/modules/simulation/process/processAnimator.tsx b/app/src/modules/simulation/process/processAnimator.tsx index d82b800..c8cf07f 100644 --- a/app/src/modules/simulation/process/processAnimator.tsx +++ b/app/src/modules/simulation/process/processAnimator.tsx @@ -29,8 +29,8 @@ interface ProcessPoint { rotation: number[]; actions: PointAction[]; connections: { - source: { pathUUID: string; pointUUID: string }; - targets: { pathUUID: string; pointUUID: string }[]; + source: { modelUUID: string; pointUUID: string }; + targets: { modelUUID: string; pointUUID: string }[]; }; } diff --git a/app/src/modules/simulation/process/processCreator.tsx b/app/src/modules/simulation/process/processCreator.tsx index f089285..4403a71 100644 --- a/app/src/modules/simulation/process/processCreator.tsx +++ b/app/src/modules/simulation/process/processCreator.tsx @@ -5,7 +5,7 @@ // useCallback, // useRef, // } from "react"; -// import { useSimulationPaths } from "../../../store/store"; +// import { useSimulationStates } from "../../../store/store"; // import * as THREE from "three"; // import { useThree } from "@react-three/fiber"; // import { @@ -29,7 +29,7 @@ // position: [number, number, number]; // actions: PointAction[]; // connections: { -// targets: Array<{ pathUUID: string }>; +// targets: Array<{ modelUUID: string }>; // }; // } @@ -72,7 +72,7 @@ // actions: point.actions.map(normalizeAction), // Preserve exact actions // connections: { // targets: point.connections.targets.map((target) => ({ -// pathUUID: target.pathUUID, +// modelUUID: target.modelUUID, // })), // }, // })), @@ -94,7 +94,7 @@ // : [normalizeAction(path.point.actions)], // connections: { // targets: path.point.connections.targets.map((target) => ({ -// pathUUID: target.pathUUID, +// modelUUID: target.modelUUID, // })), // }, // }, @@ -137,18 +137,18 @@ // // Check if current last connects to next last (requires reversal) // const connectsToLast = currentLastPoint.connections.targets.some( // (target) => -// target.pathUUID === nextPath.modeluuid && +// target.modelUUID === nextPath.modeluuid && // nextLastPoint.connections.targets.some( -// (t) => t.pathUUID === currentPath.modeluuid +// (t) => t.modelUUID === currentPath.modeluuid // ) // ); // // Check if current last connects to next first (no reversal needed) // const connectsToFirst = currentLastPoint.connections.targets.some( // (target) => -// target.pathUUID === nextPath.modeluuid && +// target.modelUUID === nextPath.modeluuid && // nextFirstPoint.connections.targets.some( -// (t) => t.pathUUID === currentPath.modeluuid +// (t) => t.modelUUID === currentPath.modeluuid // ) // ); @@ -249,10 +249,10 @@ // // Process outgoing connections // for (const point of currentPath.points) { // for (const target of point.connections.targets) { -// if (!visited.has(target.pathUUID)) { -// const targetPath = pathMap.get(target.pathUUID); +// if (!visited.has(target.modelUUID)) { +// const targetPath = pathMap.get(target.modelUUID); // if (targetPath) { -// visited.add(target.pathUUID); +// visited.add(target.modelUUID); // queue.push(targetPath); // } // } @@ -264,7 +264,7 @@ // if (!visited.has(uuid)) { // const hasConnectionToCurrent = path.points.some((point) => // point.connections.targets.some( -// (t) => t.pathUUID === currentPath.modeluuid +// (t) => t.modelUUID === currentPath.modeluuid // ) // ); // if (hasConnectionToCurrent) { @@ -312,19 +312,19 @@ // const ProcessCreator: React.FC = React.memo( // ({ onProcessesCreated }) => { -// const { simulationPaths } = useSimulationPaths(); +// const { simulationStates } = useSimulationStates(); // const { createProcessesFromPaths } = useProcessCreation(); // const prevPathsRef = useRef([]); // const prevProcessesRef = useRef([]); // const convertedPaths = useMemo((): SimulationPath[] => { -// if (!simulationPaths) return []; -// return simulationPaths.map((path) => +// if (!simulationStates) return []; +// return simulationStates.map((path) => // convertToSimulationPath( // path as ConveyorEventsSchema | VehicleEventsSchema // ) // ); -// }, [simulationPaths]); +// }, [simulationStates]); // const pathsDependency = useMemo(() => { // if (!convertedPaths) return null; @@ -335,7 +335,7 @@ // ), // connections: path.points // .flatMap((p: PathPoint) => -// p.connections.targets.map((t: { pathUUID: string }) => t.pathUUID) +// p.connections.targets.map((t: { modelUUID: string }) => t.modelUUID) // ) // .join(","), // })); @@ -404,7 +404,7 @@ import React, { useCallback, useRef, } from "react"; -import { useSimulationPaths } from "../../../store/store"; +import { useSimulationStates } from "../../../store/store"; import * as THREE from "three"; import { useThree } from "@react-three/fiber"; import { @@ -428,11 +428,12 @@ export interface PathPoint { position: [number, number, number]; actions: PointAction[]; connections: { - targets: Array<{ pathUUID: string }>; + targets: Array<{ modelUUID: string }>; }; } export interface SimulationPath { + type: string; modeluuid: string; points: PathPoint[]; pathPosition: [number, number, number]; @@ -464,6 +465,7 @@ function convertToSimulationPath( if (path.type === "Conveyor") { return { + type: path.type, modeluuid, points: path.points.map((point) => ({ uuid: point.uuid, @@ -471,7 +473,7 @@ function convertToSimulationPath( actions: point.actions.map(normalizeAction), // Preserve exact actions connections: { targets: point.connections.targets.map((target) => ({ - pathUUID: target.pathUUID, + modelUUID: target.modelUUID, })), }, })), @@ -483,6 +485,7 @@ function convertToSimulationPath( }; } else { return { + type: path.type, modeluuid, points: [ { @@ -493,7 +496,7 @@ function convertToSimulationPath( : [normalizeAction(path.points.actions)], connections: { targets: path.points.connections.targets.map((target) => ({ - pathUUID: target.pathUUID, + modelUUID: target.modelUUID, })), }, }, @@ -536,18 +539,18 @@ function shouldReverseNextPath( // Check if current last connects to next last (requires reversal) const connectsToLast = currentLastPoint.connections.targets.some( (target) => - target.pathUUID === nextPath.modeluuid && + target.modelUUID === nextPath.modeluuid && nextLastPoint.connections.targets.some( - (t) => t.pathUUID === currentPath.modeluuid + (t) => t.modelUUID === currentPath.modeluuid ) ); // Check if current last connects to next first (no reversal needed) const connectsToFirst = currentLastPoint.connections.targets.some( (target) => - target.pathUUID === nextPath.modeluuid && + target.modelUUID === nextPath.modeluuid && nextFirstPoint.connections.targets.some( - (t) => t.pathUUID === currentPath.modeluuid + (t) => t.modelUUID === currentPath.modeluuid ) ); @@ -614,6 +617,7 @@ export function useProcessCreation() { const [processes, setProcesses] = useState([]); const hasSpawnAction = useCallback((path: SimulationPath): boolean => { + if (path.type !== "Conveyor") return false; return path.points.some((point) => point.actions.some((action) => action.type.toLowerCase() === "spawn") ); @@ -674,10 +678,10 @@ export function useProcessCreation() { // Process outgoing connections for (const point of currentPath.points) { for (const target of point.connections.targets) { - if (!visited.has(target.pathUUID)) { - const targetPath = pathMap.get(target.pathUUID); + if (!visited.has(target.modelUUID)) { + const targetPath = pathMap.get(target.modelUUID); if (targetPath) { - visited.add(target.pathUUID); + visited.add(target.modelUUID); queue.push(targetPath); } } @@ -689,7 +693,7 @@ export function useProcessCreation() { if (!visited.has(uuid)) { const hasConnectionToCurrent = path.points.some((point) => point.connections.targets.some( - (t) => t.pathUUID === currentPath.modeluuid + (t) => t.modelUUID === currentPath.modeluuid ) ); if (hasConnectionToCurrent) { @@ -737,19 +741,19 @@ export function useProcessCreation() { const ProcessCreator: React.FC = React.memo( ({ onProcessesCreated }) => { - const { simulationPaths } = useSimulationPaths(); + const { simulationStates } = useSimulationStates(); const { createProcessesFromPaths } = useProcessCreation(); const prevPathsRef = useRef([]); const prevProcessesRef = useRef([]); const convertedPaths = useMemo((): SimulationPath[] => { - if (!simulationPaths) return []; - return simulationPaths.map((path) => + if (!simulationStates) return []; + return simulationStates.map((path) => convertToSimulationPath( path as ConveyorEventsSchema | VehicleEventsSchema ) ); - }, [simulationPaths]); + }, [simulationStates]); // Enhanced dependency tracking that includes action types const pathsDependency = useMemo(() => { @@ -764,7 +768,7 @@ const ProcessCreator: React.FC = React.memo( .join(","), connections: path.points .flatMap((p: PathPoint) => - p.connections.targets.map((t: { pathUUID: string }) => t.pathUUID) + p.connections.targets.map((t: { modelUUID: string }) => t.modelUUID) ) .join(","), })); diff --git a/app/src/modules/simulation/simulation.tsx b/app/src/modules/simulation/simulation.tsx index fd8b520..98fd3dd 100644 --- a/app/src/modules/simulation/simulation.tsx +++ b/app/src/modules/simulation/simulation.tsx @@ -2,7 +2,7 @@ import { useState, useEffect, useRef, useMemo } from "react"; import { useSelectedActionSphere, useSelectedPath, - useSimulationPaths, + useSimulationStates, } from "../../store/store"; import * as THREE from "three"; import Behaviour from "./behaviour/behaviour"; @@ -15,12 +15,12 @@ import Agv from "../builder/agv/agv"; function Simulation() { const { activeModule } = useModuleStore(); const pathsGroupRef = useRef() as React.MutableRefObject; - const { simulationPaths, setSimulationPaths } = useSimulationPaths(); + const { simulationStates, setSimulationStates } = useSimulationStates(); const [processes, setProcesses] = useState([]); useEffect(() => { - // console.log('simulationPaths: ', simulationPaths); - }, [simulationPaths]); + // console.log('simulationStates: ', simulationStates); + }, [simulationStates]); // useEffect(() => { // if (selectedActionSphere) { @@ -42,7 +42,7 @@ function Simulation() { - {/* */} + )} diff --git a/app/src/modules/simulation/simulationUI.tsx b/app/src/modules/simulation/simulationUI.tsx index bff2b20..055fb36 100644 --- a/app/src/modules/simulation/simulationUI.tsx +++ b/app/src/modules/simulation/simulationUI.tsx @@ -1,5 +1,5 @@ // import { useMemo, useState } from 'react'; -// import { useSelectedActionSphere, useToggleView, useSimulationPaths, useSelectedPath, useStartSimulation, useDrawMaterialPath } from '../../store/store'; +// import { useSelectedActionSphere, useToggleView, useSimulationStates, useSelectedPath, useStartSimulation, useDrawMaterialPath } from '../../store/store'; // import * as THREE from 'three'; // import useModuleStore from '../../store/useModuleStore'; @@ -9,14 +9,14 @@ // const { startSimulation, setStartSimulation } = useStartSimulation(); // const { selectedActionSphere } = useSelectedActionSphere(); // const { selectedPath, setSelectedPath } = useSelectedPath(); -// const { simulationPaths, setSimulationPaths } = useSimulationPaths(); +// const { simulationStates, setSimulationStates } = useSimulationStates(); // const { drawMaterialPath, setDrawMaterialPath } = useDrawMaterialPath(); // const [activeButton, setActiveButton] = useState(null); // const handleAddAction = () => { // if (!selectedActionSphere) return; -// const updatedPaths = simulationPaths.map((path) => ({ +// const updatedPaths = simulationStates.map((path) => ({ // ...path, // points: path.points.map((point) => { // if (point.uuid === selectedActionSphere.points.uuid) { @@ -37,13 +37,13 @@ // }), // })); -// setSimulationPaths(updatedPaths); +// setSimulationStates(updatedPaths); // }; // const handleDeleteAction = (uuid: string) => { // if (!selectedActionSphere) return; -// const updatedPaths = simulationPaths.map((path) => ({ +// const updatedPaths = simulationStates.map((path) => ({ // ...path, // points: path.points.map((point) => // point.uuid === selectedActionSphere.points.uuid @@ -52,13 +52,13 @@ // ), // })); -// setSimulationPaths(updatedPaths); +// setSimulationStates(updatedPaths); // }; // const handleActionSelect = (uuid: string, actionType: string) => { // if (!selectedActionSphere) return; -// const updatedPaths = simulationPaths.map((path) => ({ +// const updatedPaths = simulationStates.map((path) => ({ // ...path, // points: path.points.map((point) => // point.uuid === selectedActionSphere.points.uuid @@ -72,13 +72,13 @@ // ), // })); -// setSimulationPaths(updatedPaths); +// setSimulationStates(updatedPaths); // }; // const handleMaterialSelect = (uuid: string, material: string) => { // if (!selectedActionSphere) return; -// const updatedPaths = simulationPaths.map((path) => ({ +// const updatedPaths = simulationStates.map((path) => ({ // ...path, // points: path.points.map((point) => // point.uuid === selectedActionSphere.points.uuid @@ -92,13 +92,13 @@ // ), // })); -// setSimulationPaths(updatedPaths); +// setSimulationStates(updatedPaths); // }; // const handleDelayChange = (uuid: string, delay: number | string) => { // if (!selectedActionSphere) return; -// const updatedPaths = simulationPaths.map((path) => ({ +// const updatedPaths = simulationStates.map((path) => ({ // ...path, // points: path.points.map((point) => // point.uuid === selectedActionSphere.points.uuid @@ -112,13 +112,13 @@ // ), // })); -// setSimulationPaths(updatedPaths); +// setSimulationStates(updatedPaths); // }; // const handleSpawnIntervalChange = (uuid: string, spawnInterval: number | string) => { // if (!selectedActionSphere) return; -// const updatedPaths = simulationPaths.map((path) => ({ +// const updatedPaths = simulationStates.map((path) => ({ // ...path, // points: path.points.map((point) => // point.uuid === selectedActionSphere.points.uuid @@ -132,24 +132,24 @@ // ), // })); -// setSimulationPaths(updatedPaths); +// setSimulationStates(updatedPaths); // }; // const handleSpeedChange = (speed: number) => { // if (!selectedPath) return; -// const updatedPaths = simulationPaths.map((path) => +// const updatedPaths = simulationStates.map((path) => // path.modeluuid === selectedPath.path.modeluuid ? { ...path, speed } : path // ); -// setSimulationPaths(updatedPaths); +// setSimulationStates(updatedPaths); // setSelectedPath({ ...selectedPath, path: { ...selectedPath.path, speed } }); // }; // const handleAddTrigger = () => { // if (!selectedActionSphere) return; -// const updatedPaths = simulationPaths.map((path) => ({ +// const updatedPaths = simulationStates.map((path) => ({ // ...path, // points: path.points.map((point) => { // if (point.uuid === selectedActionSphere.points.uuid) { @@ -167,13 +167,13 @@ // }), // })); -// setSimulationPaths(updatedPaths); +// setSimulationStates(updatedPaths); // }; // const handleDeleteTrigger = (uuid: string) => { // if (!selectedActionSphere) return; -// const updatedPaths = simulationPaths.map((path) => ({ +// const updatedPaths = simulationStates.map((path) => ({ // ...path, // points: path.points.map((point) => // point.uuid === selectedActionSphere.points.uuid @@ -182,13 +182,13 @@ // ), // })); -// setSimulationPaths(updatedPaths); +// setSimulationStates(updatedPaths); // }; // const handleTriggerSelect = (uuid: string, triggerType: string) => { // if (!selectedActionSphere) return; -// const updatedPaths = simulationPaths.map((path) => ({ +// const updatedPaths = simulationStates.map((path) => ({ // ...path, // points: path.points.map((point) => // point.uuid === selectedActionSphere.points.uuid @@ -202,7 +202,7 @@ // ), // })); -// setSimulationPaths(updatedPaths); +// setSimulationStates(updatedPaths); // }; // const handleResetPath = () => { @@ -214,7 +214,7 @@ // const handleActionToggle = (uuid: string) => { // if (!selectedActionSphere) return; -// const updatedPaths = simulationPaths.map((path) => ({ +// const updatedPaths = simulationStates.map((path) => ({ // ...path, // points: path.points.map((point) => // point.uuid === selectedActionSphere.points.uuid @@ -229,13 +229,13 @@ // ), // })); -// setSimulationPaths(updatedPaths); +// setSimulationStates(updatedPaths); // }; // const handleTriggerToggle = (uuid: string) => { // if (!selectedActionSphere) return; -// const updatedPaths = simulationPaths.map((path) => ({ +// const updatedPaths = simulationStates.map((path) => ({ // ...path, // points: path.points.map((point) => // point.uuid === selectedActionSphere.points.uuid @@ -250,13 +250,13 @@ // ), // })); -// setSimulationPaths(updatedPaths); +// setSimulationStates(updatedPaths); // }; // const selectedPoint = useMemo(() => { // if (!selectedActionSphere) return null; -// return simulationPaths.flatMap((path) => path.points).find((point) => point.uuid === selectedActionSphere.points.uuid); -// }, [selectedActionSphere, simulationPaths]); +// return simulationStates.flatMap((path) => path.points).find((point) => point.uuid === selectedActionSphere.points.uuid); +// }, [selectedActionSphere, simulationStates]); // const createPath = () => { // setActiveButton(activeButton !== 'addMaterialPath' ? 'addMaterialPath' : null); diff --git a/app/src/modules/simulation/simulationtemp/path/pathCreator.tsx b/app/src/modules/simulation/simulationtemp/path/pathCreator.tsx index c09b21c..c9dd36b 100644 --- a/app/src/modules/simulation/simulationtemp/path/pathCreator.tsx +++ b/app/src/modules/simulation/simulationtemp/path/pathCreator.tsx @@ -11,13 +11,13 @@ type PathPoint = { }; type PathCreatorProps = { - simulationPaths: PathPoint[][]; - setSimulationPaths: React.Dispatch>; + simulationStates: PathPoint[][]; + setSimulationStates: React.Dispatch>; connections: { start: PathPoint; end: PathPoint }[]; setConnections: React.Dispatch> }; -const PathCreator = ({ simulationPaths, setSimulationPaths, connections, setConnections }: PathCreatorProps) => { +const PathCreator = ({ simulationStates, setSimulationStates, connections, setConnections }: PathCreatorProps) => { const { camera, scene, raycaster, pointer, gl } = useThree(); const { drawMaterialPath } = useDrawMaterialPath(); @@ -71,7 +71,7 @@ const PathCreator = ({ simulationPaths, setSimulationPaths, connections, setConn e.preventDefault(); if (drag || e.button === 0) return; if (currentPath.length > 1) { - setSimulationPaths((prevPaths) => [...prevPaths, currentPath]); + setSimulationStates((prevPaths) => [...prevPaths, currentPath]); } setCurrentPath([]); setTemporaryPoint(null); @@ -125,7 +125,7 @@ const PathCreator = ({ simulationPaths, setSimulationPaths, connections, setConn canvasElement.addEventListener("contextmenu", onContextMenu); } else { if (currentPath.length > 1) { - setSimulationPaths((prevPaths) => [...prevPaths, currentPath]); + setSimulationStates((prevPaths) => [...prevPaths, currentPath]); } setCurrentPath([]); setTemporaryPoint(null); @@ -179,25 +179,25 @@ const PathCreator = ({ simulationPaths, setSimulationPaths, connections, setConn if (selectedPoint) { const updatedPosition = e.target.object.position.clone(); const updatedRotation = e.target.object.quaternion.clone(); - const updatedPaths = simulationPaths.map((path) => + const updatedPaths = simulationStates.map((path) => path.map((p) => p.uuid === selectedPoint.uuid ? { ...p, position: updatedPosition, rotation: updatedRotation } : p ) ); - setSimulationPaths(updatedPaths); + setSimulationStates(updatedPaths); } }; const meshContext = (uuid: string) => { - const pathIndex = simulationPaths.findIndex(path => path.some(point => point.uuid === uuid)); + const pathIndex = simulationStates.findIndex(path => path.some(point => point.uuid === uuid)); if (pathIndex === -1) return; - const clickedPoint = simulationPaths[pathIndex].find(point => point.uuid === uuid); + const clickedPoint = simulationStates[pathIndex].find(point => point.uuid === uuid); if (!clickedPoint) return; - const isStart = simulationPaths[pathIndex][0].uuid === uuid; - const isEnd = simulationPaths[pathIndex][simulationPaths[pathIndex].length - 1].uuid === uuid; + const isStart = simulationStates[pathIndex][0].uuid === uuid; + const isEnd = simulationStates[pathIndex][simulationStates[pathIndex].length - 1].uuid === uuid; if (pathIndex === 0 && isStart) { console.log("The first-ever point is not connectable."); @@ -285,8 +285,8 @@ const PathCreator = ({ simulationPaths, setSimulationPaths, connections, setConn return ( <> - {/* Render finalized simulationPaths */} - {simulationPaths.map((path, pathIndex) => ( + {/* Render finalized simulationStates */} + {simulationStates.map((path, pathIndex) => ( + {simulationStates.map((path) => path.map((point) => ( ([]); + const [simulationStates, setSimulationStates] = useState<{ position: THREE.Vector3; rotation: THREE.Quaternion; uuid: string }[][]>([]); const [connections, setConnections] = useState<{ start: PathPoint; end: PathPoint }[]>([]); return ( <> - - {simulationPaths.map((path, index) => ( + + {simulationStates.map((path, index) => ( ))} diff --git a/app/src/modules/visualization/realTimeVizSocket.dev.tsx b/app/src/modules/visualization/realTimeVizSocket.dev.tsx index ad5e226..9ee6b5b 100644 --- a/app/src/modules/visualization/realTimeVizSocket.dev.tsx +++ b/app/src/modules/visualization/realTimeVizSocket.dev.tsx @@ -5,6 +5,14 @@ import { useDroppedObjectsStore } from "../../store/useDroppedObjectsStore"; import { useZoneWidgetStore } from "../../store/useZone3DWidgetStore"; import useTemplateStore from "../../store/useTemplateStore"; +type WidgetData = { + id: string; + type: string; + position: [number, number, number]; + rotation?: [number, number, number]; + tempPosition?: [number, number, number]; +}; + export default function SocketRealTimeViz() { const { visualizationSocket } = useSocketStore(); const { selectedZone, setSelectedZone } = useSelectedZoneStore(); @@ -14,6 +22,7 @@ export default function SocketRealTimeViz() { const { addWidget } = useZoneWidgetStore() const { templates, removeTemplate } = useTemplateStore(); const { setTemplates } = useTemplateStore(); + const { zoneWidgetData, setZoneWidgetData, updateWidgetPosition, updateWidgetRotation } = useZoneWidgetStore(); useEffect(() => { const email = localStorage.getItem("email") || ""; @@ -132,14 +141,36 @@ export default function SocketRealTimeViz() { }); //add 3D Widget response visualizationSocket.on("viz-widget3D:response:updates", (add3DWidget: any) => { - console.log('add3DWidget: ', add3DWidget); + console.log('add3DWidget: ', add3DWidget); if (add3DWidget.success) { + console.log('add3DWidget: ', add3DWidget); if (add3DWidget.message === "Widget created successfully") { addWidget(add3DWidget.data.zoneId, add3DWidget.data.widget); } } }); + //delete 3D Widget response + visualizationSocket.on("viz-widget3D:response:delete", (delete3DWidget: any) => { + console.log('delete3DWidget: ', delete3DWidget); + // "3DWidget delete unsuccessfull" + if (delete3DWidget.success && delete3DWidget.message === "3DWidget delete successfull") { + const activeZoneWidgets = zoneWidgetData[delete3DWidget.data.zoneId] || []; + setZoneWidgetData( + delete3DWidget.data.zoneId, + activeZoneWidgets.filter((w: WidgetData) => w.id !== delete3DWidget.data.id) + ); + } + }); + //update3D widget response + visualizationSocket.on("viz-widget3D:response:modifyPositionRotation", (update3DWidget: any) => { + console.log('update3DWidget: ', update3DWidget); + + if (update3DWidget.success && update3DWidget.message==="widget update successfully") { + updateWidgetPosition(update3DWidget.data.zoneId, update3DWidget.data.widget.id, update3DWidget.data.widget.position); + updateWidgetRotation(update3DWidget.data.zoneId, update3DWidget.data.widget.id, update3DWidget.data.widget.rotation); + } + }); // add Template response visualizationSocket.on("viz-template:response:add", (addingTemplate: any) => { console.log('addingTemplate: ', addingTemplate); diff --git a/app/src/services/factoryBuilder/environment/findEnvironment.ts b/app/src/services/factoryBuilder/environment/findEnvironment.ts index de5b6a6..08cfe68 100644 --- a/app/src/services/factoryBuilder/environment/findEnvironment.ts +++ b/app/src/services/factoryBuilder/environment/findEnvironment.ts @@ -26,7 +26,7 @@ export const findEnvironment = async (organization: string, userId: string) => { false, false, false, - 0, + 40, true ); return userpos; diff --git a/app/src/store/store.ts b/app/src/store/store.ts index 365eb97..725180b 100644 --- a/app/src/store/store.ts +++ b/app/src/store/store.ts @@ -14,7 +14,7 @@ export const useSocketStore = create((set: any, get: any) => ({ const socket = io( `http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Builder`, { - reconnection: false, + reconnection: true, auth: { email, organization }, } ); @@ -22,7 +22,7 @@ export const useSocketStore = create((set: any, get: any) => ({ const visualizationSocket = io( `http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Visualization`, { - reconnection: false, + reconnection: true, auth: { email, organization }, } ); @@ -302,7 +302,13 @@ export const useDrieTemp = create((set: any) => ({ export const useActiveUsers = create((set: any) => ({ activeUsers: [], - setActiveUsers: (x: any) => set({ activeUsers: x }), + setActiveUsers: (callback: (prev: any[]) => any[] | any[]) => + set((state: { activeUsers: any[] }) => ({ + activeUsers: + typeof callback === "function" + ? callback(state.activeUsers) + : callback, + })), })); export const useDrieUIValue = create((set: any) => ({ @@ -341,24 +347,29 @@ export const useSelectedPath = create((set: any) => ({ })); interface SimulationPathsStore { - simulationPaths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]; - setSimulationPaths: ( + simulationStates: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]; + setSimulationStates: ( paths: - | (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[] - | ((prev: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[] - ) => (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) + | (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[] + | ((prev: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[] + ) => (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) ) => void; } -export const useSimulationPaths = create((set) => ({ - simulationPaths: [], - setSimulationPaths: (paths) => +export const useSimulationStates = create((set) => ({ + simulationStates: [], + setSimulationStates: (paths) => set((state) => ({ - simulationPaths: - typeof paths === "function" ? paths(state.simulationPaths) : paths, + simulationStates: + typeof paths === "function" ? paths(state.simulationStates) : paths, })), })) +export const useNavMesh = create((set: any) => ({ + navMesh: null, + setNavMesh: (x: any) => set({ navMesh: x }), +})); + export const useIsConnecting = create((set: any) => ({ isConnecting: false, setIsConnecting: (x: any) => set({ isConnecting: x }), diff --git a/app/src/types/world/worldTypes.d.ts b/app/src/types/world/worldTypes.d.ts index 3ec0682..7baf5e0 100644 --- a/app/src/types/world/worldTypes.d.ts +++ b/app/src/types/world/worldTypes.d.ts @@ -271,10 +271,10 @@ export type RefCSM = React.MutableRefObject; export type RefCSMHelper = React.MutableRefObject; interface PathConnection { - fromPathUUID: string; + fromModelUUID: string; fromUUID: string; toConnections: { - toPathUUID: string; + toModelUUID: string; toUUID: string; }[]; } @@ -296,7 +296,7 @@ interface ConveyorEventsSchema { rotation: [number, number, number]; actions: { uuid: string; name: string; type: string; material: string; delay: number | string; spawnInterval: number | string; isUsed: boolean }[] | []; triggers: { uuid: string; name: string; type: string; isUsed: boolean; bufferTime: number }[] | []; - connections: { source: { pathUUID: string; pointUUID: string }; targets: { pathUUID: string; pointUUID: string }[] }; + connections: { source: { modelUUID: string; pointUUID: string }; targets: { modelUUID: string; pointUUID: string }[] }; }[]; position: [number, number, number]; rotation: [number, number, number]; @@ -311,12 +311,40 @@ interface VehicleEventsSchema { uuid: string; position: [number, number, number]; actions: { uuid: string; name: string; type: string; start: { x: number, y: number } | {}, hitCount: number, end: { x: number, y: number } | {}, buffer: number }; - connections: { source: { modelUUID: string; pointUUID: string }; targets: { pathUUID: string; pointUUID: string }[] }; + connections: { source: { modelUUID: string; pointUUID: string }; targets: { modelUUID: string; pointUUID: string }[] }; speed: number; }; position: [number, number, number]; } +interface StaticMachineEventsSchema { + modeluuid: string; + modelName: string; + type: 'StaticMachine'; + points: { + uuid: string; + position: [number, number, number]; + actions: { uuid: string; name: string; buffer: number | string; material: string; isUsed: boolean }; + triggers: { uuid: string; name: string; type: string }; + connections: { source: { modelUUID: string; pointUUID: string }; targets: { modelUUID: string; pointUUID: string }[] }; + }; + position: [number, number, number]; +} + +interface ArmBotEventsSchema { + modeluuid: string; + modelName: string; + type: 'ArmBot'; + points: { + uuid: string; + position: [number, number, number]; + actions: { uuid: string; name: string; speed: number; processes: { triggerId: string; startPoint: string; endPoint: string }[] }; + triggers: { uuid: string; name: string; type: string }; + connections: { source: { modelUUID: string; pointUUID: string }; targets: { modelUUID: string; pointUUID: string }[] }; + }; + position: [number, number, number]; +} + export type EventData = { modeluuid: string; modelname: string; @@ -333,7 +361,7 @@ export type EventData = { rotation: [number, number, number]; actions: { uuid: string; name: string; type: string; material: string; delay: number | string; spawnInterval: number | string; isUsed: boolean }[] | []; triggers: { uuid: string; name: string; type: string; isUsed: boolean; bufferTime: number }[] | []; - connections: { source: { pathUUID: string; pointUUID: string }; targets: { pathUUID: string; pointUUID: string }[] }; + connections: { source: { modelUUID: string; pointUUID: string }; targets: { modelUUID: string; pointUUID: string }[] }; }[]; speed: number | string; } | { @@ -342,7 +370,7 @@ export type EventData = { uuid: string; position: [number, number, number]; actions: { uuid: string; name: string; type: string; start: { x: number, y: number } | {}, hitCount: number, end: { x: number, y: number } | {}, buffer: number }; - connections: { source: { modelUUID: string; pointUUID: string }; targets: { pathUUID: string; pointUUID: string }[] }; + connections: { source: { modelUUID: string; pointUUID: string }; targets: { modelUUID: string; pointUUID: string }[] }; speed: number; }; };